Implements org-graph-unification-phase2-universal-self-planning-design.md
§4 + §5, the engine-extension sub-phase (Phase 2a) -- no org-flow callers
changed yet, this is the underlying capability.
- _run_one_node() now resolves subagent_type/skill_ref per-node (node.get
with the run-level org_node/skill_id as fallback), threaded through
_ensure_node_row/_make_run_fn/_resolve_node_verify_fn -- a node's own
judgment.kind="llm" call runs under its own declared identity, not
always the graph-level default. Found and fixed a real gap surfaced by
writing this: run_graph() only ensures the run-level default skill_id
exists as a placeholder skill (work_node_execution.skill_ref's FK
target) -- a node declaring its own skill_ref needs the same guarantee
or the first INSERT for that skill_id fails FOREIGN KEY constraint.
- New on_fail.action="dynamic_loop_back": Reflection-review
(_judge_root_cause_node) runs three real parallel perspectives (content/
connectivity/history) under the Validator identity, each picking a
target_node_id from the failing node's real ancestors plus a defect_kind
(content_error vs skill_defect), majority-voted by _tally_reflection
(own small Counter-based implementation, not imported from
root_cause_trace.py -- that module already imports this one). A runtime
ancestor check in _run_one_node backs up _tally_reflection's own
degradation guarantee.
- skill_defect triggers Fix-Skill (_fix_skill_for_node) before the loop
back fires: reads the target node's declared skill_ref, builds a
rewrite prompt from what was asked/produced/why it failed/prior loop
history, runs it under the Validator identity (user-confirmed via
AskUserQuestion), then calls the existing but -- until now -- never
actually invoked by any production path bug_record.create_bug_record()
+ skill_update.update_skill(), against skill_query._REPO_ROOT (never
target_folder_path). Logs a real 'skill_iterated' execution_event (a
CHECK-enum value that has existed since the original U-001 schema but
was never written before). Rate-limited to
_MAX_SKILL_FIXES_PER_RUN_PER_SKILL rewrites of the same Skill per run.
- New total-attempts-per-source-node loop_limit guard alongside the
existing per-(target,source) one -- dynamic_loop_back can pick a
different target each round, which would otherwise dodge the per-pair
cap indefinitely. New settings_config key shape
"{org_node}:{source_node_id}:total", no interface change needed there.
- New skills/skill-defect-remediation/SKILL.md (Validator-only), wired
into roles/validator/role.json.
python3 -m unittest discover -s src (741 tests) + discover -s supervisor
-p "test_*.py" (126 tests) both green, zero regressions.
Deferred to Phase 2b (per design doc's own sequencing note): §2.1/§2.2
(work_graph_run.org_node removal + ux_work_graph_run_active index
narrowing) -- narrowing that index now, before the append-to-existing-run
mechanism lands, would break the current production flow, since Planner's
and Coder's work_graph_run rows both stay non-terminal indefinitely on
the happy path today (only Validator's own graph ever reaches 'done').
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>