• 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>
    bboonnee authored
     
    Browse File »
  • 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 org-graph-unification-phase2-universal-self-planning-design.md
    §2.3, §3, §6 -- Coder's implement_code() no longer runs one hardcoded
    synthetic "implement" node; it self-plans via plan_work_graph(conn,
    "coder", ..., append_to_run_id=run_id), appending its own nodes onto
    Planner's existing work_graph_run instead of creating a separate one.
    
    - work_graph_plan.py: per-org_node suggested node-type catalogs
      (_CODER_NODE_CATALOG/_VALIDATOR_NODE_CATALOG, "starting points, not
      requirements" same as _PLANNER_NODE_CATALOG), new judgment/on_fail/
      promotes_to_artifact fields in the generic planning prompt. New
      plan_work_graph(..., append_to_run_id=...) parameter: merges newly
      planned nodes into an existing run (node_id collision -> raise, never
      silent overwrite), returns new_node_ids so callers can avoid
      reprocessing nodes an earlier stage already promoted to artifacts. New
      shared dispatch_build_prompt() for graphs mixing Planner-shaped
      (artifact_type) and Coder-shaped (task_prompt) nodes side by side.
    
    - e2e_pipeline.py: _write_completed_node_artifacts() now also promotes
      nodes declaring promotes_to_artifact (not just Planner's artifact_type
      nodes), with an only_node_ids scope so a merged-graph caller doesn't
      re-touch artifacts an earlier stage already wrote. implement_code()
      reworked around self-planning; code_diff stays Python-computed (a real
      git diff, not any node's own content -- no node can know the diff ahead
      of running it), test_report is promoted from whatever the self-planned
      graph declares, falling back to a synthesized concatenation if it
      declares none. needs_worktree=True now passed to run_graph() for Coder
      (found missing entirely during this rework -- harmless with the old
      single-node manifest, a real 03-C §3.6 gap once concurrent code-writing
      nodes are possible). Also fixed a real bug found while wiring this up:
      _review_planner_output_with_retries()'s "reuse existing artifacts"
      branch hardcoded run_id=None, even though every real artifact row
      already has a valid produced_by_run_id -- Coder had nothing to append
      into on that resume path.
    
    - work_graph_fork.py: _reconstruct_build_prompt now dispatches per-node
      (via the new shared dispatch_build_prompt) instead of requiring the
      whole graph to be one uniform shape -- a real regression Phase 2b would
      otherwise have introduced silently, since a forked merged graph can now
      genuinely mix both node shapes.
    
    Sequencing note (unchanged from Phase 2a's own finding): work_graph_run's
    org_node column removal and the ux_work_graph_run_active index narrowing
    (design doc §2.1/§2.2) stay deferred to Phase 2c -- Validator still
    creates its own separate run until Validator also appends into the shared
    one, so narrowing the index to task_id-only now would collide with it.
    
    python3 -m unittest discover -s src (752 tests) + discover -s supervisor
    -p "test_*.py" (126 tests) both green, zero regressions.
    
    Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
    bboonnee authored
     
    Browse File »

  • Per CLAUDE.md's docs/ role split (todo = pending, done = shipped into the
    SDD/code): all seven Graph Engineering series items with a real
    implementation (B, D, E, F, G, H -- A had no separate doc, resolved
    directly in graphlemon_architecture.md; C is explicitly won't-do) now have
    their requirements+design docs moved from docs/todo/ to docs/done/,
    git mv'd to preserve history.
    
    Every cross-reference to the 12 moved files -- across the other moved
    docs themselves, graph-engineering-open-items.md, 2 Skill files, and 9
    src/*.py docstrings/comments -- updated from docs/todo/<file> to
    docs/done/<file>. Verified no stale docs/todo/ references to any of the
    12 filenames remain anywhere in the repo.
    
    graph-engineering-open-items.md itself stays in docs/todo/ (not moved) --
    it's a living index that keeps gaining new entries from later
    comparison-note/gap-analysis passes (H itself was added this way, and a
    new item already appeared while this cleanup was in progress), not a
    single finished conclusion. Its own header now reflects that all of
    A/B/D/E/F/G/H are done and explains why it wasn't moved. Also fixed two
    pre-existing stray path references (missing todo/done/ prefix entirely,
    predating this cleanup) in its G section.
    
    Full src suite (625 tests) passes -- this is a pure documentation/comment
    change, no behavior touched.
    
    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 »