OBS-11 — stop/resume killed pure-native runs over a phantom external pin.
Role templates' preferred_external_agent leaked into execution identity even
when the user requested native and execution actually ran native; on resume
the availability gate trusted the pin and failed every non-terminal item.
Root fixes across the whole chain:
- Staffing card per-role defaults are now the RESOLVED backend (explicit
session agent choice > runnable template preference > native), never a
hardcoded external default; seat enrichment and the dispatch selector's
locked branch downgrade provably unavailable externals to native and
record the wish in execution_agent_unavailable.
- The resume availability gate fails closed only when a resumable external
session actually exists; a bare pin heals to native (snapshot AND task
durable identity) and the run resumes — mirroring dispatch fallback.
- Suspend-checkpoint replies: force_resume (chat/headless spelling) is
recognized alongside ui_force_resume, and bare continuation tokens
(English and Chinese spellings) take the plain-resume path instead of
being routed to the final decider as content, which reopened the
already-approved intake card.
OBS-5 — failed runs never closed and dropped new input. The dispatcher's
convergence exit now settles terminally-failed runs (status=failed,
lifecycle=closed_failed, run_failure metadata) and emits a
company_run_failure_review card whose replies never swallow messages:
dismiss acknowledges, content falls through so normal routing starts a
fresh run. _maybe_resume_existing_company_runtime no longer re-executes a
terminally-failed tree: control replies get an honest closed status,
content-bearing input starts a new run.
OBS-6 — provider quota exhaustion terminally failed work items. Rate-limit
rejections are classified (LLMProvider.is_rate_limit_error, covering
status codes, exception types, and English/Chinese provider error text),
the agent runtime raises typed ProviderQuotaExhaustedError instead of
burning conversation-feedback retries, and the company dispatcher parks:
the item returns to READY (attempt interrupted, no terminal failure), the
member session idles, and claiming backs off exponentially (60s doubling
to a 900s cap; a quiet 30min resets the streak) before resuming
automatically.
Verified end-to-end on the real minimax-m3 campaign: same goal, same 300s
stop point, same run shape that previously killed the whole tree within
90s now resumes cleanly and completes with all items approved; staffing
defaults native for all 11 roles.
Tests: test_stop_resume_native_pin (10), test_run_failure_settlement (6),
test_provider_quota_park (9); attempt-ledger, recruiter, and
suspend-resume suites updated to the new contracts (their old assertions
pinned the defective behaviors).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Root-cause fix for the project-4444 class of deadlocks: any FAILED/
CANCELLED work item with downstream dependents used to block its whole
tree forever, because the advancement gate required all dependencies to
be APPROVED and nothing ever propagated or triaged failures.
Settlement mechanism (work_item_transition.py):
- compute doomed set (FAILED/CANCELLED seeds contagious through hard
deps); settlement-released cards are treated as alive
- three-way advancement gate: all-approved (unchanged) / settled-with-
failures releases the nearest decision-capable card (manager parent ->
failure-triage synthesis turn, rollup delivery/aggregate -> READY)
with an atomic dependency_settlement stamp; released cards never
oscillate back
- claim/park/resume/dispatcher-tick all honor the stamp: runnable gates
admit settled failed+stuck deps, parking excludes settled deps and
re-arms triage when a failure raced the park, engine resume no longer
re-locks released cards, the dispatcher tick releases rollup cards
created after the failure
- settlement cascade: once the settled card is APPROVED, stuck children
the manager did not rebuild are cancelled (transitive closure over
stamped stuck seeds, retried until every cancel lands)
- info-class deps never block settlement; adaptive runnable gate now
shares DEPENDENCY_CLASS_DEFAULT with the release gates
Dispatch guard (company_mode.py):
- NO_DELEGATION_JUSTIFICATION parsing tolerates markdown decoration
(bold/lists/quotes/full-width colon) and rejects placeholder echoes
across all artifact/metadata/content channels
- retries exhausted no longer FAILs the work item: dispatch is a soft
constraint, so the turn output is accepted as normal completion and
annotated via manager_dispatch_guard_unresolved; the reminder loop is
unchanged, and the mutation flag is now reset per turn so one past
delegation can never mute future reminders
- manager board context now surfaces failed/cancelled children with
their preserved output and pending-cancellation stuck list so the
triage turn can rebuild, accept partial results, or escalate
Self-produced delegation output goes through review (persisted fact,
single predicate):
- the DONE transition classifies what a dispatch/intake/plan turn
actually delivered from store ground truth (live children => delegated,
none => self_produced) and persists turn_output_kind/-source on the
WorkItem
- is_manager_reviewable_turn honors the persisted marker, so the DONE
routing, report spawn, report completion and recovery scans all read
the same fact — this closes a pre-existing hole where
NO_DELEGATION_JUSTIFICATION output auto-approved with no review at all
- escalation requires a real agent manager above; top seats reporting to
the human owner keep auto-approve (covered by final delivery's human
acceptance) instead of minting unclaimable review cards
- dispatcher tick reconciles reviewable cards stuck in
AWAITING_MANAGER_REVIEW with no live report/review card by rebuilding
the report card idempotently (legacy DBs, crash windows)
Verified: 4444 tasks.db replay unwedges end to end; real-store
report->review chain exercised without lifecycle mocks (mutation check
confirms the tests bite); full suite failure set identical to a
same-session HEAD baseline run (all remaining failures pre-existing or
environment flakes reproduced at HEAD).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>