• 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 »