Extends U-006's execute_work_graph in place (same controller, being
completed, not a parallel module):
- ClassifierBlockedError: raised when a response's permission_denials array
has >=3 entries (03-C §3.5 says "3 consecutive or 20 cumulative" -- true
cross-call cumulative tracking needs persistence U-013 doesn't provide
yet, so this is a documented, conservative per-call approximation).
- UsageLimitReachedError (carries quota_limit_type) + a new
execute_work_graph_with_usage_limit_retry() implementing p_usage_limit_wait
(04-P §4.4.1): 5->10->20->30min backoff (repeating at 30) for
session/weekly quota hits, timeout after 8h/9d -> UsageLimitWaitTimeoutError;
opus quota hits skip backoff and fail immediately (model-downgrade retry
is a caller decision, not this function's). sleep/now are injectable so
tests don't block on real waits.
Retry operates at the whole-work-graph-call level, not per individual
work_node_execution row -- U-013 (c_work_node_run, which actually owns that
table) doesn't exist yet, so node-level quota tracking isn't attempted
here; noted explicitly in development-plan.md rather than silently
simplified.
Also corrects the same class of Done-line overreach as U-009/U-010/U-011
(4th occurrence): REQ-07's happy case literally asks for REQ-01~06 all
passing end to end, which needs PH2 (Validator root-cause tracing, Org-level
Loop, breakpoint recovery) -- U-012 only owns REQ-07's boundary/failure and
REQ-14's happy case, which was already correctly scoped.
23 new/changed mocked stdlib unittest cases (existing U-006 tests untouched
and still passing -- subclassing WorkGraphExecuteError keeps them
backward-compatible). 107 total mocked tests across U-001-012, all passing;
both existing real-agent tests (U-006's reused spike, U-011's planner call)
re-verified against the refactored code.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>