Repository navigation
Description
Context
Version: t3 0.1.8-nightly.20261106.4275, binary sha256 fa4e92dc049aed9ec6fb09c49a3df982fc67798ef6fc7cb8052bfa0ebf7a9c8b.
We run planned host maintenance in two phases:
- Stop the T3 server.
- Later, start T3 again.
After the restart, no agent turn may begin in a defined set of threads until an operator sends the first message.
Two startup paths can begin turns without a user message:
-
Restart continuations. They are already controllable. The project override
projectSettingsOverrides[projectId].continueThreadsAfterServerUpdate=falsegates both the shutdown/reconcile prepare and the continuation sender at execution time.t3_thread_waitwithuntilDelegatedWorkSettled:truealready exposes running, prepared-continuation and pending-continuation-effect state without consuming anything. -
Delegated-completion delivery. This is the remaining gap.
recoverDelegatedTasks→offerDelegatedCompletionDeliveryoffers a parent turn for every run where all of these hold:delegatedCompletion.disposition === "open";deliveryis non-null with taskIds;- the thread is not archived or deleted;
- the delivery message is absent or is an undelivered mailbox steer.
No supported read exposes this state. No setting suppresses it.
The existing reads do not cover it:
task_statusandt3_thread_readmark results delivered.t3_thread_waitcovers child-sidecompletionDeliverypending/claimedonly.t3 thread showalways performs a message-page read.
Request: one of the following
Option A: read-only query (preferred)
Add a non-consuming deliveryRecovery object for a thread to two surfaces: t3_thread_read (any view) and a CLI form usable from an independent console while the server runs, t3 thread show <id> --json --state-only. --state-only must not read messages.
The object:
deliveryRecovery: {
evaluatedAt, eventSequence, serverVersion,
openDelegatedCompletionOffers: [ // exactly the offerDelegatedCompletionDelivery precondition
{ parentRunId, generation, messageId, taskIds, messageState: "absent"|"undelivered_steer"|"delivered" }
],
childCompletionDeliveries: [ // every subagent/delegated task of this thread
{ taskId, childThreadId, remoteEnvironmentId|null, state: "pending"|"claimed"|"delivered"|"acknowledged"|"disposed"|null }
],
restartContinuation: { // same functions startup uses
enabled, source: "global"|"project"|"policy",
candidateRunId|null, // restartContinuationRun() after restartContinuationBlocked()
pendingEffects: [{ effectId, runId, status }]
},
wouldStartTurnOnRestart: boolean, // OR of the above under current settings
complete: boolean, errors: [] // never silently omit inaccessible/remote/native records
}
Add the CLI listing t3 thread list --all-projects --include-subagents --json. Each row must include worktreePath and parentThreadId, and the output must report pagination completeness. An operator can then build the scoped set without an agent session.
Reads must never change completionDelivery, a cohort disposition or message delivery. This must be documented. The same non-consumption guarantee should be documented for t3_thread_wait.
Option B: startup hold
Add a persisted hold that an operator can set before stop and that survives the restart, for example t3 service hold-recovered-work on. Optional scope: --project <id>. While the hold is on, startup:
- reconciles as today;
- does not claim
provider-runtime.continueeffects (the existingclaimNext({ excludeRestartContinuations })path); - does not call
offerDelegatedCompletionDelivery; - keeps queued runs
queueHeld.
Also add:
t3 service hold-recovered-work status --json, which lists the held offers and continuations by thread and run and reads nothing else;... release [--thread|--project|--all];... discard, which disposes held items explicitly and records it.
Acceptance scenarios
Each scenario is seeded and then followed by a controlled restart, unless it says otherwise.
- Completed parent, child result not yet delivered. Before stop, the query reports a non-empty
openDelegatedCompletionOffersandwouldStartTurnOnRestart=true. Under Option B with hold on, a restart starts zero parent turns. Status lists the offer, and release starts exactly one. - Parent that already consumed its completion. The query reports empty offers and
wouldStartTurnOnRestart=false. A restart starts zero turns. - Idempotent reads. Calling the query, CLI
--state-onlyort3_thread_wait(untilDelegatedWorkSettled)10 times leaves delivery states, disposition and event sequence unchanged (no delivery events emitted). A later normal delivery still happens. - Cross-project. Parent and child are in different projects, and one child is in a linked remote environment. Both appear, or
complete=falsewith an error is returned. No silent omission. - Restart continuation. A running thread with a live turn, plus a completed run with open awaited background work, both report a
candidateRunIdwhile continuation is enabled. With the project override false,enabled=falseand a restart starts zero continuation turns. - Prepared continuation. After a graceful stop with continuation enabled, the query is evaluated against the persisted state at next start (Option B status). It lists the prepared continuation without running it.
- Queue. Queued runs remain
queueHeldand are reported. No queued turn starts before release. - Independent console. Every scenario above can be evaluated by the CLI with no agent session running.
Non-goals
- No requirement that unrelated projects be idle.
- No direct database access, internal RPC or undocumented flags for operators.
- This is unrelated to agent-harness publication replay (agent-harness#1849).
Activity