-
User-reported gap: the alert banner only ever showed task.blocked_reason (a coarse category like 'execution_error') with zero indication of the actual cause -- the real message only existed in the matching task_status_changed execution_event's own detail text, with no path to the UI at all. Diagnosing today's several distinct real blockers required querying the DB directly each time, which the user correctly flagged as something the console itself should surface. task_query.get_task() now returns blocked_detail (the most recent blocking event's detail text) when status is blocked_pending_human. v_task_detail shows it as an expandable <details>/<summary> inside the alert banner (no JS wiring needed, matches the plain-vanilla-no-framework convention) so a long or multi-line real error message doesn't force itself into the banner's layout by default but is one click away in full, not truncated or hidden. Also investigated (not a bug, documented here for the record): two node logs the user found empty really are empty on disk -- execution_log_file rows exist but their target files were never created, for two nodes dating back to the task's original 2026-08-04 run, long before today's fixes. The log viewer's "暂无日志内容" is accurately reporting that state, not a rendering bug. 820/820 tests, frontend smoke passes. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
-
Real incident (2026-08-13, task b243dfe8): _normalize_graph_manifest() calls _validate_loop_back_targets() on the newly-planned manifest BEFORE it's merged with the existing persisted one (append mode). A new node's on_failure edge legitimately targeting an already-persisted node from an earlier append (e.g. a new verification node looping back to an earlier SDD node) was wrongly rejected as "does not exist in this graph_manifest" -- it genuinely doesn't exist in the brand-new manifest by itself, only once merged. _validate_loop_back_targets() gains additional_valid_target_ids, threaded from plan_work_graph()'s existing_manifest through _normalize_graph_manifest(). Ancestor-chain validation is skipped for a target in this set -- an already-persisted node's ancestry was validated when it was originally planned. New unit test for the validation function directly, plus a real end-to-end test through plan_work_graph() in append mode. 817/817 tests. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
-
Real incident (2026-08-13, task b243dfe8): run_work_node() unconditionally INSERTed a new execution_log_file row every call. Fine the first time, but if the process crashed/restarted between that INSERT and execute_work_graph() genuinely returning, work_node_execution.status is left at 'running' (not 'done', not a fresh node) and an execution_log_file row already exists for that node_exec_id. The next run_work_node() call for the SAME node_exec_id (REQ-06 requires this to be resumable) hit 'sqlite3.IntegrityError: UNIQUE constraint failed: execution_log_file.node_exec_id' and could never recover -- this exact bug is what task 2084590a's own (still-blocked) goal describes. Reuses the existing row (log_file_id, file_path) instead of re-inserting, same "resume must reuse what already exists" pattern this function already applies to git_worktree_ref a few lines below. New test confirms the exact production traceback on the pre-fix code and passes post-fix. Also adds docs/todo/2026-08-13-blocked-pending-human-incident-retrospective.md, today's consolidated retrospective + fix/execution-order plan for the 6 tasks that were blocking on various independent real causes. 815/815 tests. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
-
Real incident (2026-08-13, task b243dfe8): _handle_task_route's auto-continue allowlist was ("queued", "planning_brd_prd_sdd", "coding", "validating"). Org Graph unification Phase 1 (2026-08-08) added 'reviewing_planner_output' to task_execution._RESUMABLE_STATUSES, but nobody updated this separate allowlist to match -- the same exact bug the 2026-08-07 'validating' fix (see the existing comment right above this change) was supposed to have taught us to watch for, just one status later. Effect: manual_resume onto a task landing on 'reviewing_planner_output' flipped the DB status back and returned 200, but spawned no background thread. The task sat completely idle (zero new execution_event rows, no real subprocess) -- which looks identical to "still stuck" from the console, even though the actual underlying bug that originally blocked it (a separate, already-fixed issue) was long gone. Diagnosed live: resumed b243dfe8, watched it sit with no activity for 7+ minutes, found zero events past the resume's own status-change row and no claude subprocess running anywhere. New regression test mirrors the existing 'validating' one exactly. 814/814 tests. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> -
Requested by user after today's incident retrospective: a manually-assignable execution-order hint across a project's tasks, shown as a new "执行顺序" column on v_task_board. Serial steps are whole numbers (1, 2, 3); parallel siblings of one step share the same integer part as decimals (2.1, 2.2). Purely advisory -- nothing in the scheduler/dispatch loop reads it, it's a human/Boss-Agent-facing planning aid, not an enforcement mechanism. - schema.py: task.execution_priority REAL (nullable), migrate_add_task_execution_priority (plain ADD COLUMN, no CHECK constraint). Two earlier CHECK-rebuild migrations that also touch task (migrate_relax_org_node_constraints, migrate_add_reviewing_planner_ output_status) now call it as a prerequisite and include the column in their own rebuilt task_new, same "depends on a later additive column" pattern migrate_relax_org_node_constraints already used for migrate_add_work_graph_fork_columns. - task_query.py: list_tasks/get_task expose it; new update_task_execution_priority (unlike update_task_goal_text, NOT gated to status='queued' -- it's a display hint, not a planning input, so it stays settable on in-flight/blocked tasks too). - backend_server.py: PUT /api/tasks/:id now accepts execution_priority independently of goal_text on the same endpoint. - frontend/app.js: new editable column on v_task_board, PUTs on change. Also adds docs/todo/append-run-node-id-collision-across-org-nodes-requirements.md, a third real finding from today's retrospective (task 911861fe: Coder and Validator's suggested node catalogs both converge on node_type="test_script", so their self-planned node_ids collide inside a shared merged work_graph_run -- PlanningFailedError, uncaught by _ROUTABLE_EXCEPTIONS, falls into the same generic execution_error bucket FR-7 already flagged). 813/813 src tests, 134/134 supervisor tests, frontend smoke passes. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
-
Real incident (2026-08-13, task 71868db6): ConcurrencyLimitReachedError isn't an error -- it just means this dispatch attempt found no free slot, which is normal, expected backpressure. Routing it through the same blocked_pending_human/ execution_error bucket as a genuine failure was itself a bug: it forced a task that should just wait its turn into looking like it needs human judgment. _check_concurrency() raises before any task.status transition happens for this attempt, so task_execution.py::_mark_blocked() now leaves status untouched (still 'queued' for a fresh dispatch) instead of blocking -- the next new_goal_dispatch tick naturally retries it, no human/Boss Agent involvement needed. Still logged as a new 'concurrency_wait' execution_event (new migrate_add_concurrency_wait_event_type, same accumulated-CHECK-enum pattern as the existing event-type migrations) so the wait stays auditable, not silently invisible. This is the first concrete instance of FR-7 in docs/todo/boss-agent-autonomous-blocked-task-arbiter-requirements.md (system should emit distinguishable blocked_reasons/non-error states at the point of failure, not dump everything into one generic bucket). 803/803 src tests, 134/134 supervisor tests. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
-
…a664-main-checkout-drift
-
…9856-main-checkout-drift
-
Two real findings from today's live self-hosting run, surfaced while diagnosing why bfd3ee82/71868db6 were blocked: 1. trigger_org_node/trigger_org_node_structured use a fixed wall-clock subprocess.run(timeout=...) -- a long-running-but-genuinely-progressing agent call gets killed just for taking longer than a guessed constant (300s), which is exactly what happened to bfd3ee82's Validator planning call. Per an already-established (but never actually implemented) decision: an agent call should never be judged "stuck" by total duration alone, only by an extended period with no activity AND no error. New requirements doc: docs/todo/agent-call-liveness-not-fixed-duration-timeout-requirements.md. 2. task_execution.py::_mark_blocked's catch-all dumps anything outside a small exception whitelist into blocked_reason='execution_error' -- including ConcurrencyLimitReachedError, which isn't an error at all, just normal backpressure. Boss Agent needs the system to emit distinct, meaningful reasons at the point of failure, not reverse-engineer root cause from a generic bucket -- added as FR-7 to the Boss Agent doc. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
-
Requirements doc (BRD/PRD level) for a new org-level role that monitors blocked_pending_human tasks, does real diagnosis (not blind retry), and acts within an explicit authorization boundary instead of always waiting on a literal human -- generalizing the planner_reviewer precedent (an autonomous judgment agent already replacing a human review gate) to this surface. Motivated by today's real incident: 4 tasks blocked with the same generic execution_error reason but three genuinely different root causes (stale process, legacy narrative-output format, a real concurrency bug), all diagnosed by hand. Also documents watch_resume.py's real concurrency-race flaw as a requirement input (FR-6) so the eventual implementation doesn't repeat it. Deliberately does not pick the autonomy boundary per blocked_reason -- left as an open question for explicit user sign-off, not something Planner should infer silently. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
-
v_task_detail's org-strip only ever covered planner/coder/validator -- no way to see planner_reviewer's verdict trail from the task detail page at all, only from v_graph_console. Rather than maintain two parallel, drifting implementations of "org node status for this task", v_task_detail now reuses the same 4-stage Org meta-graph component (renderOrgMetaGraph/mountOrgMetaGraph) v_graph_console already has. mountOrgMetaGraph/renderOrgMetaStageDetailHtml gain an optional enableNodeClick option so v_task_detail's usage gets real per-node live log-tail expansion (wired through the existing activeLogViewers/closeAllLogViewers/mountLogViewer machinery) while v_graph_console keeps its existing read-only snapshot behavior unchanged. ORG_NODE_DETAIL_RE now also accepts planner_reviewer so deep links into the 4th stage are reachable; landing on one auto-expands and scrolls to it (focusOrgMetaStage), matching the old focusOrgNodePanel's behavior. Dashboard's own 3-node org-strip is untouched. Deleted the now-dead renderTaskDetailOrgStripHtml/renderOrgComboPanelContent/ wireOrgComboArtifactClicks/focusOrgNodePanel. node frontend/test_graph_console_smoke.js passes (extended with coverage for the regex widening and the enableNodeClick threading), independently re-verified. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
-
Real prod incident (2026-08-13): two live tasks crashed with sqlite3.IntegrityError UNIQUE constraint failed: work_graph_run.task_id right after a planner_reviewer FAIL/INCONCLUSIVE verdict. ux_work_graph_run_active (just added this session) allows only one non-terminal work_graph_run row per task_id, but a rejected review's retry called plan_documents() with no run_id, which always INSERTs a fresh row -- the rejected attempt's own row is never marked done/failed just because its content was rejected (Phase 2c: one run spans a task's whole lifecycle). plan_documents() gains append_to_run_id, threaded into plan_work_graph()'s existing append machinery (same convention implement_code() already uses for Coder). _review_planner_output_with_retries() now carries prior_run_id across retry attempts so a re-plan appends into the still-open run instead of colliding with it. The first attempt (no prior run) is unaffected. New test drives a real FAIL-then-PASS retry through the actual plan_work_graph() INSERT path and the real ux_work_graph_run_active index -- confirmed it reproduces the exact production traceback on the pre-fix code and passes post-fix. 801/801 src tests, 127/127 supervisor tests, both independently re-verified. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
-
Real self-hosting DB (2026-08-13) has 10 task_ids with multiple non-terminal work_graph_run rows each (legacy per-org_node-row leftovers from before the merged-graph architecture) -- the migration's final CREATE UNIQUE INDEX ux_work_graph_run_active ON work_graph_run(task_id) crashed against this real data (IntegrityError), and because executescript() commits each DDL statement individually, the crash left the live DB in a partially-migrated state: org_node column dropped, but the index never created, with the old idempotency check (`if "org_node" not in cols: return`) then permanently skipping any further attempt to create it. Adds _reconcile_duplicate_active_work_graph_runs(), which marks all but the most-recently-created non-terminal run per task_id as 'failed' (not 'blocked' -- the index's WHERE clause treats 'blocked' as still-active, which was the first fix attempt and still failed) before the index is created. Recency is ranked by rowid, not run_id: real data has started_at=NULL on every legacy row, so a run_id tiebreak would pick among duplicates by UUID string value, unrelated to actual insertion order. Also splits the idempotency check into column-drop and index-creation halves so a database already in the partially-migrated state (like the live one) gets the missing index created on the next run instead of being skipped. Dry-run verified against a copy of the live 36-row production DB before applying to the real ~/.graphlemon/graphlemon.db (backend_server was down for this, no concurrent writers). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
-
…0cd7-main-checkout-drift
-
…6f22-main-checkout-drift
-
Real production gap found while resuming stuck self-hosting tasks: .claude/agents/planner_reviewer.md was never deployed after Phase 1 (Org Graph unification, commit ea19c7d) added the planner_reviewer role -- role.json/SOUL.md/AGENTS.md all existed, but nobody re-ran agent_profile.deploy_agent_definitions() against this live checkout after adding the role, so every task reaching the planner_reviewer review stage failed immediately with "claude --agent 'planner_reviewer' not found" and landed on blocked_pending_human/execution_error. This has silently been blocking every task since Phase 1 shipped. Re-running deploy_agent_definitions() also caught coder.md/validator.md drifting out of sync with their role.json skills lists (missing design-dynamic-work-graph, work-graph-node-review, skill-defect-remediation, unknown-scope-defect-sweep -- accumulated from several sessions' worth of role.json edits that never got redeployed). planner.md was already in sync. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
-
This is a point-in-time snapshot doc (dated 2026-08-03) that's explicitly meant to be hand-edited in place as gaps close, not rewritten -- three entries had gone stale relative to work landed since: the Planner-output review gate (Phase 1, already done back in early August but never marked here), the Work Graph node execution deblackbox migration, and the new-Goal auto-dispatch scheduler loop. Updated each to ✅ and refreshed the "most worth watching" summary and the self-hosting task table row accordingly -- the still-open Deploy Supervisor poll_fn gap is called out explicitly as a *different*, still-unsolved closed loop so it doesn't get conflated with the now-solved scheduler entry point gap. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
-
Removed the "disabled" framing from docs/done/validator-test-script- narrative-output-issue.md (moved todo/ -> done/, root cause identified, structural fix landed, spot-check clean) -- the mechanism it described (_CANONICAL_DOC_CHAIN, e2e_pipeline._VALIDATOR_MANIFEST) no longer exists in production code, superseded by the 2026-08-08 self-planning rewrite and Org Graph unification Phase 2. Planner's and Validator's self-planning catalogs already carry test_script as a suggested (not required) option; _CODER_NODE_CATALOG was the one gap -- added a matching entry there (mechanical check_script_compiles judgment, same as Validator's). All three org agents now decide per-goal whether this node is worth planning, with no remaining "this node type is globally off" switch anywhere. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
-
org-graph-unification-and-universal-self-planning-requirements.md, org-graph-unification-phase2-universal-self-planning-design.md, scheduler-new-goal-dispatch-requirements.md, and work-graph-node-execution-deblackbox-requirements.md all moved docs/todo/ -> docs/done/ (already done in earlier commits via git mv) -- this fixes the remaining docs/todo/ path references to these four files across the docs that cross-link them. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
-
Spot-check (real API spend, user-authorized) of whether the historical "narrative text standing in for real output" failure mode (docs/todo/validator-test-script-narrative-output-issue.md) recurs now that Coder self-plans its implementation graph (Org Graph unification Phase 2). Built a non-self-target temp repo with a real rate-limiter module containing a planted bug, and a goal requiring Coder to read it and produce an audit report -- the same "explore then produce content" trigger condition the original incident's root-cause analysis identified. Ran the real production path (plan_work_graph + run_graph) with RUN_REAL_AGENT_E2E=1. Result: not reproduced. The self-planned node's content was a real, line-cited audit report (correctly found the planted bug plus four other genuine issues), not narration standing in for missing work -- despite the Coder catalog's "impl" entry having no suggested_judgment, the planning LLM voluntarily attached its own narrative-detection judgment, closely mirroring work-graph-node-review's methodology. Recorded as a new timeline entry with an explicit single-run-confidence caveat and a concrete next step (_NODE_REVIEW_JUDGE_PROMPT wired directly into the catalog) if a real recurrence shows up later. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
-
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>
-
New src/new_goal_dispatch.py (find_queued_tasks() + dispatch_once(), mirroring task_reconciliation.py's shape but deliberately a separate module/loop -- scheduler-task-reconciliation-design.md §7 already established the "don't merge into one mega scheduler loop" principle, this follows it). Wired into backend_server.py::main() as its own daemon thread with --new-goal-dispatch-interval-seconds (default 45s, shorter than reconciliation's 300s to satisfy the near-real-time acceptance bar) and --disable-new-goal-dispatch-loop. Also added the matching --disable-new-goal-dispatch-loop flag to supervisor/deploy_stage.py::_launch_candidate() -- same reasoning as the existing --disable-reconciliation-loop flag there: a health-checking deploy candidate runs against a copy of the production DB and must stay passive until Deploy Supervisor decides it's live, otherwise it would start autonomously dispatching real Goals off stale/copied state. User-confirmed 2026-08-13: full auto-dispatch, not a conservative default-disabled rollout -- this was previously flagged as a standalone "changes the system's own autonomy boundary" decision requiring separate review (docs/done/scheduler-new-goal-dispatch-requirements.md), now resolved. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>