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

  • Attempt 10 crashed immediately in the fix committed last: git add -A --
    . ':!.graphlemon-worktrees' throws "paths are ignored by one of your
    .gitignore files" (exit 1, not just advisory text -- confirmed even with
    advice.addIgnoredFile=false suppressed) the moment that path is ALSO
    gitignored, which it now always is. Reproduced locally.
    
    Plain `git add -A` (no explicit pathspec) already skips gitignored paths
    correctly on its own -- the explicit exclude was redundant now that
    .gitignore covers it, and actively conflicting. Simplified
    ensure_worktree_committed() back down. Also added the same .gitignore
    entry to test_work_node_run.py's _init_git_repo() fixture so real-worktree
    tests match production config instead of coincidentally not hitting this.
    
    562 tests green (441 src + 121 supervisor).
    
    Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
    bboonnee authored
     
    Browse File »
  • Attempts 8 and 9 both hit "local changes would be overwritten by merge"
    again, despite the earlier _check_prd_consistency worktree-isolation fix.
    Root cause is deeper: git worktrees deliberately SHARE project identity
    with their main checkout (same .git, just another checkout) -- a real
    `claude -p` call's memory:project write doesn't reliably respect the cwd it
    was invoked with, and can land directly on the main checkout regardless of
    which specific call triggered it. Worktree-wrapping one call (as done for
    _check_prd_consistency) only moves around which call happens to trigger
    this; it doesn't fix the underlying issue.
    
    ensure_worktree_committed() now also runs against repo_path itself (not
    just the worktree) right before every merge_worktree() call, in both
    work_node_run.run_work_node() and e2e_pipeline._check_prd_consistency().
    Same already-tested mechanism, now applied generically regardless of which
    real call caused the drift or why.
    
    Fixing this surfaced a second real bug in the fix itself: running `git add
    -A` against repo_path while a node's own .graphlemon-worktrees/<id>/
    checkout is still present on disk picks it up as a gitlink-like entry,
    which then shows as "deleted" the instant remove_worktree() runs right
    after. Fixed by excluding .graphlemon-worktrees/ from both the dirty-check
    and the add via pathspec (not relying on the caller repo's own .gitignore),
    plus added it to graphlemon's own .gitignore for correctness generally.
    
    New regression test: test_drift_on_main_checkout_is_auto_committed_before_merge
    reproduces a run_fn writing directly to repo_path instead of its worktree,
    and confirms a second node's own merge isn't affected by it.
    
    562 tests green (441 src + 121 supervisor).
    
    Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
    bboonnee authored
     
    Browse File »
  • A real self-hosting run (U-042, first real exercise of needs_worktree=True
    since U-035 forces it unconditionally for self-target) exposed a real bug
    RealGitWorktreeIsolationTest never caught: its own run_fn always committed
    its edits, but a real Coder isn't instructed anywhere to git commit its own
    changes. The Coder genuinely edited src/org_loop_route.py and verified it
    in its own test_report -- but never committed, so merge_worktree()'s `git
    merge` was a true no-op ("Already up to date"), and remove_worktree() then
    silently discarded the dirty worktree along with the real work. code_diff
    came out empty; the change never reached the branch at all.
    
    Adds ensure_worktree_committed(): checks `git status --porcelain` in the
    worktree before merging and auto-commits any dirty state found. A no-op
    when the worktree is legitimately clean (e.g. a pure investigation task).
    Same "判断用 Agent,机制用代码" principle already used elsewhere in this
    codebase -- don't rely on persona prompt-engineering for a mechanical
    correctness guarantee that the system itself should hold.
    
    Two new regression tests: one reproducing the exact "edited but never
    committed" scenario, one confirming a legitimately-clean worktree still
    merges fine. 554 tests green (435 src + 119 supervisor).
    
    Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
    bboonnee authored
     
    Browse File »

  • CLAUDE.md is explicit that PH5 (self-modification/auto-rollback) must not
    start until PH4 has genuinely closed -- not just "all unit tests green,"
    but 06-验收与测试锚点.md's REQ-01~14 happy/boundary/failure cases actually
    covered. A REQ-by-REQ audit (the same discipline that caught U-031's
    integration gap) found 5 real gaps:
    
    - REQ-03 failure: work_node_execution.status jumped straight
      running->retrying, skipping 'reflecting' (declared in the schema enum,
      never once written by any code).
    - REQ-05 failure / REQ-09 boundary: the "scheduler keeps serving other
      queued tasks past one blocked_pending_human" scenario was never tested
      against a real scheduler -- the old test literally said "no scheduler
      exists yet to test against directly" (stale since U-032).
    - REQ-06 / REQ-07 / REQ-14 failure (the biggest gap, shared root cause):
      CorruptPersistedStateError, ClassifierBlockedError, and
      UsageLimitWaitTimeoutError were each correctly raised and each correctly
      marked their own work_node_execution 'blocked', but nothing ever routed
      that to task.status='blocked_pending_human' with the blocked_reason each
      REQ's acceptance text names. e2e_pipeline.run_end_to_end is split into
      run_task_lifecycle() so scheduler.py's run_goal_to_completion can create
      the task itself and catch these three specific exceptions, following the
      same UPDATE+execution_event pattern budget_guardrail.check_budget()
      already established for REQ-10.
    - REQ-02 boundary: PRD internal-contradiction check (verifying->reflecting)
      had no implementation anywhere -- artifact_write always marked
      validation_status='passed' unconditionally. Added an optional verify_fn
      hook to work_graph_orchestrate.run_graph() (one regeneration attempt,
      then ConsistencyCheckFailedError) and a real consistency-check agent()
      call scoped to the PRD node only. The first real run of this new call
      caught a genuine bug: the model returned "consistent": "false" as a JSON
      string, not a boolean, which `if ok:` silently treated as truthy -- fixed
      with explicit _coerce_bool().
    - REQ-13 failure: minor test-assertion weakness (WS 404 rejection test
      didn't check the JSON error body).
    
    384 tests green. REQ-01~14 now have real, exercised coverage rather than a
    "tests are green" assumption -- PH4 can be treated as genuinely closed.
    
    Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
    bboonnee authored
     
    Browse File »

  • U-031: closes a structural integration gap found during the REQ-01~14 regression
    audit -- plan_work_graph/execute_work_graph/run_work_node were each individually
    tested but never actually called together in production code (e2e_pipeline.py's
    only validated closed loop bypassed all three via flat org_node_trigger calls).
    Adds work_graph_orchestrate.py (topological sort over graph_manifest + one
    one-node dynamic-workflow agent() call per Work Node, needed for REQ-06's
    per-node breakpoint recovery), rewires e2e_pipeline.py's plan_documents/
    implement_code onto the real chain, and fixes two bugs a real API run
    surfaced: graph_manifest's id/node_id/depends_on normalization
    (work_graph_plan._normalize_graph_manifest) and a missing repo_path in
    run_work_node's cwd resolution. work_node_run.py also now marks a node
    'blocked' instead of leaving it stuck 'running' on any unretryable run_fn
    exception.
    
    U-024.5: the regression audit also found REQ-12's reconnect boundary case
    (refetch a snapshot after a dropped WS reconnects) was never implemented --
    only the dashboard reacted to onStatusChange, and even it never refetched.
    Fixes mountDashboard/mountTaskBoard/mountTaskDetail (which embeds
    v_graph_visualizer) to refetch their current snapshot on reconnect.
    
    Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
    bboonnee authored
     
    Browse File »

  • now 默认值从 time.monotonic 改成 time.time(墙钟),使 quota 等待的
    已耗时计算能在进程重启后正确续算;run_work_node 对已 done 的节点直接
    返回存量结果不重跑,对 retrying/waiting_for_quota 节点从持久化的
    retry_count/quota_wait_started_at 续算而非清零;needs_worktree=True
    时复用已存在的 worktree 而不是重新 create。新增
    resume_work_graph_run() 返回一次 run 里尚未完成的 node_exec_id 列表,
    并对内部不一致的持久化状态统一抛 CorruptPersistedStateError。
    
    Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
    bboonnee authored
     
    Browse File »
  • Re-checking REQ-14's boundary case against the letter of its text found a
    real functional gap, not just a testing gap: U-013's opus handling only
    did "skip backoff" -- it never actually retried on a downgraded model,
    just failed immediately. REQ-14 boundary says "不走退避轮询,直接降级到非
    Opus 模型重试" (skip backoff, retry immediately on a non-opus model) --
    the retry was the part that was missing.
    
    Fixed: run_fn's signature is now run_fn(cwd, model=None); an opus quota
    signal retries immediately (no backoff) with opus_downgrade_model
    (default "claude-sonnet-5"). If the downgraded model somehow also reports
    an opus signal (shouldn't happen -- it's not using Opus), this doesn't
    loop forever chasing it, raises UsageLimitWaitTimeoutError instead.
    
    work_graph_execute.py's own opus handling (U-012) deliberately NOT changed
    to match: REQ-14's coverage only names c_work_node_run/c_org_node_trigger,
    and that mechanism (a multi-agent dynamic workflow, no single top-level
    --agent identity) has no one "the model" to downgrade -- a deeper A-1
    question, documented as out of scope rather than silently left
    inconsistent without explanation.
    
    Also filled in a real test gap: quota_limit_type=weekly (detection +
    recovery, and the 9-day timeout) was never tested despite the mechanism
    already supporting it since U-013.
    
    11 new/changed stdlib unittest cases across work_node_run.py's test suite
    (all existing run_fn lambdas updated for the new signature). 178 total
    across U-001-020, all passing.
    
    This closes PH2-S3 alongside U-019. REQ-14 is now genuinely complete, not
    just "mostly right."
    
    Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
    bboonnee authored
     
    Browse File »
  • run_work_node(): the per-node contract -- input schema check (rejects
    outright, never starts, vs. output schema failure which retries), status
    machine (pending->running->(reflecting/retrying up to caller-specified
    max_retries)->done|blocked), execution_log_file lifecycle (active on start,
    closed in a finally so it closes even when run_fn raises), and
    USAGE_LIMIT_REACHED handling using 03-C §3.6's *exact* detection regex
    (`hit your (session|weekly|opus) limit`, case-insensitive) -- more precise
    than the phrase-matching approximations U-010/U-012 used before this Unit
    existed to give quota_wait_started_at/quota_limit_type a real owner.
    
    git worktree isolation (create_worktree/merge_worktree/remove_worktree)
    tested for real, no LLM call needed: two independent nodes each get their
    own worktree + branch, each run_fn writes and commits a different file,
    both merge back into the main checkout with --no-ff, git log confirms both
    commits landed, git_worktree_ref differs per node. This is REQ-03's
    boundary case, verified end to end with real git.
    
    "actual work" is an explicit required run_fn(cwd) dependency, not a hidden
    default calling `claude` -- what a node does is inherently node-specific
    (the whole point of "give each node a contract"); production callers wire
    in a real subprocess call, tests inject fakes.
    
    Corrects the same Done-line overreach as U-009/010/011/012 (5th occurrence):
    REQ-03's happy case needs c_artifact_write (still unowned, per U-011's
    flagged gap) and a real Coder session, neither of which U-013 has access
    to via its own dependencies (U-012 only). Boundary is what's real here.
    
    10 new stdlib unittest cases, all real (no mocking needed -- git and the DB
    are both fast/free/local). 117 total across U-001-013, all passing.
    
    This closes PH1-S2, the sub-phase development-plan.md's own text flagged as
    "本项目风险最高的 Sub-phase" (highest-risk in the project).
    
    Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
    bboonnee authored
     
    Browse File »