• 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>
    bboonnee authored
     
    Browse File »


  • 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>
    bboonnee authored
     
    Browse File »

  • 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>
    bboonnee authored
     
    Browse File »

  • 纯前端 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>
    bboonnee authored
     
    Browse File »
  • 三个页面需要的读接口此前都不存在,本 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>
    bboonnee authored
     
    Browse File »