-
Implements docs/todo/verifier-fan-out-jury-design.md. root_cause_trace.py: _tally_perspectives() extracts the existing >=2/3 rule out of judge_root_cause so the closure-based version and the new judge_root_cause_via_work_graph() share one implementation, not two that could drift apart. The fan-in vote stays plain Python (zero_token aggregation per the design-dynamic-work-graph Skill's own edge_type distinction) rather than becoming a fourth Work Node -- no reason to pay for an Agent call just to count votes. judge_root_cause_via_work_graph(): each perspective becomes an independent Work Node with real schema-constrained structured output ({"category", "detail"} directly), not real_validator_perspective's manual "CATEGORY:"/"DETAIL:" text-line parsing. judge_root_cause / real_validator_perspective are kept, not removed -- documented as the lightweight fallback for scenarios that don't need worktree/Work Graph overhead. org_level_loop.run_fix_loop (the one real production caller) now calls the Work Graph version; the fixer/verify calls are unchanged flat trigger_org_node calls. Real bug found and fixed along the way: this is the first production code path that actually triggers a run_graph() multi-node CONCURRENT layer (every graph_manifest before F was single-node or a strict serial chain, so G's ThreadPoolExecutor path had never really run in production). scheduler.py::run_goal_to_completion and task_execution.py::start_task_execution_in_background both created their conn without check_same_thread=False -- fixed both, since their conn can now reach run_graph()'s worker threads via run_fix_loop. Test boundary migrated in test_org_level_loop.py/test_scheduler.py: the 3 perspective calls are now mocked at work_graph_execute.write_workflow_script/ execute_work_graph (matching test_work_graph_orchestrate.py's pattern) instead of org_node_trigger.trigger_org_node. New tests cover: three real independent Work Node executions, judgment-rule equivalence with the closure version, clean per-node input_payload, and concurrent wall-clock overlap across the three perspectives. Full src suite (586 tests) + supervisor suite (125 tests) pass with zero regressions. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> -
Implements docs/todo/dynamic-work-graph-design-skill-design.md. G already answered FR-2 (how to mark a parallel-eligible node group): no new field needed -- topological_layers() infers independence purely from depends_on/edges, so the new Skill's job is just "express real dependencies honestly, don't add fake ones." New Skill skills/design-dynamic-work-graph/SKILL.md: the node-boundary / zero_token-vs-needs_judgment / per-node self-contained task_prompt methodology, wired into agent_profile.py's FRONTMATTER for coder and validator (Planner's own doc-chain path is untouched -- FR-4 only names Coder/Validator). work_graph_plan.py: new _GENERIC_PROMPT_TEMPLATE + generic_node_prompt_builder(), used whenever org_node != 'planner'. Planner keeps its existing fixed brd/prd/sdd/benchmark/... chain (_PROMPT_TEMPLATE) completely unchanged -- zero regression risk to the one real production planning path. Scoped per the requirements doc's non-goal #1 ("prove the mechanism works, don't cover every real scenario yet"): does NOT wire into e2e_pipeline.py::implement_code()'s existing single-node production path. New tests prove the mechanism itself: a Coder scenario that naturally splits into 3 independent modules produces a correctly-shaped graph_manifest, topological_layers() puts all three in one concurrent layer (ties E directly to G), and generic_node_prompt_builder drives it through run_graph() to completion. Full src suite (580 tests) passes with zero regressions. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> -
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>
-
…de13-main-checkout-drift
-
The literal token value was committed in plaintext across 4 files (agent-memory notes, a stored run artifact, and a test assertion) while documenting that it had been redacted from migrated skill files -- the documentation itself failed to redact it. Replacing with placeholders/omission ahead of pushing this repo to a remote for the first time; the pre-existing commits (2a71bd5, 0cbf4b1, 14dee05) still contain the plaintext value in history. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
-
…85fa-main-checkout-drift
-
Root cause traced (docs/implementation-gap-analysis.md): the Benchmark document Validator relies on for its verdict was frequently a narrative about the work session ("The planner workflow completed and produced a Benchmark defining 18 scenarios...") instead of the actual scenarios -- found via a real skill-detail-page task's benchmark.md, then confirmed present since the earliest real self-hosting runs. Validator's own judgment was, in practice, resting on thin, sometimes-vacuous prose. Planner's work graph (brd->prd->sdd->benchmark) extends to benchmark->test_dataset->test_script: test_dataset/test_script are always present as nodes, but the generating subagent judges per-goal whether a real dataset/script applies (many goals, e.g. UI wiring, legitimately don't have one -- replying 'N/A: <reason>' is a real, expected answer, not a failure). test_script gets a genuinely mechanical verify_fn (real py_compile/node --check, not LLM judgment) -- the one node type where an objective check is actually possible. All four document prompts also gained an explicit anti-narration instruction (only 'brd' had a weaker version of this before). Coder's implementation prompt now receives the real benchmark/dataset/ script and must make the Planner's real script pass for real, not just whatever tests it invents on its own. Validator gets its own 3-node Work Graph (validator_benchmark -> validator_test_dataset -> validator_test_script), generated independently from SDD/PRD -- deliberately NOT reusing Coder's or Planner's own copies, same reasoning as a held-out eval set vs. the dev set a model was tuned against. The resulting script, if real, is actually executed against the current repository state; a non-zero real exit code force-overrides the verdict to FAIL in code (user-confirmed hard gate: the script is not up for LLM debate on a failure, only on a pass can subjective judgment add INCONCLUSIVE/risk notes). schema.py: artifact.artifact_type's CHECK constraint gains the 5 new types, plus migrate_expand_artifact_types() -- SQLite has no ALTER-based constraint migration, so this is the standard rebuild-copy-swap dance, applied for real to the live ~/.graphlemon/graphlemon.db (42 rows, verified byte-identical count before/after, integrity_check clean). skills/qa-task-validation.md and skills/project-sdd-planning.md already gained a standing principle from this same incident: verify cross-task data dependencies against real system state, not seeded fixtures alone (see prior commit d7035fc) -- this commit is the mechanism-level half of the same fix, not just the prose-guidance half. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> -
Real incident (2026-08-06): the skill-content migration task and the skill detail page bug fix were two separate tasks. Neither was asked to verify that migrated content is actually reachable through the DB-backed lookup the detail page uses. Both passed their own tests cleanly -- because both only ever exercised the mechanism against seeded/mocked fixture data, never checked whether the real producer's real output actually exists in the real system. The result: the skill detail page returned "not found" for all 12 real migrated skills, and nobody caught it until a human clicked through the real console. qa-task-validation (§8): passing unit tests against seeded fixtures proves the mechanism is correct given valid input -- it does not prove that input exists for real. When a feature reads data another task/process was supposed to have already written, Validator must independently query the real running system against a real (not newly-created) object. project-sdd-planning (§10): when a task's acceptance depends on another task's real output, the Benchmark must name a real, specific object as the acceptance anchor, not just describe the mechanism. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
-
…11fd-main-checkout-drift
-
…c231-main-checkout-drift
-
_launch_candidate() spawns a real `python -m src.backend_server` process (`revived`) to re-verify the previous version during a post-cutover rollback. On the success path it's correctly left running -- it IS the new Live. But on every failure path (never bound live_port, failed re-verification, git revert conflict) nothing ever terminated it -- found via 31 accumulated orphaned processes on this machine, one per failed rollback_path_b call across many real test runs this session. This is also the likely cause of RollbackPathBFailureTest's own reported non-determinism (three independent real Validator sessions saw it fail, never reproduced manually): a leaked process from an earlier failed run can still be squatting on the port a later run's _find_free_port() picks, producing a false "alive" health-check reading. Fix: call deploy_cutover._stop_process(revived.pid) in both failure branches before raising, mirroring the pattern cutover() already uses for its own stop_timeout-bounded process teardown. Also fixes RollbackPathBHappyPathTest's own matching leak (it re-appended bad_live.pid a second time instead of tracking the actual revived process, a copy-paste bug, not real cleanup) by capturing the real pid via a thin _launch_candidate wrapper. 31 pre-existing orphaned processes killed by hand; verified 5 repeated test runs after the fix leak zero new ones. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
-
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
-
Three real self-hosting fixes (log content never written, skill detail page missing real content, artifact list not clickable), two design questions set aside per user's request (unified Planner-driven work graph across all org agents, loop visualization on the graph), three bugs left for a future batch, and two infrastructure bugs found and fixed along the way (manual_resume not actually continuing execution for most block reasons, run_goal_to_completion crashing instead of blocking on unrouted exceptions). Also upgrades the RollbackPathBFailureTest flakiness note -- three independent real sessions have now hit it. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
-
…1a79-main-checkout-drift
-
…ea4d-main-checkout-drift