Skip to content

[Critical][next runtime] Add admitted-progress liveness to repository review and governance #187

Description

@sumitake

Severity and release requirement

Critical — must be fixed in the next signed runtime release.

Managed repository review and governance can be terminated solely because their original wall-clock budget expires even while the provider is healthy and making structured, runtime-admissible progress. This turns required review/governance evidence into a false timeout, can block governed delivery at the maximum public timeout, and creates pressure to bypass the managed route. The safe response today is to stop without replay; that is correct but operationally inadequate for legitimate long reviews.

This issue owns the runtime/client contract change and release qualification. It does not authorize raw-provider fallback, automatic replay, unsigned client-only behavior, or activation outside the normal release process.

Audited identities

  • Workspace source: sumitake/agent-collab-workspace@10f391ca26863fc0c206719f829f2c4dc82bb894 (clean exact head).
  • Public plugin/runtime client: sumitake/agent-collab@v7.0.0 / fb4723c696663efd9c725be8f62c521a720aa15e.
  • Packaged 7.0.0 identities observed during the audit:
    • manifest SHA-256: 2bf858764510fddfa86f491f677ad1a80d05b854a33d77a9a3230d0cb399fddf
    • runtime client SHA-256: 7d272ac732faa2262fbd2dd66b0dd5fc5a86cdc646b052fac53877c23e9dbed4
    • README SHA-256: 63e95d4d43ce8a3a06f5ac1641726008fdc4a82ac8736f670b72c8b304d1bc5a

Exact affected scope

At the audited workspace head, the critical Gemini-backed actions are:

  • review.repositorygemini/advisory.repository at family priority 0 (routing source).
  • frontend_review.repository → the same Gemini advisory transport at family priority 0 (routing source).
  • governance.repositorygemini/governance.repository at family priority 0 (routing source).

Important correction to the initial audit hypothesis: architecture.repository has no Gemini candidate at this head; it routes to Codex/Grok/OpenCode (routing source). It must not be cited as proof of Gemini starvation. It should remain total-deadline unless the implementation PR separately demonstrates a provider-neutral need and includes it in the same closed contract and regression matrix.

Evidence and root-cause chain

  1. The public contract explicitly excludes review/governance from lease renewal. Plugin 7.0.0 documents timeout_ms as a total deadline for every action except the two codegen actions (README).

  2. The public client hard-codes codegen-only liveness. runtime_client.py derives codegen_liveness only from _CODEGEN_ACTIONS, rewrites every other request to the remaining total budget, creates a progress pipe only for codegen, and calls _collect_bounded(... progress_reader, stall_interval=...) only on that branch (classification/deadline, pipe/collector).

  3. The runtime also hard-codes codegen-only descriptor admission. _claim_progress_sink accepts the private descriptor only when logical_action in _CODEGEN_ACTIONS; all other actions close it (provider runtime). _fresh_codegen_phase_deadline is likewise codegen-only (provider runtime).

  4. The read-only repository path drops the sink before adapter invocation. _invoke_repository calls _invoke without progress_sink, so merely teaching Gemini to accept the hook would still leave review/governance on the old path (provider runtime).

  5. Gemini is omitted from the adapter sink forwarding. _invoke forwards progress_sink conditionally to Codex/Grok/OpenCode, but its Gemini branch does not pass it (provider runtime).

  6. The generic supervisor already has the correct primitive. native_process requires a positive stall interval plus a monotonic probe, emits only fixed content-free marks, renews the internal stall budget only when the sequence advances, and deterministically terminates/reaps on silence or channel loss (validation, supervision loop). The fix should reuse this primitive.

  7. Gemini has three independent total-deadline kill points. Its argv builder turns the original remaining wall-clock budget into agy --print-timeout (native Gemini); its main provider call supplies neither stall interval nor progress probe/sink (native Gemini); and post-return parsing/cleanup still evaluates the original absolute deadline (parse, cleanup). Fixing only the outer client would therefore remain brittle.

  8. Gemini already projects the structured events needed for an honest probe. The projector retains closed step_update / native_tool_v4 identity and lifecycle fields and discards unknown raw events (native Gemini). This is the right observation boundary; raw provider text is not.

No provider request was launched during the original read-only audit. The defect follows directly from the closed client/runtime control flow. A later managed architecture review of this issue plan completed successfully and corrected the affected-action and sink-threading scope; its immutable receipt is recorded below.

Required design invariants

The implementation is acceptable only if all of these remain true:

  • One accepted request launches at most one provider attempt. A timeout, pipe loss, provider error, teardown error, or uncertain outcome is terminal; no automatic replay or provider fallback after provider start.
  • Pre-provider validation, readiness, source sealing, and launch remain under the original fixed total deadline.
  • After supervised provider start, timeout_ms is an inactivity lease only for actions explicitly marked by the signed descriptor.
  • Only a runtime-owned, content-free mark derived from a monotonic structured progress sequence renews the lease. Model prose, thinking, stdout/stderr byte volume, EOF, PID liveness, log growth, duplicate frames, malformed/anonymous events, usage frames, and the terminal result event never renew it.
  • Cancellation, output limits, source containment, exact-head binding, evidence verification, process-group cleanup, and the independent cleanup reserve remain terminal and unchanged.
  • Missing/invalid progress descriptor, absent probe, non-monotonic sequence, or EPIPE fails closed with truthful typed failure and confirmed cleanup.
  • The client creates a progress pipe iff the verified signed action contract selects admitted-progress supervision. Client/runtime mismatch fails closed; neither side guesses from an unversioned list.
  • No daemon, queue, broker, retry loop, heartbeat thread, second runtime, provider-specific raw-output heuristic, or hidden persistence is added.

Proposed implementation plan

1. Make timeout semantics one signed logical-action property

Add one closed enum to the compiled logical action descriptor, for example:

timeout_mode = total_deadline | admitted_progress_inactivity

This field—not duplicated _CODEGEN_ACTIONS sets—must drive public-client pipe creation, runtime sink claim, adapter stall enablement, and documentation generation. Mark the existing codegen actions plus review.repository, frontend_review.repository, and governance.repository as admitted-progress. Keep context actions and readiness total-deadline. Keep architecture.repository total-deadline unless its own need is separately proven.

Advance the routing graph/descriptor schema, direct wire identity, affected adapter wire identities, PUBLIC_RUNTIME_CLIENT_SHA256, manifest/wire mirrors, and provider runtime version atomically. A half-release is forbidden.

2. Generalize the existing public-client supervision path

  • Replace codegen-specific naming/branching with descriptor-derived admitted-progress supervision.
  • Preserve the current pre-launch budget and cleanup reserve.
  • Create/pass the private progress pipe only for a signed admitted-progress action.
  • Continue using _collect_bounded with progress_reader and stall_interval=timeout_ms/1000 after supervised start.
  • Treat pipe creation failure, pipe loss, and missing first runtime mark as typed fail-closed outcomes; close descriptors on every path.
  • Do not add an absolute wall-clock backstop after provider start. It would reproduce the same false kill at a larger number. The existing inactivity lease, output/resource caps, caller cancellation/disconnect, terminal protocol state, and process-group reap are the explicit lifecycle bounds.

3. Thread the lease through the complete read-only runtime path

  • Generalize _claim_progress_sink and _fresh_codegen_phase_deadline around the signed timeout mode.
  • Pass the claimed sink through _execute_edge_invoke_repository_invoke → the selected adapter.
  • Ensure post-provider receipt projection, source revalidation, contract validation, and cleanup receive one fresh finite timeout_ms budget after a long leased provider run; those phases do not renew indefinitely.
  • Preserve the provider-start truth bit and no-replay semantics on every wrapper/error path.

4. Add Gemini structured progress without trusting provider prose

Use a small stateful tracker at the existing stdout projector boundary. Its monotonic sequence may advance only on:

  1. the first well-formed occurrence of a (conversation_id, step_index) identity from step_update or native_tool_v4; and
  2. the first later success/failure close of that same identity.

Duplicate pending/in-progress/terminal frames for an already-counted transition do not advance. Unknown state, identity regression/collision, malformed JSON, anonymous tools, and raw text are ignored for renewal (or fail the request where the existing parser contract already requires it).

For admitted-progress Gemini calls:

  • pass stall_interval_seconds, the tracker's read-only progress_sequence probe, and progress_sink to native_process.run_native;
  • omit agy --print-timeout, because it is an unrenewable copy of the old wall-clock kill;
  • replace the original absolute deadline in post-return parse/source-validation/cleanup with the one fresh post-provider budget described above.

The provider's terminal result event is completion evidence, not liveness evidence.

5. Make every selectable adapter honor the logical-action contract

Because the public client allocates the pipe before route selection, every active candidate selectable for an admitted-progress action must accept it. Enable the already-structured progress probes for:

  • Codex (_AppServerDriver.progress_sequence),
  • Grok/ACP (AcpV1Session.progress_sequence),
  • OpenCode/ACP (its retained session progress sequence), and
  • Gemini (the identity-lifecycle tracker above).

An adapter that cannot provide an admitted structured probe must be ineligible for that action at descriptor compile/readiness time; it must not accept the route and silently fall back to total deadline.

6. Update documentation and failure vocabulary

Document timeout_ms once in terms of signed timeout_mode, list the currently admitted-progress actions, state the trusted progress events, and preserve the no-replay/cleanup rules. Typed diagnostics must distinguish at least: progress channel unavailable before launch, progress channel lost after launch, provider inactivity lease expired, invalid/non-monotonic probe, and post-provider phase timeout.

Failure/degradation matrix

Failure Required outcome
Progress pipe cannot be created or claimed before provider start Fail closed before inference; zero provider attempt; cleanup descriptors
Provider starts but emits no admitted structured progress for one lease timeout; terminate/kill/reap once; no replay
Raw prose/bytes/logs continue but no tool identity transition occurs Lease still expires
Progress sequence regresses or probe raises Typed provider/protocol failure; cleanup; no replay
Parent closes progress reader / runtime gets EPIPE Treat as cancellation/pipe loss; cleanup provider group
Provider exits while final output drains Use the existing bounded cleanup reserve and final fixed mark behavior
Post-provider parse/source/receipt/cleanup stalls Expire its one fresh finite budget; retain truthful attempt/evidence fields
Old client with new runtime, or new client with old runtime Reject by signed wire/client identity mismatch; never silently downgrade
Active route candidate lacks progress-probe support Descriptor/readiness fail closed before provider launch
Caller cancels at any phase Cancellation wins; deterministic cleanup

Required regression and qualification matrix

  1. Public client: descriptor-derived pipe creation; progress renews affected actions beyond the original wall clock; raw output/EOF/duplicate mark does not; silence/pipe loss terminates within lease + cleanup reserve; non-admitted actions remain fixed-total.
  2. Provider runtime: read-only sink survives _invoke_repository; all wrappers retain provider-start and cleanup truth; post-provider deadline refresh happens exactly once; no replay/fallback.
  3. Gemini adapter: only identity start/first close advances; prose, thinking, malformed/anonymous/duplicate/terminal events do not; --print-timeout omitted only in admitted-progress mode; parse/source/cleanup use the refreshed budget.
    • Include an exact-runtime PTY canary proving that agy flushes admitted step_update / native_tool_v4 lifecycle frames promptly enough to renew the lease. A provider/tool fixture that buffers structured events beyond the lease must time out rather than be treated as healthy.
  4. Codex/Grok/OpenCode adapters: each active failover accepts the sink on affected read-only actions and uses its existing structured probe; unsupported actions still reject inappropriate sinks.
  5. Negative/mixed-version: old wire/client hash, missing descriptor field, bad FD, EPIPE, probe regression, output limit, cancellation, provider error, teardown error, source change, receipt failure, and cleanup failure all fail closed with exact typed diagnostics.
  6. End-to-end semantic proof: an affected managed request runs longer than its original timeout_ms, emits admitted progress, and succeeds; the same fixture with progress stopped times out without a second provider attempt.
  7. Packaging/release: provider-free source closure, exact packaged-byte qualification, manifest/schema parity, signature/notarization, both supported architectures, clean-root and installed-root canaries, and runtime/client wire identity readback all pass at the exact release head.
  8. No regressions: existing codegen lease behavior remains byte-contract compatible except for the intentional descriptor/schema version advance; context/readiness total deadlines remain unchanged.

Release and rollback

  • Land the workspace runtime source first under normal exact-head governance.
  • Build the signed runtime and update the plugin client/manifest/version mirrors in one plugin release PR. Do not publish a runtime-only or client-only half.
  • Treat this as a next-runtime-release gate; the final version number is chosen by the release owner, not hard-coded here.
  • Rollback is the prior complete signed plugin/runtime pair. Never mix the new client with the prior runtime or vice versa.
  • Activation/restart remains a separately qualified release-owner action.

Acceptance criteria

  • The signed descriptor is the single source of truth for total-deadline vs admitted-progress supervision.
  • review.repository, frontend_review.repository, and governance.repository can exceed the original wall-clock timeout_ms only while admitted structured progress continues.
  • Stopping admitted progress causes one bounded timeout/cleanup and zero replay.
  • Raw provider output cannot keep a request alive.
  • Gemini's --print-timeout and stale post-return absolute deadline cannot defeat the lease.
  • Every active candidate for an affected action supports the same fail-closed contract.
  • Context/readiness and any unmarked action keep their existing fixed total deadline.
  • Exact-head/source-seal/evidence/no-replay invariants remain covered and green.
  • Runtime, public client, manifest/wire mirrors, docs, and version identities ship atomically in the next signed release.
  • Exact packaged bytes pass the full provider-free and semantic qualification matrix before release.

Independent architecture receipt

A managed distinct-family architecture.repository pass inspected 21 paths at the exact clean workspace head and returned REQUEST_CHANGES, correcting the affected-action scope and the missing read-only/Gemini/post-deadline/failover wiring captured above.

  • request: critical-liveness-20260830-01
  • executed edge: 27d627afc4a1d5b4053e44ede59e7d4d2e1301a1eb7f6ad73481a09c99261c2b
  • artifact SHA-256: 52167b695c7eb0dc2b8a140a5e0910d8c0a57cbc1328fabadc5b31dc572b3338
  • evidence SHA-256: f9d8faa4fd09a040ce957b13363e23a569ff69ce1f0b6d410e564a955cdefb64
  • cleanup confirmed: true

Revised-plan review receipt

A separate targeted Gemini review.repository request reviewed the substantive revised implementation plan and issue draft at the same clean exact head. It returned APPROVE with high confidence and no blocking findings. Its only unsupported-assumption callout—the need to prove timely agy structured-event flushing—is now an explicit qualification canary above.

  • request: critical-liveness-revised-20260830-01
  • executed edge: 8de588de1b974b68d6cae3147167eebca79eedbaf700764b58583d99e94de278
  • artifact SHA-256: e0b44b4ce20d2dbaf21628eea1bed9477b7687993931b82a0171a727e2d727c9
  • evidence SHA-256: 9045424c6b60e3b172c64cdd374714102c9d7c57aa6f766f0bebc3e30156e890
  • cleanup confirmed: true

Delivery estimate — implementation_plan

Scope: implementation through the released boundary, including workspace source, all active adapters, exact-head governance, signed runtime packaging, and the paired plugin release; excluding installation, activation, and restart.

  • Focused agent wall-clock P50/P80/P95: 0.46 h / 1.08 h / 1.95 h.
  • Calendar elapsed P50/P80/P95: 2.04 h / 3.04 h / 7.20 h.
  • Calendar wait decomposition P50/P80/P95: vendor/CI/review 0.92 h / 2.25 h / 2.42 h; release-owner gate 0.33 h / 0.67 h / 1.50 h; quota delay 0 h / 0 h / 0 h.
  • Critical path: descriptor contract → adapter/runtime work → regression/semantic qualification → CI → exact-head governance → review wait → signed release.
  • Planned concurrency: 2; actual merge/release/go/no-go remains with the primary/release owner.
  • Confidence: low. The packaged prior is bootstrap/descriptive, falls back eight hierarchy levels to the generic enhancement cohort (580 eligible duration observations; evidence through 2026-08-25), and has no published token, quota-delay, review/rework, or marginal-cash prior.
  • API-equivalent token cost: unavailable_no_token_prior; actual marginal cash: unknown. Official pricing snapshots were current through 2026-08-28 but cannot produce cost quantiles without token evidence.
  • Estimate scope SHA-256: 0c57fa5bdc0ce62a97c06825dcd110c82b4084658b39d644eea9f80d2142660e; prior/pricing/quota SHA-256: 572284e9466ce024f64e202d1bf9bf33be26bf1c54df8c968184756900b22f65 / 95e3ff5f86861080d43a83b6400a487820c5b924cdbef8c9dee1be384c320a6f / 7000a45c88b3b3c4134ff87f7e100e9817bf764db5670ffba41e45221eb3fee6.

This estimate is a planning range, not a release SLA. Reconcile it only after verified completion evidence exists.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions