-
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>