-
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>
-
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>
-
FR-5a: a new, standalone four-stage Org meta-graph (renderOrgMetaGraph and friends) rather than extending the existing 3-node renderOrgGraphTopology (left untouched, it's pinned by test_graph_console_smoke.js). Each stage expands in place: planner/coder/validator reuse renderGraphVisualizerPanel unmodified against that stage's latest run (identified via org_nodes_involved, Phase 2c's replacement for the removed single-value org_node column); planner_reviewer has no self-planned work_graph_run, so it shows its planner_review_verdict execution_event history instead (new task_query.py::_planner_review_events_for_task(), mirroring the existing _loop_back_events_for_run() pattern). FR-5b: an attempt_number-ordered, click-to-reveal feedback timeline built from loop_back_events, which was already being fetched but never rendered. New frontend/test_org_meta_graph_smoke.js (35 assertions, same vm.Context sandbox convention as the existing 4 smoke tests). 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>
-
…76ae-main-checkout-drift
-
Implements docs/todo/work-graph-time-travel-debugging-design.md, backend and console together (user confirmed 2026-08-06). Key finding that shrank the v1 scope: ux_work_graph_run_active is a PARTIAL unique index (only covers non-terminal statuses), not a blanket one -- forking from a parent run that's already reached a terminal status never collides with it at all. v1 restricts forking to exactly that case, so no index/constraint change is needed, only two new nullable columns (parent_run_id, fork_of_node_exec_id). Resolved the requirements doc's FR-1 ambiguity ("override input_payload, re-trigger execution") as OUTPUT SUBSTITUTION instead: the fork point's own output_payload is replaced with the human-supplied content directly, it is never re-executed via a new claude -p call -- only the strict downstream subgraph actually re-runs. This sidesteps reconciling the different build_prompt/input_payload conventions each caller uses (Planner's artifact_type lookup, E's generic task_prompt field, F's jury) -- work_graph_fork.py only needs the persisted graph_manifest and each node's output_payload. Implementation needs ZERO changes to the execution engine: pre-seeding every non-downstream node as a 'done' work_node_execution row before calling the unmodified run_graph() on the unmodified graph_manifest is enough -- run_work_node()'s existing REQ-06 breakpoint-recovery short-circuit (already-'done' nodes return their persisted output without calling run_fn) does all the "reuse without re-executing" work for free. _reconstruct_build_prompt supports two graph shapes generically from persisted state alone (Planner's canonical doc chain via e2e_pipeline._planner_prompt_builder, and E's generic task_prompt field); anything else raises ForkGraphShapeUnsupportedError rather than producing broken prompts. New: src/work_graph_fork.py (create_fork/execute_fork/fork_work_graph_run/ start_fork_in_background, the last splitting fast DB-only setup from slow real execution so an HTTP caller gets run_id back immediately, same pattern task_execution.start_task_execution_in_background already uses). work_graph_run gets parent_run_id/fork_of_node_exec_id (SCHEMA_SQL + migrate_add_work_graph_fork_columns for existing databases). work_graph_run_query.py/task_query.py surface both fields. New endpoint POST /api/work-nodes/:node_exec_id/fork. Console: a "从这里分叉" form on each 'done' node in v_run_detail, a fork badge linking back to the parent run, and a 🔀 marker on v_graph_console's run list -- no diff/merge UI (non-goal #3), read-only branch visibility only. Verified end-to-end for real: started the actual backend, sent a real HTTP fork request, confirmed the new run persisted with correct parent_run_id/fork_of_node_exec_id lineage. Tests cover requirements doc acceptance standards 1-3 (PRD swapped -> SDD/Benchmark genuinely re-execute, BRD untouched; original run completely unaffected; the same node forked twice produces independent branches) plus schema migration idempotency, query-layer field surfacing, the HTTP route, and 3 frontend smoke-test assertions. Full src suite (608 tests) + all 3 frontend smoke tests pass. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
-
Two new console pages requested directly by the user, beyond 02-V's original declared non-goal ("不做完整多项目管理 UI(项目列表/切换)"): - v_project_list: full project list + rename + archive/reactivate. "Import an existing directory with real code" needs no new code -- project_scaffold.create_project() already only ever adds .graphlemon/ inside the target folder. New: src/project_query.py (list/get/update), GET/PUT/DELETE /api/projects[/:id]. DELETE archives (status='archived'), never a physical row delete -- project_id is FK-referenced from task/ artifact/bug_record/etc., and 01-M's own active/archived enum already models this as soft-delete. - v_goal_list: extends the existing v_task_board/v_task_detail rather than duplicating them. Added sort/order to task_query.list_tasks() (column whitelist, no injection surface) and edit/delete on v_task_detail, both restricted to status='queued' (task_query.TaskNotEditableError, HTTP 409) -- editing or deleting a goal after real work has referenced it would leave that history pointing at something that no longer matches reality. Implemented directly rather than through graphlemon's own self-hosting loop -- confirmed with the user first that implement_code() always uses a hardcoded single-node manifest (no plan_work_graph() call for Coder), so a multi-page/multi-endpoint feature like this would've been one unreviewable Coder session with no way to decompose it. Real bug found on first verification pass (not caught by the existing _insert_task test helper, which never writes execution_event): a real task_create.create_task() always writes an execution_event row in the same transaction (01-M's FK, no ON DELETE CASCADE) -- even a never-touched queued task already has one, so DELETE FROM task raised sqlite3.IntegrityError. Fixed by clearing the task's own execution_event rows first; new regression test goes through the real create_task() path. 474 tests green. Verified end-to-end against a real running server (every new endpoint exercised via curl) since the Chrome extension is still unavailable this session. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
-
纯前端 Unit,数据已经在 U-025 的 c_task_get 里,只是 task_query.py 的 _work_nodes_for_run 补上了 hover tooltip 需要但当时没取的字段 (input_schema_ref/output_schema_ref/quota_limit_type/ quota_wait_started_at)。 frontend/app.js 新增 computeGraphLayers():按 graph_manifest 节点的 depends_on 边做拓扑分层,渲染成按执行层级排布的行,fan-out/fan-in 都能正确分层——用一个 n1→[n2,n3]→n4 的真实 graph_manifest 验证过, 直接从 app.js 里取出 computeGraphLayers 本体(不是重新实现一份逻辑) 跑真实服务器返回的 JSON,分层结果完全正确。节点按 03-C 3.6 节六态 配色,waiting_for_quota 态 hover 展示 quota_limit_type + 已等待时长。 02-V §2.7 原描述还包含一份 Org Graph 层,但 v_task_detail 页面顶部 已有等价的 org-strip 面板,这里判断重复渲染没有意义,只做了 Work Graph DAG 层,Org Graph 复用页面已有的那个。 嵌入位置:v_task_detail 里原来"随 U-026 补上"的占位提示换成了真实 的 DAG 面板。 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
-
三个页面需要的读接口此前都不存在,本 Unit 一并建了: - c_task_list/c_task_get(03-C §3.2,此前无 Unit 认领):新增 src/task_query.py + GET /api/tasks、GET /api/tasks/:task_id。 c_task_get 的返回比 03-C 字面契约更完整——额外带上 work_graph_run(含解析后的 graph_manifest)+ 每个 run 的 work_node_execution 列表,因为 v_task_detail 的 to-do 树需要这份数据, 03-C 已订正补全。 - c_org_loop_route(U-016 已实现 route_org_loop(),从未接 HTTP)第一次 接上 POST /api/tasks/:task_id/route,v_task_detail 的人工干预 (manual_resume)按钮需要它。 - 预算护栏此前没有任何读接口(03-C 只写了 PUT),新增 budget_guardrail.list_budget_configs() + GET /api/settings/budget 给仪表盘预算条用。 frontend/app.js 补上真实的 #/(org graph 三节点卡片、当前任务概要、 预算条、事件时间线,全部通过 c_ws_subscribe 实时刷新)、#/tasks (关键字/状态/org_node 过滤)、#/tasks/:task_id(task 字段、to-do 树、 关联 artifact/bug_record、blocked_pending_human 告警条 + manual_resume 按钮)。路由改成对象形式支持挂载态清理,切页面时关掉上一个页面的 WebSocket 连接。v_graph_visualizer/v_log_viewer 子模块明确标成占位 提示(随 U-026/U-027 补上),不是假造内容。 顺带把 U-023 里因 c_task_list 当时不存在而简化的 related_task_id 换回真下拉,goal_composer/bug_feedback 提交成功后也改回跳转真实的 v_task_detail。 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>