-
Real incident (2026-08-13, task b243dfe8), diagnosed live with the user after they asked "what's the actual bug behind this block": the task's benchmark regression-check node kept looping back to itself, then hit "exceeded max_attempts=3" -- but the DB had no record of WHY the final (3rd) attempt was rejected, only attempts 1 and 2's feedback. This made the block impossible to properly diagnose: reading attempt 3's actual content (now possible thanks to the artifact-promotion fix) showed it had correctly grounded itself in the task's own approved SDD, unlike attempts 1/2 -- but whether the judge agreed was unknowable from the DB alone. Root cause: _run_layers()'s exceeded-limit branch raised ConsistencyCheckFailedError immediately, skipping the _record_loop_back_event() call a few lines below entirely -- sig.feedback (the judge's real, specific reason for rejecting THIS FINAL attempt, the one that actually exhausted the budget) was silently discarded. Every other rejected attempt's feedback gets persisted via that same call; only the budget-exhausting one didn't. Fixed by recording it before raising, same as every other rejection. New test drives a real 3-attempt exhaustion (max_attempts=2 -> attempts 1, 2, 3) and asserts all three loop_back_triggered events exist with attempt 3's own distinct feedback text -- confirmed it reproduces the exact real gap (2 events, not 3) on the pre-fix code. 823/823 tests. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
-
…3d96-main-checkout-drift
-
Implements docs/done/work-graph-node-execution-deblackbox-requirements.md end to end. The three documented call sites (e2e_pipeline.py:: _check_prd_consistency, work_graph_orchestrate.py::_llm_judgment_verify_fn, work_graph_orchestrate.py::_make_run_fn) all used to render a one-off Dynamic Workflow .js script and run it via `claude -p 'Run /<name>...'` purely to get "agent identity + schema-shaped output" -- a workaround for --json-schema silently conflicting with --agent (05 §5.4.1.1). That workaround was never actually necessary: work_graph_plan.py:: plan_work_graph() solved the identical problem from day one with a flat `claude --agent ... -p ...` call + ```json-fence extraction from free text, already validated in production. New org_node_trigger.trigger_org_node_structured() unifies all three call sites onto that same flat-call approach. extract_json_payload() generalizes work_graph_plan.py's fence-extraction algorithm; _extract_graph_manifest is now a thin wrapper over it. Two more call sites not in the original design doc (written before they existed) were found and migrated too: _run_reflection_perspective and _fix_skill_for_node (Phase 2a's Reflection-review/Fix-Skill). work_graph_fork.py needed no changes -- it only reaches _make_run_fn indirectly via run_graph(), so it benefits automatically. FR-4's real-agent verification (RUN_REAL_AGENT_E2E=1, mandatory, not optional -- src/test_org_node_trigger_e2e.py) confirmed persona loading, --model override, and JSON-fence extraction all work against a real model. write_workflow_script/execute_work_graph/execute_work_graph_with_usage_ limit_retry are confirmed to have no remaining production callers; docstrings mark them historical, the file is kept (not deleted). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
-
A merged graph's one run genuinely spans several org_nodes now (Planner/ Coder/Validator all append their own nodes into the SAME run) -- a single run-level org_node column was never accurate once Phase 2b/2c landed, and real per-node ownership already lives in work_node_execution.subagent_type. Schema: work_graph_run.org_node column removed; ux_work_graph_run_active narrowed from UNIQUE(task_id, org_node) to UNIQUE(task_id) WHERE status NOT IN ('done', 'failed') -- 'blocked' now counts as active on purpose, since resuming a blocked run always appends into the same row rather than inserting a fresh one. New migrate_drop_work_graph_run_org_node() handles already-populated databases, wired into backend_server.py's startup path. Call sites updated: work_graph_plan.py/work_graph_fork.py/ root_cause_trace.py's INSERTs; work_graph_run_query.py/task_query.py now return "org_nodes_involved" (derived from work_node_execution.subagent_type) instead of the removed single-value "org_node"; frontend/app.js's org-strip and run-list rendering updated to the list-based shape. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
-
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>
-
…4843-main-checkout-drift
-
Implements docs/todo/work-graph-parallel-execution-design.md: run_graph() now schedules graph_manifest nodes layer-by-layer (topological_layers(), Kahn's algorithm grouped by round instead of flattened), running a multi-node layer's nodes concurrently via ThreadPoolExecutor (default 4 workers) with a barrier between layers; a single-node layer stays synchronous, matching every real graph_manifest observed so far. topological_order() is now a thin flattening wrapper, unchanged behavior (regression-tested). _LockedConn/_FetchedRows makes the existing scattered conn.execute() call sites in work_node_run.py/work_graph_orchestrate.py/execution_log.py safe to call from multiple threads without touching those call sites -- note the lock must cover the full execute()-through-fetchone()/fetchall() cycle, not just execute() itself, or two threads can still collide on the shared sqlite3 connection handle. That gap was caught for real (not theoretically) by RunGraphRealSqliteConcurrencyTest during development -- committing the fixed version, not the first draft. create_worktree() (work_node_run.py) gets a module-level lock around the `git worktree add` call for concurrent layers touching the same repo. New tests: layer grouping, same-layer concurrency + inter-layer barrier, one node's failure not cancelling a concurrent sibling (WorkGraphLayerError aggregates), breakpoint-recovery resume of a concurrent layer, a quota-wait timeout coexisting with a sibling's real persisted output, real (non-mocked) sqlite under concurrent writes across several rounds, and real concurrent `git worktree add` calls. Full src (575 tests) + supervisor (125 tests) suites pass with zero regressions. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
-
Adds paths.repo_root()/is_self_target() and forces needs_worktree=True in work_graph_orchestrate.run_graph() whenever target_folder_path is graphlemon's own checkout, regardless of caller intent -- 05 §5.8's unconditional rule, since a self-target in-place edit risks corrupting the currently-running process's own source out from under it. Adds src/core_engine_classify.py (path-based rule: .claude/agents/*.md, src/*, supervisor/* = core_engine; frontend/, docs/ = not) and bug_record.record_core_engine_change() (a PASS-path audit record, distinct from create_bug_record's FAIL-path root-cause attribution -- no route decision, status='resolved' from creation). scheduler.finish_task_lifecycle() records this audit trail as an additive side effect after close_task_done() on self-target PASS closures. Found and resolved a real SDD-internal conflict (confirmed with the user via AskUserQuestion) before wiring this up: supervisor-auto-rollback-design.md §1 triggers Deploy Supervisor on self-target+Validator-PASS alone, but 03-C §3.11/04-P §4.6 literally gate it on an existing core_engine bug_record -- and task_create.py confirms goal-type self-improvement tasks (the exact self-development-feasibility.md walkthrough scenario) never produce a bug_record on their happy path, which would silently defeat that whole task class under the literal reading. Resolved per user decision: trigger on self-target+PASS alone; the bug_record is a byproduct, not a gate. p_deploy_supervisor_blue_green (04-P §4.6) never touches task.status, so close_task_done() still runs unconditionally -- Deploy Supervisor is a fully decoupled state machine, matching §2's "no shared failure domain" principle. org_loop_route.py is intentionally untouched -- fast_lane/full_replan is FAIL-path retry routing, orthogonal to this PASS-path trigger; deployment row creation stays U-037's job per its own Done criterion. 417 tests green; RealGitWorktreeIsolationTest (U-013/REQ-03's real git worktree regression) re-verified passing per this Unit's own Done criterion. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
-
CLAUDE.md is explicit that PH5 (self-modification/auto-rollback) must not start until PH4 has genuinely closed -- not just "all unit tests green," but 06-验收与测试锚点.md's REQ-01~14 happy/boundary/failure cases actually covered. A REQ-by-REQ audit (the same discipline that caught U-031's integration gap) found 5 real gaps: - REQ-03 failure: work_node_execution.status jumped straight running->retrying, skipping 'reflecting' (declared in the schema enum, never once written by any code). - REQ-05 failure / REQ-09 boundary: the "scheduler keeps serving other queued tasks past one blocked_pending_human" scenario was never tested against a real scheduler -- the old test literally said "no scheduler exists yet to test against directly" (stale since U-032). - REQ-06 / REQ-07 / REQ-14 failure (the biggest gap, shared root cause): CorruptPersistedStateError, ClassifierBlockedError, and UsageLimitWaitTimeoutError were each correctly raised and each correctly marked their own work_node_execution 'blocked', but nothing ever routed that to task.status='blocked_pending_human' with the blocked_reason each REQ's acceptance text names. e2e_pipeline.run_end_to_end is split into run_task_lifecycle() so scheduler.py's run_goal_to_completion can create the task itself and catch these three specific exceptions, following the same UPDATE+execution_event pattern budget_guardrail.check_budget() already established for REQ-10. - REQ-02 boundary: PRD internal-contradiction check (verifying->reflecting) had no implementation anywhere -- artifact_write always marked validation_status='passed' unconditionally. Added an optional verify_fn hook to work_graph_orchestrate.run_graph() (one regeneration attempt, then ConsistencyCheckFailedError) and a real consistency-check agent() call scoped to the PRD node only. The first real run of this new call caught a genuine bug: the model returned "consistent": "false" as a JSON string, not a boolean, which `if ok:` silently treated as truthy -- fixed with explicit _coerce_bool(). - REQ-13 failure: minor test-assertion weakness (WS 404 rejection test didn't check the JSON error body). 384 tests green. REQ-01~14 now have real, exercised coverage rather than a "tests are green" assumption -- PH4 can be treated as genuinely closed. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
-
U-031: closes a structural integration gap found during the REQ-01~14 regression audit -- plan_work_graph/execute_work_graph/run_work_node were each individually tested but never actually called together in production code (e2e_pipeline.py's only validated closed loop bypassed all three via flat org_node_trigger calls). Adds work_graph_orchestrate.py (topological sort over graph_manifest + one one-node dynamic-workflow agent() call per Work Node, needed for REQ-06's per-node breakpoint recovery), rewires e2e_pipeline.py's plan_documents/ implement_code onto the real chain, and fixes two bugs a real API run surfaced: graph_manifest's id/node_id/depends_on normalization (work_graph_plan._normalize_graph_manifest) and a missing repo_path in run_work_node's cwd resolution. work_node_run.py also now marks a node 'blocked' instead of leaving it stuck 'running' on any unretryable run_fn exception. U-024.5: the regression audit also found REQ-12's reconnect boundary case (refetch a snapshot after a dropped WS reconnects) was never implemented -- only the dashboard reacted to onStatusChange, and even it never refetched. Fixes mountDashboard/mountTaskBoard/mountTaskDetail (which embeds v_graph_visualizer) to refetch their current snapshot on reconnect. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>