The harness contract: six clauses the bot holds any model-loop process to, pi as its one implementation
Record 0038 decided that a harness — a process that runs the model loop for one run, in the container the run's machine class provides — is held to six things and nothing else: it starts with the run's bearer and never a provider key (credential); every tool call it runs is decided by the bot (gate); Switchboard's tools are served to it and run by the bot (relay); every event it emits has a home on the run's record (record); it is driven as a seed, steers and prompts and is ended (conversation); and it leaves facts on the run's row so the bot, in this generation or the next, finds its process or rebuilds it from the record (survival). The seam is one interface, Harness (src/core/harness/contract.ts), and the run loop is handed an object of it and calls it — never a word it compares. pi is the one implementation (harness-pi.md holds pi's rows: the mechanics of each clause as pi meets them); a second harness enters as a conformance row before it enters an image.
- Code:
src/core/harness/contract.ts(Harness,HarnessRun,HarnessDeps,HarnessSession,FollowUpTurn,HarnessResume,HarnessFactswithPiHarnessFactsandOpenCodeHarnessFacts,harnessFactsOf,isPiFacts,factsBelongTo,Finding,HarnessInterruptedError,HarnessMismatchError,HarnessContainerReplacedErrorandHarnessRecord,RELAUNCH_CEILING,HarnessResume.relaunch,openThroughSeam,Disposition),src/core/harness/pi/piHarness.ts(PiHarness: pi as the contract's object),src/core/harness/container.ts(HarnessContainer,saysTransportLost,saysContainerDown,CONTAINER_DOWN_WORDING,HarnessContainerDownError,ProbeWait,PROBE_WAIT_MAX_MS,PROBE_WAIT_BACKOFF_MS,HarnessPaths,HarnessStart,HarnessStarted,HarnessRequest,HarnessResponse,PORT_ARG,HARNESS_PORT_ENV,ExecHarnessContainerand its scripts,startScript,requestScript,parseHttpResponse,isContainerGone,HarnessContainerError,HarnessContainerRuntimeReplacedError: the container seam, item 9;replacedVerdict,ReplacedVerdictandReplacedCondition,identityChangedCondition,replacedBecause: the one more command before the crash judgement, item 6),src/core/harness/botHostContainer.ts(BotHostHarnessContainer,harnessContainerFor),src/core/harness/testing/fakeContainer.ts(the in-memory container the tests drive),src/core/harness/pi/process.ts(PiRunPathsas pi's layout overHarnessPaths,PI_BIN,PI_STDOUT_FILTER),src/core/harness/pi/harness.ts(runPiHarnessOpen, the loop behindPiHarness.open;locatePi, the steps behind itsfind),src/core/harness/pi/bridge.ts(PI_EVENT_DISPOSITION, pi's table for the record clause),src/core/dispatch/run.ts(HarnessProcessDeps.harnesses: the roster the process drives runs with),src/core/dispatch/runLoop.ts(the loop picks the object off the roster — the row's word for a resume, the preset's configuration word for a fresh run — callsopen,findandendon it, reads the row's facts throughharnessFactsOf, and relaunches throughprepareRelaunchon the typed replaced-container verdict),src/core/dispatch/relaunch.ts(prepareRelaunch,RelaunchRefusedError,RelaunchDecision,RelaunchContext: the ceiling's steps, item 6),src/core/dispatch/provision.tsandsrc/core/runEvents.ts(run_meta.harness),src/core/dispatcher.ts(the restart from the request after a mismatch),src/core/harness/names.ts(wire name vocabulary),src/core/harness/roster.ts(HARNESS_NAMES,DEFAULT_HARNESS,HarnessRoster,isHarnessName,harnessForPreset,harnessNamed: the roster's words and the pick, item 8),src/core/harness/scope.ts(HARNESS_SCOPES,HarnessScope,isHarnessScope: the scopes a word is set at, in a module with no imports so the run record and the timeline fold can carry the scope into the Workers' and the dashboard's programs without the harness objects following; re-exported by the roster, item 8),src/config.ts(AppConfig.harness,Scope.harness,ResolvedHarness,ResolvedRequest.harness,AppConfig.opencode,OpenCodeConfig: the word per preset through the scopes and OpenCode's block) andsrc/config/validate.ts(validateHarnessWords,validateOpenCode: every layer's words validated against the roster's, OpenCode's block against its own, item 8),src/index.tsandsrc/cli.ts(the roster wired:PiHarnessandOpenCodeHarness, each with the deployment's compaction thresholds),src/channels/modelProxy.ts(PROXY_PATHS: the three dialects the proxy serves, the roster a harness's credential clause draws on),src/core/harness/opencode/process.ts(OpenCodeRunPathsandopenCodeRunPaths,openCodeLaunchEnv,openCodePermissionRules,openCodeConfig,launchOpenCode,OpenCodeNotReadyError,openCodeFacts: the OpenCode process, item 12),src/core/harness/opencode/tailerSource.ts(OPENCODE_TAILER_SOURCE: the tailer as text),src/core/harness/opencode/client.ts(OPENCODE_ROUTES,openCodeSessionRoutes,OpenCodeFeedRecord,parseMessagesPage,parsePermissionList,readSessionStoreandreadStoreSincewithSTORE_PAGE_LIMITandSTORE_PAGES,parseAnswerId: the routes and shapes derived from the pinned protocol, the parsers a re-attach reads the store and the pending asks with, and the store read whole page by page),src/core/harness/opencode/dispositions.ts(OPENCODE_EVENT_DISPOSITION: OpenCode's table for the record clause, the record clause item 4),src/core/harness/opencode/bridge.ts(OpenCodeBridgewithadoptStoreandobserving(own | earlier | catching-up),driveOpenCode,OpenCodeConnectionwithsaveOffset,reattach,knownMessageIdsandposted,OpenCodeReattach,OpenCodeWriteUnresolvedError,ledgerTurnCount,judgeOpenCodeAsk,OpenCodeGateBypassedError,OpenCodeReplyFailedError,OpenCodeRequestRefusedError,OpenCodeSilentError,FIRST_EVENT_BOUND_MS,executionStartedFor,OpenCodeConnection.postTurn,openCodeToolNameWord: the gate and the record over the feed, items 2 and 4; the store joined by message id and the re-attach's catch-up, item 13; the answer to every request read, the first-event bound lifted by the session's own execution start, the soft stop and the finale bound, items 5 and 13),src/core/harness/windDown.ts(CONTINUE_PROMPT: the continue every resumed process is prompted with, on either harness;finaleTimedOutNote,finaleAbortReason: the finale bound's card line and the failed call's words when the bound itself ended the write-up, item 5),src/core/harness/opencode/pluginSource.ts(openCodePluginSource: the relay plugin as text — the run's launch declarations registered as direct tools, each callPOST /harness/authorizethenPOST /harness/toolwith the model's call id, the relay clause),src/core/harness/opencode/session.ts(openCodeImportBody,openCodeStoreMessages,openCodeSeedAndRequest,openCodeSessionId,openCodeSettlementNote: the seed and the rebuild as an authored-session import, the conversation and survival clauses),src/core/harness/opencode/harness.ts(OpenCodeHarness: OpenCode as the contract's object —openthe run overlaunchOpenCode, the seed import, the relay registration, the follow-up drain anddriveOpenCode, and on a resume the re-attach onto the row's still-answering server or a refusal that retains original custody without a fresh start,find/endover the recorded port and root,resumeOpenCodeFacts),src/core/harness/opencode/testing/driver.ts(openCodeDriver,MutatedClause,ReattachOptions,FakeServeOptions,TAILER_READY_NOTES,feedByteLength: OpenCode's conformance driver over a fakeservedriving the realOpenCodeHarness, the full table, the mutation switches, the faults a serve can be told to commit (a refused prime or prompt, a silent prompt), the model reference resolved when an execution starts as the real server resolves it, and the row's recorded server a re-attach is driven against;scriptOpenCodeServe,ScriptOpenCodeServeOptions,ScriptedOpenCode: the same serve bound to a bare container for a run the run loop opens, item 8),src/core/harness/pi/toolRules.ts(openCodeToolWord: OpenCode's actions in pi's tool words);src/core/harness/sessionPolicy.ts(OriginalSessionPolicy,originalSessionPolicyOf,sameOriginalSessionPolicy);src/core/harness/nativeMedia.ts,src/core/harness/opencode/media.ts - Tests:
src/core/harness/launchTools.test.ts,src/core/harness/contract.test.ts,src/core/harness/roster.test.ts,src/config.test.ts,src/core/harness/container.test.ts,src/core/harness/botHostContainer.test.ts,src/core/harness/pi/transport.test.ts,src/core/harness/pi/process.test.ts,src/core/harness/oneHarness.test.ts,src/core/dispatch/runLoop.test.ts,src/core/dispatch/relaunch.test.ts,src/core/dispatch/provision.test.ts,src/core/dispatcher.test.ts,src/channels/modelProxy.test.ts,src/core/harness/pi/harness.test.ts,src/core/harness/pi/relay.test.ts,src/core/harness/pi/bridge.test.ts,src/core/harness/pi/mirror.test.ts,src/core/harness/opencode/process.test.ts,src/core/harness/opencode/tailer.test.ts,src/core/harness/opencode/client.test.ts,src/core/harness/opencode/bridge.test.ts,src/core/harness/opencode/pluginSource.test.ts,src/core/harness/opencode/session.test.ts,src/core/harness/opencode/harness.test.ts,src/core/harness/opencode/testing/realDriver.test.ts,src/core/harness/conformance.test.ts,src/deploy/imageOpenCodeHarness.test.ts;src/core/harness/sessionPolicy.test.ts;src/core/harness/opencode/media.test.ts - Docs: record 0038 (the contract, the second harness's row, the stage gates), harness-pi.md (pi's rows), model-proxy.md (the bearer and the three dialects), run-history.md (the ledger the record clause writes to), configuration.md (the
harnessandopencodeblocks), How-to: put a preset on OpenCode (the configuration word in use)
Behavior
Credential. A harness starts with the run's bearer and the proxy's URL as its only way to a model, revealed once into its process's environment and never a provider key, a command line or a file; every model call it makes goes through the model proxy, which pins the model and the caps and meters the turn on the run's page (model-proxy.md). A failed model call is recorded as a typed terminal result: proven provider failure or refusal, pi-local cancellation, or unknown. Only proven provider failures carry a
ProviderFailure.cause; the harness uses the typed result and a safe rendered sentence, never provider prose or payload. The proxy serves exactly three wire dialects — Anthropic messages, OpenAI chat completions and OpenAI Responses (PROXY_PATHS) — and refuses any other path by name before a byte is forwarded; a harness whose model library speaks a fourth dialect is a change to record 0038, never a quiet route. pi's row: harness-pi.md item 4 (the environment as the channel for the bearer,models.jsonnaming the proxy as the one provider).Gate. The gate decides intent; the walls enforce effects. Every tool call a harness runs is decided by the bot, before it runs when it runs in the container and at execution when it runs in the bot: a relayed tool is allowed by name at the ask because the bot's own gates decide it when it runs; the harness's own shell and file tools are judged by
judgeToolCallwith the run's identity and the thread's rules, each decisionacceptordeclineand never cached outside the bot, a refusal atool_refusednote the model reads the reason of. A call the record shows ran with no decision beside it fails the run closed, and so does a call whose decision was a reply the bot did not send (on a harness whose approval lives in its own server the model's shell can forge one, so the gate there is enforcement by detection and the forgery is the harness's honest cannot on its conformance row); a call the harness itself refused before running is aharness_errornote, not a bypass. A gate reply the harness's server answers 404 is read against the server's own pending asks (the one idempotent read), never as the reply failing outright: the ask gone, the server withdrew it before the reply reached it — on OpenCode arejectdeclines every other ask the session has pending (the reject cascade, originally traced inpackages/core/src/permission.ts:203-220at v2.0.3, with apermission.repliedrejectpublished for each; the current runtime pin is item 12's), the sibling's call failingpermission.rejectedwithout running. Against the real 2.0.24 binary, the server continues the model with both refusals and succeeds in the original execution, so the harness starts no second execution and emits nodecline_cascade. If a cascade instead ends the executioninterrupted, the harness queues a prompt carrying the refusal only when it did not cut the execution and is not already winding down. The withdrawn ask gets oneask_withdrawnnote naming the call, the reply the gate had decided and the same step's refusal, the loop not stopped, the step ending by the server's word; the server's ownrejectecho for the withdrawn ask is the cascade's and no forgery only when the bot's own refusal of another call of the same step is on the record as its cause — with no such refusal the withdrawal is still no fatal reply (the note says no refusal of the step is on the record) but the echo is judged as any reply is, arejectagainst a decidedoncethe gate bypassed, fail closed; the ask still pending, the reply genuinely failed and the run stops fail closed (OpenCodeReplyFailedError) as for any reply that did not land, and a pending-asks listing that cannot be read fails it the same way. What the gate decides is the call; what bounds the effects of an approved call is not the gate: an approved shell command runs as the container user with everything the container holds, so the walls are the container, the proxy holding the credentials, the token's scope and branch protection. The read identity's walls exist (a read-only worktree and no write token; the gate's read rules restate them); the write identity's one-push-target rule and the harness process's own secrets are held by rules alone, the two gap rows below. pi's row: harness-pi.md item 7 (the extension's hook, the coverage check from the stream,GateBypassed). The 2.0.24 permission reply request carries{ decision: "once" | "reject", message? }; thepermission.repliedevent still carriesreply, so the request’s field and the gate’s echo are distinct.Relay. Switchboard's tools — the preset's toolset less the workspace tools the harness has of its own — are served to the harness by the bot, registered under their own names, and run in the bot under the run's context and the bot's own gates; a call may outlive one request and is joined, never run twice, by its call id; a call in flight when the previous bot generation died is settled from the record. pi's row: harness-pi.md item 7 (the three harness routes,
RelayedCalls).Record. Every event kind a harness emits has a disposition onto the run stream —
mapped,structure,folded,impossibleornote(Disposition; a harness's table is itsdispositionsproperty) — in the vocabulary the record already speaks (tool_call,tool_result,assistant,run_note), and its finished turns are mirrored into the ledger's step records so a resume reads its rows as it reads any run's; a kind the table does not name is aharness_errornote naming it, so a harness bump shows in the first run's record, and a kind markedimpossiblethat arrives all the same is one too; either note is said once per kind for the run — the first arrival is the finding, the note ends(said once: later events of this kind are not noted), and later arrivals of that kind write nothing — so one wrong table entry is one line on the record, never one per event. OpenCode'slocation.shutdown(the location's cached services shut down),provider.updatedandmodel.updated(catalogue changes), andsession.permissions(the session's permission rules) arestructure, not unknown kinds or session endings; the bridge neither settles nor emits a failure for them. The 2.0.24 manifest no longer namescatalog.updatedorsession.permissions.updated. pi's row: harness-pi.md items 5 and 8 (PI_EVENT_DISPOSITION, the bridge, the mirror).Conversation. A harness is driven as a seed (the thread's earlier turns, then the request as the prompt), steers (a follow-up, the wrap-up warning, the forced write-up, a soft stop), prompts (the post-turns on the same session: the description turn, the verdict turn, the head-move re-review), and a hard stop that ends it; the budgets and the wind-downs are the loop's words on every harness — every harness hands the run loop the ending that labelled its answer (
HarnessSession.ending, aWindDownEnding), so the thread's answer is composed once the loop's post-steps have established what the tree held and where it went, never by the harness's guess (harness-pi.md item 6, the conformance rowsbudget-ending-*) — and the wind-down owns the ending on every harness: a model call that fails once the run is winding down is aharness_errornote, never the run's failure — the finale bound's own end of what was in flight included, the note worded for what that was: a model call (pi's shape; on OpenCode the write-up's own call hanging) is a model call that failed under the wind-down, while on OpenCode a tool call the bound fell on — the loop-end cut's tool with its interrupt still unanswered, or a tool the write-up's own execution made — is the wait the bound ended, no model call having failed (finaleWaitNote, naming the open tools and the unanswered interrupt) — and the run closes with the wind-down's answer, which names the failed call (or wait on a tool) where the write-up would have been —windDownFailureNotefor a model call,finaleWaitNote's wording for a tool wait — in thewriteUpFailedclause oftimeBudgetAnswer,turnGuardAnswerandsoftStopAnswer(distinguished bywriteUpFailedOnToolon theWindDownEnding) insrc/core/harness/windDown.ts; the budget note says what the run was at when the clock ran out — the open tool calls by name, the model call under way, or the budget alone (doingNowon each bridge,MODEL_CALL_IN_FLIGHT). An operator's soft stop is honoured on every harness: the write-up steered (SOFT_STOP_INSTRUCTION) under astoppednote in modesoft, every tool refused meanwhile, the answer under the ⏹ label (softStopAnswer). The write-up is bounded on every harness (loopClock.finaleMs, thewriteUpallowance ofsrc/core/budgets.ts, three minutes): past the bound the harness aborts the call in flight (pi'sabort, OpenCode'sinterrupt), says so on the card (finaleTimedOutNote) and closes by the wind-down's answer without waiting on a settle the aborted turn may never send — the process ended by the caller as after any loop — so a model call that never answers ends within the finale bound whatever the wind-down was, never as a failed run and never as a replaced container; where the abort itself is why no write-up came and the harness cannot read the aborted call's own words,finaleAbortReasonstands in as the failed call's words on theharness_errornote and in the answer'swriteUpFailedclause. Switchboard's effort tier reaches it in the harness's own word (Harness.effort). pi's row: harness-pi.md items 6, 9, 14 and 15.Survival. A harness leaves facts on the run's row (
HarnessFacts,state.harness) — the process, where it was filed, the container it runs in, the bearer's hash, and the count of its relaunches — so the bot that comes back, in this generation or the next, asks the harness where that process is (find) before anything is probed or ended, continues it where verified and retains its original custody when location or liveness is uncertain; rebuilding from the record uses the explicit replacement protocol: anauthored-sessionharness (Harness.history; pi) accepts the ledger's transcript as its own history, so a rebuild is a rewrite of it; anown-storeharness has only its private store, so a store that is gone closes the runinterruptedand its request runs again; either rebuild reads the record, never the dead process. The ceiling. A container replaced under a living bot — the harness's typed verdict,HarnessContainerReplacedError, carrying the record as the harness holds it (HarnessRecord: the transcript it mirrored onto the ledger, this generation's copy of the rows a bot death reads back; every call of the last turn settled; the counters; the deadline) — relaunches the process from that record in the container the run holds (prepareRelaunch,src/core/dispatch/relaunch.ts, called by the run loop on the typed verdict; harness-neutral, the rebuild itself the harness's ownopenwith the record as its resume andHarnessResume.relaunchset). In order: the bound read off the row'srelaunches(RELAUNCH_CEILING, two — the third finding closes the runinterruptednaming the bound, no fourth start; the count is written by the loop and carried unchanged by the harness, so it survives a bot generation); the workspace re-attached where the row says it is or refused by name (reattachWorkspace, run-history.md item 54, the executor the run holds from then on); the bearer rotated on the run's own meter with the row's facts written exactly once inside the rotation — the new hash, the count one higher (model-proxy.md item 2); then the harness's rebuild — the run's relay registration taken over with its relayed calls kept and awaited, nothing probed or ended at the row's pid, the process started on the record, oneresumednote. Outside a stamped pilot coding run, a refusal by name — the ceiling, an ordinary lost worktree, a bearer that cannot be rotated, a row without facts, anown-storeharness whose store went with the container — is an interruption like the floor's (RelaunchRefusedError): the loop forgets the run on the relay, says why in a secondsandbox_restartednote after the harness's verdict (the floor's own kind; neverresumed, since the run is not — the note starts at the why and does not restate the verdict), and closes the runinterruptedfor the dispatcher's restart from the request, the refusalworkspace_lostfor the worktree andcontainer_replacedotherwise; a row write that throws inside the rotation fails the run with nothing relaunched and both secrets verifying. A stamped pilot coding run pauses on a named relaunch refusal, including the ceiling, an unavailable harness store, missing facts, a lost worktree or bearer rotation failure; it hands off the same ledger row and binding with no finish, release or request restart for operator recovery. The record across two deaths. A process rebuilt from the record — after a bot death or a relaunch — starts on a session whose last turn settles every call that was in flight; that settlement turn is written onto the ledger too, as the results pending for the rebuilt process's first step (pi:PiMirror.prime; the write-through's own convention, the results since the last assistant turn are the next step's one user turn), so the ledger's next rows are[user(settlements + the continue's echo), assistant]from the seed index, the ledger's rows equal the session's and the harness's record of them, and a supported explicit replacement or compatible in-place continuation preserves a result for everytool_use. The two-deaths test'ssettlementResultsview after an unverified third-container resume is only a protocol projection: that producer remains held; the view was not handed to a restarted model. Native restoration in that unverified third container is retired as an acceptance criterion, pending independent supported proof. The conformance rowsurvival-rebuild-records-settlementholds every harness to it. The first gate (the plan's execution note, the mid-run re-attach) passed in the fakes: the seam composes — a recorded binding re-attaches mid-run with no gate context and a process starts again in a replacement container from the ledger's rows. What the fakes cannot prove is the resident: areuse: truere-attach onto a container the platform just rolled is proven only by the live row (harness-pi.md16, live), owed before stage A closes. The floor beneath the ceiling is harness-pi.md item 16 (the verdict and the settle-and-close), pi's relaunch harness-pi.md item 8; OpenCode's ceiling is its own:driveOpenCode's container-gone read (saysContainerReplacedon the feed) throws the same typed verdict carrying the record built from its mirrored rows, nothing killed or removed in the container that answers now, and its rebuild is an import of that record — and a resume naming the container this run holds re-attaches onto the row's still-answering server (its password the row'sbearerHash, the tailer kept or restarted over the same feed, the feed read from thelogOffset, the pending asks decided through the gate; item 13), retaining the original server, tailer, root and session whenever authentication, version, session/store, pending asks, feed collection or bearer adoption prevents continuation. Missing, incomplete or truncated original collection, foreign placement or unavailable current identity likewise raises typed unconfirmed custody before cleanup, replacement or new facts. Compatible same-container continuation and permitted legacy unbound placement remain supported observations, not physical custody proof; only the distinct explicit typed replacement protocol authorizes reconstruction from the transcript, settlements and compactions. One more command before the crash judgement. The floor's condition is the executor's word on a failing container command, and the platform's rollout has a window that misses it: the container's processes are killed first whileexecstill answers, so the alive probe finds the process gone before any command has failed with the word, and a harness that judged by the word alone read the process's own death where the container had in fact been replaced. So a process found dead WITHOUT the word — pi's loop once its transport ends unsettled,driveOpenCodeonce the feed ends — takes exactly one more container command,identity, before it judges (replacedVerdict, the container seam): that command failing with the word is the executor's word, and the verdict is replaced as it would have been had the word come on the read (saidthe word,conditiontaggedword); that command answering another word for the container than the one recorded when the process started is the verdict too, by the changed identity — a renamed container with a dead process is a replaced one; the boot id corroborates wherever the word can come and decides only here, where none can — withconditiontaggedidentity,saidnothing, and thesandbox_restartednote sayingidentityChangedCondition()'s sentence,the changed identity was the condition: …, in the executor's words' place; anything else — the same word, no word on either side, a command that failed for another reason — leaves the crash judgement standing, the failure it always was, with nothing named by the container. The condition is a tag (ReplacedCondition,word | identity) every verdict carries, so a reader of the error or of the record compares it and never parses a sentence, andsaidis present exactly when the tag isword— the invariant the class refuses at construction. The conformance rowssurvival-dead-without-word-then-word,survival-dead-without-word-then-renamedandsurvival-dead-without-word-then-samehold every harness to all three, the last the negative half: a wordless death in the same container is not a replacement. The third failure shape: a command that fails on its transport with no word. The platform's replacement has a second window the word misses: it kills the container under the process's command, and the read's transport dies with it — the resident client'sresident /exec: Peer closed WebSocket: 1006 WebSocket disconnected without sending Close frame., the binding'sThe container is not running, consider calling start(), a connection reset — before any word can come, so a harness that judged that a plain failure lost the run where the container had in fact been replaced. A container command that fails so (saysTransportLost, the container seam) takes the same one more command (replacedVerdict), and the shape is decided by the EXECUTOR'S TYPED WORD first, exactly as the one more command itself decides: anExecInfraError— on the error or anywhere in its cause chain (infraErrorOf,selfAndCauses; the seam rethrows the executor's throw as it is, so the type is never lost at the boundary) — whose reason a wait can clear (infraMayClear: the transport lost, the deadline passed, the empty failure shape, the Worker unavailable; execution.md item 9's waitable set, which is what the one more command waits on) is the shape whatever its words — the plan owner's live run metresident /exec: Network connection lost.typedtransport-lostat a rollout's onset and was failed at once for want of this — while a typed refusal or the run's own stop is never the shape whatever its words; only anansweredfailure, whose meaning is in the resident's words, and an untyped one are read by the words: the container's transport or the container down (CONTAINER_DOWN_WORDING: the 1006 close, the SDK's ownNetwork connection lost.— @cloudflare/containers' sentence for the Durable Object's connection to its container dropping — the not-running refusal, a connection reset) or the seam's typed down answer; never the word, never a control file lost, never a command that failed as a command — and the same three answers decide: the word on it, or a changed identity, is the replaced verdict as above — the condition taggedwordoridentity, thesandbox_restartednote, the record, nothing killed or removed, the relaunch from the record; the recorded identity leaves the failure standing, NAMED as the transport error it was (the run fails with that error, aharness_errornote saying the one more command named no replacement), never a crash judgement of the harness's own. The one more command survives the restore window. After the platform's replacement the resident rebuilt its container in about a minute, and until then the one more command itself answers that the container is not running: that answer is a wait, never the judgement.identitythrows it asHarnessContainerDownError, deciding by the type first and by the words only where no type decides: a typed infra failure (ExecInfraError.reason, execution.md item 9) whose reason a wait can clear (infraMayClear: the transport lost, the deadline passed, the empty failure shape, the Worker unavailable — the resident's 5xx in the restore window among them; the executors' real failures in the deploy window, typed where they are built and never matched by their prose here) is the down answer; a typed refusal (an evicted worktree that needs an attach, the deploy-storm streak guard, a 4xx, the resident client's strike on a definite engine view —down,onboarding, a Worker that did not answer — whose words may still say the container just exited) or the run's own stop (aborted) is no name whatever its words, so the command judges at once; the resident's restore window is ONE wait of this bound whatever route the resident answered it by — the hydrate path'srestore in progress503 and the wake path's strike after the client's own shorter budget ran out on a still-restoring resident are both typed unavailable (execution.md item 9:residentAnswerReasonandresidentWakeStrikeread the oneisWakeabledecision), so neither route gives up at the client's 60 s where the other waits five minutes; anansweredfailure, whose meaning is in the resident's words, and an untyped failure are read by the container's own words (saysContainerDown) — the down answer when they are the container's, no name when they are not (anot-serviceablerefusal on a status that is not a 5xx among them) — while outside that command such a failure names nothing (identityOrNothing, what a launch andfindread the row's word through) — andreplacedVerdictre-sends the command after the executor's own backoff (PROBE_WAIT_BACKOFF_MS, 5 s, 10 s, then 15 s) until the container answers — the word, a changed identity or the same word then decide as ever — or the wait reaches the executor's own bound on a container's start (PROBE_WAIT_MAX_MS, five minutes) and runs out, deciding nothing; both constants are the start gate's (execution.md item 23), the same rule: a starting container is a wait the executor re-sends through, not a verdict. The bound is wall-clock time from the wait's start, read on the harness's own clock between re-sends (ProbeWait.now; no clock of the seam's), so a command that itself hangs to its timeout is counted and one such command may overshoot the bound by at most its own timeout, never by the count of attempts. The wait observes the run: its hard-stop signal (RunControl.hardSignal,ProbeWait.signal) ends the wait at once, in the middle of a pause, and the run's deadline (ProbeWait.deadline) ends it before a re-send that would pass it — each said in the note, neither a verdict, and the run then ends as the stop or the failure it was. The harness's own sleep drives the wait — a sleep that rejects rejects the wait with its failure, never a wait that hangs with the rejection unhandled — and the record says the wait began and how long the container took to answer, or why it ended. The conformance rowssurvival-transport-lost-then-word,survival-transport-lost-then-renamed,survival-transport-lost-then-same,survival-transport-lost-down-then-sameandsurvival-transport-lost-wait-stoppedhold every harness to all five. The word never outranks a live process, and a control reset is not the word. Before any relaunch on the executor's replaced word, the harness takes onealive(pid)for the row's process in the container the run holds: the identity is the kernel's boot id, which a same-kernel replacement keeps, so only the process refutes the word — alive here, the run re-attaches in place withrelaunchesuntouched and aresumednote recording the disagreement; gone, the verdict stands. And the resident's own Durable Object resetting under a live process — a Worker-code deploy, distinct from a replaced container — answers its own word,control-reset, the container and the process unchanged: never the verdict, the executor re-sending an idempotent op once and never a write, the loop re-attaching in place and resolving the write by the harness's echo (a prompt awaits its echo before any re-send, the gate reply and an abort re-sent as they were, only a write with no echo failing the run by name). Both these responses — the alive-guard and the control-reset re-attach — are one shared module the two harnesses drive (src/core/harness/reattach.ts), so the rule lands in pi and OpenCode alike — and in pi's follow-up turns, which take the same two answers as its loop — and past the bound on re-attaches with no record between them the run fails by name on both, whichever word it met (a control plane that keeps resetting, or a replaced word that keeps coming while the pid still answers — never turned into the verdict, a relaunch beside a live process), rather than riding the bound to the deadline; a write the reset leaves unknown is resolved by pi's echo on pi and by the server's own state on OpenCode (item 13), never re-sent blind on either. The conformance rowsurvival-replaced-word-with-pi-aliveholds every harness to the alive-guard; the harness-specific mechanics are harness-pi.md item 16 and the resident's word resident-repos.md item 43.The seam: an object handed in, never a word compared. The process wires its harnesses into
HarnessProcessDeps.harnesses, the roster of item 8 (src/index.ts,src/cli.ts:PiHarnesswith the deployment'spi.compactionthresholds andOpenCodeHarnesswith itsopencode.compactionthresholds, each behind its own object as its own settings, so every harness is handed the sameHarnessDeps), and the run loop picks one and calls it through the seam's door,openThroughSeam(harness, deps, run), for every run, the answer handed back with the process alive on its session (HarnessSession:answer,followUp,end) for the post-turns; on afinishplan,find(facts, container)and thenend(facts, container)for the leftover process. The loop names no harness and compares no word — the source scan of harness-pi.md item 1 forbidsrunPiHarnessOpenin the run stage as it forbids the deleted loop. The object declares itsname(the roster key and the discriminator of the facts it writes), itshistoryword, itsdispositionstable, itseffortmap and thebuiltinToolsa run of each identity holds. The row's facts are read by the harness that wrote them.HarnessFactsis a union keyed onharness: pi's{ harness: "pi", pid, logOffset, sessionFile?, root?, bearerHash?, container?, relaunches }and the second harness's{ harness: "opencode", pid, port, logOffset, sessionID, root, bearerHash?, container?, relaunches }— the feed's byte boundary as pi's log has one, the bearer's hash and the container optional as on pi's row (a bot-host container has no word, and a bearer without a secret no hash), a shape nothing in the tree writes yet, carried so the seam is read against two shapes.harnessFactsOfreads a row by the shape itsharnessnames, a row without the key as pi's (the one harness that ever wrote one), each shape's known fields by type with a field of the wrong type dropped,relaunchesas 0 when absent or malformed, and keeps every key it does not know, so a field a later build writes survives this build's rewrite of the row; a row missing a shape's required fields, or naming a harness this build does not know, is no facts.findanswers one of four words:alive-here(the process answers in the container the run was handed), foreign placement or sampled absence (original custody is unconfirmed, so no ending or fresh start is authorized),another-harness(the facts were written by a harness other than the one asked, answered with no container command). Afinishplan on unconfirmed original custody retains the workspace; another-harness disowning ends nothing and says so in aresumednote (the another-container note names both words, the row's and the container this run was handed; the another-harness note names the row's word and the judge that disowned it). The loop picks a resumed row's harness by the row's own word (item 8), so it never hands the door a foreign row; the seam's door (openThroughSeam, what the run loop and every conformance driver open a run through) keeps the refusal as its defence for any other caller: another harness's facts are refused before the harness is asked anything (factsBelongTo, the seam's one comparison of a row's harness with the object's name) — aharness_errornote on the record, thenHarnessMismatchErrornaming both harnesses; pi'sopenkeeps the same check as a defence for a caller that is not the seam — and the loop reads such an interruption exactly as it reads a replaced container: every interruption is aHarnessInterruptedErrorcarrying the card's reason and the request's refusal token, so the loop and the dispatcher name no harness's own error class; the run closesinterrupted, its card closes🔁 … the row's harness facts are <found>'s, not <expected>'s; restarting from the request, never❌, the workspace is released, and the dispatcher runs the request again again under the same run id with the refusalharness_mismatch. The relaunch count is the loop's: a harness writes 0 on a fresh run and carries the row's count unchanged through every save and every restart of its process within the run.The roster and the configuration word: one roster, one word, and the row's word wins. The process wires every harness it can drive a run on into one roster (
HarnessRoster,src/core/harness/roster.ts, built insrc/index.tsandsrc/cli.tsand nowhere else — the source scan of harness-pi.md item 1 forbids a harness word or class in the agent registry and a harness class in the run stage), keyed by the name each object declares (Harness.name), and that name IS the configuration word:harness: { <preset>: pi | opencode }puts a preset's fresh runs on the object of that name. The word is a scope setting (routing-and-config.md items 2 and 5): the deployment's top-levelharness:block inconfig.yamlis the defaults layer under its one spelling (defaults.harnessis refused by name pointing at it), andchannels.<id>.harness/users.<id>.harness— static, or written at run time byconfig set channel|me --harness.<preset> pi|opencodeinto the overrides document — override it for the runs requested in that scope, user > channel > defaults per preset, with no request directive (the front door never writes from prose) and no thread stickiness;resolve()hands the loop the word and the scope it came from (ResolvedRequest.harness = { name, scope },HARNESS_SCOPES), and nothing in the resolution is OpenCode's — a third harness would ride the same ladder by its name alone. A person's word moves every run of that preset they request, in any channel — the coding children a ship run spawns for them included — and nobody else's. The roster's words are one list (HARNESS_NAMES, held by type to the facts' discriminator, so a facts shape without a word or a word without a shape fails to build), read in three places and spelt in none of them. The validator (validateHarnessWords) reads them in every layer — the top-level block, each channel's and each user's map, inconfig.yamland in a hand-edited or stored overrides document alike — and the chat command holds the same words by schema on write: a mapping of registered presets to those words loads; a preset the registry does not know fails by name; a value that is not a roster word —codex,native(the loop that no longer exists), a case slip, a non-string — fails naming the path and the words that exist (harness.coding: codex is not a harness; the harnesses are pi and opencode,users.slack:UBAD.harness.coding: codex is not a harness; …); a non-mapping fails as<path> must be a mapping of preset to a harness name (pi or opencode). The loop's pick for a fresh run (harnessNamedoverresolved.harness): the word the scopes resolved, elseDEFAULT_HARNESS, pi — nothing defaults to OpenCode, and production configuration names no preset. A resumed row's judge: a row that carries facts is judged (find), ended (end) and resumed (openwith the facts) by the harness its facts name, picked off the roster, whatever the scopes' word says now — a preset flipped between generations, or a person who moved their own runs mid-flight, never mismatches a run in flight; a run keeps the harness it started on: the row's word wins. A row naming a harness this build does not know (a rollback under a newer build's row, a harness removed) is no facts (item 7), so the preset's harness rebuilds the run from the record — the survival clause working — and the record says so: item 7's rule for a process that is not this one's to judge is "named, not ended", so before the rebuild (or before a finish runs its post-steps) oneresumednote readsthe row names the <word> harness, which this build does not know; its process (pid N in container C) was neither judged nor ended here; the run was rebuilt on <harness>, the pid and containerunknownwhen the row did not record them.run_meta.harness(item 10) is the scopes' pick for the fresh run it announces,run_meta.harnessScopewhose word it was. Each harness's deployment settings ride behind its own object from its own block —pi.compactionintoPiHarness,opencode.compaction(bufferandkeepTokens, OpenCode's own words, positive integers in tokens;validateOpenCoderefuses any other shape or key by name, pi's words included) intoOpenCodeHarness— so the loop carries nothing harness-specific.config/config.example.yamldocuments theharnessblock with both words, a user scope'sharnessand theopencodeblock, commented out; put a preset on OpenCode is the how-to, a person's own runs its first path. The word's precondition is proven at the loop: before any preset's word may beopencode, the survival clause's ceiling (item 6) holds end to end on OpenCode through the run loop —harness: { coding: opencode }opens a coding run on the roster's OpenCode over the fakeserve(scriptOpenCodeServe: the conformance driver's serve bound to a bare container, learning the run at its first request from the launch's environment, the relay registration and the written configuration), the container is replaced with a call in flight, the loop relaunches from the record in the replacement with the bearer rotated, the row carriesrelaunches: 1with the new container and hash, the record holds thesandbox_restartedandresumednotes and the call's replaced settlement, and the run completes on the continuation the replacement's store was imported for.The container seam is harness-neutral in fact, not only in name.
HarnessContainer(src/core/harness/container.ts) is what any harness's process needs of the container the run's machine class provides —makeRoot,cwd,writeFile,start,writeLine,readLog,alive,identity,request,kill,tail,remove— with three implementations:ExecHarnessContainerover the run's executor, one command per operation as the thread's user (harness-pi.md item 4);BotHostHarnessContaineron the bot host for a preset without a workspace (item 12); and the in-memory fake the tests drive.makeRoot(wanted)answers the root the container makes from the one the harness proposes (its predictable/var/tmp/switchboard-<harness>-<runId>, outside the shared temp directory a checkout's suite or cleanup empties): the exec container answers the proposal itself, the bot host amkdtempbeside it.starttakes the program (a plain word on the container's PATH; a shell fragment is refused by name), its arguments, the stdout filter (lines carrying a mark never reach the log; absent, every line lands) and the run directory's layout (HarnessPaths: the root and the directories the start makes at 700, the FIFO, the log, the error log, the pid file, the command directory) as inputs, and answers the pid — the wrapper's, the leader of the group the process runs in, whichkillends first — and, when the start named a port, the port: a number to hand the process, orfreeto pick one in the container before the command runs (node on the exec classes, the host's ownneton the bot host), put inPORT_ARG's place among the arguments and in the environment underSWITCHBOARD_HARNESS_PORT, said on the first line of the exec's answer with the pid on the last, for the row; the placeholder among the arguments with no port named is a harness bug, refused by name before anything is made or spawned, never handed to the program as the word{port}. pi's start is byte-identical to the script the seam wrote before these were inputs:pi, pi'smessage_updatefilter, pi's layout, no port.request(paths, { method, port, path, headers?, secretHeaders?, body? })reaches a server the process listens on over loopback inside the container:curl -sS -iover the executor on the exec classes — the method, the port and the path checked as the shell and HTTP would read them, curl's own--max-timeunder the executor's timeout so a slow server is curl's named failure and never the executor's killed-command word, the body from stdin throughprintfor, past the inline size, from a file under the run's command directory that the request's own command removes, noExpect: 100-continue, never-f, so a 4xx or 5xx is an answer parsed to its status, its lowercased headers and its body with an interim1xxskipped — andfetchon the bot host, bounded by the same figure as the exec class's commands (OP_TIMEOUT_MS). A header whose value is a secret (a server's per-run password as Basic auth) goes insecretHeaders: on the exec classes its name is in the command text and its value rides the exec's env channel (-H "name: $SWITCHBOARD_REQUEST_H<n>"), the road the bearer takes on a start, so the executors' command logs never carry it; on the bot host it is a header like any other, nothing being logged on that road. The exec container requires structured command outcomes: exit and truncation are validated before stdout is decoded as HTTP, a launch receipt or log bytes. Stdout and stderr remain separate; presentation markers and runtime words in those streams never decide infrastructure state. Missing structured execution is refused before a command is sent. Typed infrastructure failures remain typed. Every retry consumes the original operation bound, within the admitted run deadline and the current run-control lease; transport cancellation bounds waiting but does not prove physical termination. A server nothing answers on, or one that does not answer in time, is a named failure, and a container gone under the request is the typed error, as from every other operation.identity()rethrows the executor's typed word that the container is gone (ExecSandboxRestartedError, or a typedHarnessContainerRuntimeReplacedErrorraised by an adapter;isContainerGone) instead of answering no name; an empty, malformed or failed answer is still no name. The run loop'sfinishplan reads that word fromfindas nothing left to end — aresumednote says the container is gone under the finish — and runs the post-steps with the answer, never failing the run over a leftover. A failed command is aHarnessContainerErrornaming the operation; a send whose control file vanished from under a live run while the container answers is the typedHarnessControlFileLostErrornaming the file and the root — never a container gone (harness-pi.md item 4).run_metanames the harness, and whose word put the run on it. The run's meta event carriesharness: <Harness.name>when the process drives runs with one, so a record can be told from another harness's on the run page and inruns get, andharnessScope: user | channel | defaults— the scope whose word picked it (item 8) — when a scope named the run's preset, absent when none did (the roster's default), so a reader of a run on OpenCode never guesses whose override moved it: the run page's facts bar saysopencode harness (user scope)(the timeline fold keepsharnessand a scope the roster knows, dropping any other). A process that starts no run publishes no such fields, and a record written before the seam has none. Additive: every consumer that knows the other fields keeps working.The conformance table: one table, every harness, no row without the record. The six clauses and the parity rows are one table of scenarios (
SCENARIOS,src/core/harness/testing/scenarios.ts), each a function of aHarnessDriver— start a run from a scripted model, read the run events, the ledger steps, the row's facts and what the container was asked, end — so pi's driver (src/core/harness/pi/testing/driver.ts: the real bridge, mirror, relay and gate over the fake container and the scripted double, opened through the seam's door,openThroughSeam, as the run loop opens every run) and any second harness's driver walk the same rows and no harness gets a table of its own; the drivers the tree has are one list (harnessDrivers) the suite and the matrix script both read. The rows: credential (the bearer in the process's environment and no provider key — the driver plants a sentinel under the bot's provider-key variables for the run, and no value of the process's environment may carry it — and neither events nor steps carry the bearer), gate (an allowed command and a refused push with itstool_refusednote; a command run without asking fails the run closed), relay (a relayed tool served under its name, run in the bot, its side effect in the run's context), record (the record's vocabulary — theleaseevent the harness starts the loop with included — and one ledger step per assistant turn; an unknown event kind aharness_errornote), conversation (the seed then the prompt; a follow-up steered as the next user turn; a hard stop), survival (the facts on the row and their round trip; another container's row neither probed nor ended; another harness's row refused), parity (the tools offered equal the harness's own for the identity plus the relayed ones; identitynoneandreadhide and refuse what they must), and the budget row (the loop ends inside the lease: theleaseevent names the start, the end and the loop's cut, the write-up is steered at the cut, and the run finishes before the lease ends — harness-pi.md item 15). A row's check reads the record: the lint (runRow) records every property a check reads and refuses a row that read neithereventsnorsteps, so a row that passes without looking at the record cannot enter the table. A row a harness cannot pass is a failure in the matrix, never a skip; a limit a harness declares (HarnessDriver.cannot, row id to reason) is asserted, not skipped: the suite's test for that row requires the run to fail as declared, so a declaration the harness has outgrown goes red, and the matrix prints it as its own cell with the reason beneath the table. The matrix (renderHarnessConformanceMatrix, printed bynpx tsx scripts/harness-conformance-matrix.ts) is harness × row, a harness without a driver shown absent; it is what a PR that touches a harness carries.The OpenCode process (record 0038's fourth amendment; the second harness as far as its process — the gate, the record and the conversation over it are the units after this one).
opencode serveruns per run in the run's container with the model proxy as its only provider and nothing else reachable. The images pin@opencode/cli@2.0.24beside pi in all three Dockerfiles with one line —npm install -g --allow-scripts=@opencode/cli @opencode/cli@2.0.24 && npm cache clean --force && opencode --version | grep -qx 'opencode v2.0.24': the wrapper's postinstall hard-links the platform binary into place, so it is the one install script allowed and by name; the version text is what the binary prints, exactly — the resident again asworker1after the user pool, the bot's in its runtime stage before its user;src/deploy/imageOpenCodeHarness.test.tsholds the pin equal across the three images and the@opencode/protocoland@opencode/schemadevDependencies at the same pin (about 206 MB unpacked per image; dark: nothing starts it yet). The layout (openCodeRunPaths,src/core/harness/opencode/process.ts) is/var/tmp/switchboard-oc-<runId>/(OPENCODE_RUN_ROOT_PREFIX), directly under the sticky/var/tmpfor pi's reason — outside the shared temp directory a checkout's suite or cleanup empties:xdg/{data,config,cache,state}(the four XDG roots, every global path OpenCode has),opencode.json,plugins/switchboard/index.js, the server'sserve.in,serve.log,serve.errandpid, the tailer'stailer.js,tailer.in,tailer.errandtailer.pid,feed.jsonlandcmd/; the tailer is a second process through the same seam (paths.tailer) whose log is the feed, so its stdout lands where the harness reads. The environment (openCodeLaunchEnv) is exactly: the bearer underSWITCHBOARD_RUN_BEARER(the name the configuration interpolates), the bot's URL underSWITCHBOARD_HARNESS_URL,SWITCHBOARD_RUN_ID, the fourXDG_*_HOMEunder the run (HOMEis left the container user's, so the model's shell sees the same~/.gitconfigand the rest that pi's shell sees),OPENCODE_CONFIGthe run's file with the project's own configuration disabled under both names the server reads (OPENCODE_CONFIG_PROJECT_DISABLE=1,OPENCODE_DISABLE_PROJECT_CONFIG=1; the first wins),OPENCODE_DISABLE_MODELS_FETCH=1,OPENCODE_DISABLE_AUTOUPDATE=1,OPENCODE_DB=:memory:(the store is a cache; the ledger is the record) andOPENCODE_PASSWORD— the bearer's hash (openCodePassword): per run and random because the bearer is, derivable by a later generation from the row'sbearerHashalone, worth nothing at the proxy or the bot's door; a bearer of another shape gets a random password and no re-attach. Never a provider key, whatever the bot's process holds; the server keeps the password in its environment (only--stdiomode deletes it), so a reply to an ask the bot did not send is a bypass the gate's unit must read as such. The configuration (openCodeConfig, held against the pinned schema in the tests):providers.switchboardwithpackageby the run's wire and the block's biller (openCodeProviderPackage(wire, biller), record 0052's amendment — the harness write names the biller's own provider):aisdk:@ai-sdk/anthropicon the Anthropic wire,aisdk:@ai-sdk/openaion Responses (refused at dispatch until measured, model-proxy.md item 1), the aggregator's ownaisdk:@openrouter/ai-sdk-providerfor a biller the table names (billerHarnessProvider— it asks forusage.coston the final chunk and spells reasoningreasoning: { effort }; amarkerscard's cache rides as OpenRouter's top-levelcache_control: { type: "ephemeral" }in the provider'ssettings.extraBody, merged into every request body alongside the binary's per-block markers on the system message, last tool and message tail. The real 2.0.24 binary sends both forms through the proxy; the generic provider's contrasting payload carries neither form (model-proxy.md item 11)), andaisdk:@ai-sdk/openai-compatibleonly for a block that is generic in fact (each bundled in the binary — the aggregator package as its own openrouter provider; nothing is installed at runtime),settings.baseURL<bot>/v1(the providers hang their route —/messages,/chat/completions,/responses— under it, the proxy's three paths) andsettings.apiKey: "{env:SWITCHBOARD_RUN_BEARER}"(interpolated at load; a provider with a key needs no credential-store entry), the model with a zero rate card and the run's output cap — the entry the run's card (model-proxy.md item 11):limit.contextfrom the card's window (the run'scontextTokenswhere no card came),capabilities.inputfrom its inputs, onevariantsentry per tier the card does not refuse whosebodyoverlay spells the wire's own word (openCodeVariants:reasoning_efforton the completions dialect,reasoning: { effort }on the aggregator's package; adaptiveoutput_config.efforton the Anthropic dialect, where a budget model has no adaptive word to spell and gets no variants; the identity words when the levels are unknown), and the cap field ascompatibility.maxTokensFieldon the completions dialect;modelthat model;default_agent: "switchboard";agents.switchboardmode: "primary", the composed prompt and the harness note assystem(openCodePromptNote: OpenCode's tool names for the identity,bashmapped ontoshell), andpermissionsin the order the evaluator needs —{ action: "*", resource: "*", effect: "ask" }FIRST, then the identity's denies (openCodePermissionRules), because OpenCode appends these after its base policy and judges by the LAST matching rule while*matches every action: a deny after the ask is the last word for its action and hides the tool, an ask after the denies would be the last word for everything and hide nothing. The denies:question,subagent,execute(CodeMode, many calls in one),webfetchandwebsearch(egress that is not the proxy) for every identity;editbesides forread;read,edit,shell,glob,grep,skillandexternal_directorybesides fornone.agents.title.disabled: true, or every session's first prompt spends one more model call — a proxy turn — on a title.plugins: ["./plugins/switchboard"]: a directory relative to the file (the loader resolves./against the document's directory and drops a configured plugin that is a file), whoseindex.jsis a placeholder that loads and registers nothing until the relay lands.update: "disable",share: "disabled",snapshots: false,lsp: false,formatter: false;compaction: { buffer, keep: { tokens } }only when the deployment sets them. The file carries no secret. The launch (launchOpenCode): the root the container makes for the run (makeRoot), the three files,opencode serve --hostname 127.0.0.1 --port <free>throughHarnessContainer.starton the seam's picked port with no stdout filter (a server started without--portscans upward from 4096, so the port is always passed). Readiness:GET /api/info(server.infoin the pinned protocol'sServerGroup) with the password as Basic auth — the one scheme the server reads, the info behind it like every route — answering 200{ version: "2.0.24", pid, urls, paths: { tmp } }withinOPENCODE_READY_MS(30 s), polled everyOPENCODE_READY_POLL_MSwhile nothing listens or the server says it is starting; a 401 is the password refused, another version is a binary this build does not drive, a body without a string version and nonnegative integer pid is not server info, a server that exited is its stderr tail, each anOpenCodeNotReadyErrorby name at once; thenGET /api/configechoing the run's document with every clause-carrying key present (configProblem: the loader drops a mistyped value by key with a logged diagnostic and keeps the rest, so presence is the proof a key took); thenGET /api/pluginpolled within the same readiness bound until the inventory names theswitchboardrelay plugin asactive(2.0.12 removedplugin.awaitActivation; its inventory is published after setup settles): an unrelated active plugin is not readiness, the relay’sfailedstate or a malformed inventory fails by name, and an absent relay times out before any tailer or session starts; then the tailer started withnodeontailer.js(its log the feed, kept and never truncated:HarnessStart.keepLog, so a restarted tailer cannot wipe what a recorded offset points into), and readiness ends only when the feed carries the tailer'sconnectednote, whose end is the feed offset the launch answers and the row's firstlogOffset; the tailer's pid rides the row's facts beside the server's, so a generation that comes back probes both and restarts only what is gone; the server's port underSWITCHBOARD_HARNESS_PORT(the seam's own variable) and its pid underSWITCHBOARD_SERVE_PID. The pid, the port and the root go on the row (openCodeFacts). A container gone under any probe is the typed error, rethrown as it is. The tailer (tailerSource.ts, plain CommonJS requiring only Node's modules) subscribes toGET /api/event(data: <json>blocks, a: heartbeatcomment between), writes one record per event as it arrives, reconnects with backoff (250 ms doubling to 5 s) when the stream drops — it is volatile by contract — and at everysession.step.ended,session.step.failedandsession.execution.succeeded/failed/interrupted, and on every reconnect for every session it knows, appends two records from the store: the session's pending asks (GET …/permission, whole) and the messages that changed since its previous refill of that session (GET …/message?order=asc&limit=200, the cursor followed to the end, diffed by message id against the JSON it keeps), so the feed grows with the work and not with the session; it exits when the server's process is gone. The feed's records (OpenCodeFeedRecord,client.ts, one JSON object per line):{ feed: "event", at, event },{ feed: "permissions", at, sessionID, reason, data },{ feed: "messages", at, sessionID, reason, data },{ feed: "tailer", at, note, … }(started,connected,reconnected,stream closed, a refill that failed);reasonis the event type that caused the refill, orreconnect. The client (client.ts) is hand-derived from the protocol and schema, originally at v2.0.3, each route and shape named with its source file and version (the server info and plugin inventory routes, experimental import/wait paths, permission decision body, and inbox time shape follow 2.0.24), and imports nothing from them at runtime;@opencode/cli,@opencode/protocoland@opencode/schemaare now pinned together at2.0.24, matchingOPENCODE_VERSION;client.test.tsbuilds the pinned groups and decodes server response samples (historical live responses updated to the 2.0.24 schemas), so a bump that moves a route or a field fails there and not in a run. Two facts the units after this one read off the same probes:POST /api/experimental/session/:id/waitblocks until the loop is idle (it does not answer 503 while busy), and a tool turn produces twosession.step.ended(the call's step, the answer's). Workspace runs use a separatescratchdirectory beneath their owned root for$TMPDIRand native file tools. The launch facts record that capability, so a legacy live process acquires no new path access on reattachment. The existing producer-custody rules govern cleanup of the whole root.OpenCode as the contract's object (the relay, conversation and survival clauses over the process item 12 built).
OpenCodeHarness(opencode/harness.ts) is the secondHarness, driven through the seam like pi's. The relay (openCodePluginSource,pluginSource.ts) is a local plugin the launch writes intoplugins/switchboard/index.js(nobun install; a configured local plugin must be a directory): at load it registers each frozen launch declaration through the v2ctx.tool.transformeditor as a DIRECT tool (options.codemode: false, or the model's direct call answers "No tool named …"), and each call runsPOST /harness/authorizethenPOST /harness/toolwith the model's call id (context.id) — the202 pendingre-asked and the 90-second waits exactly as pi's extension does, so the relay's idempotency by the call id holds and the bot gains no MCP endpoint. A plugin-registered relayed tool raises nopermission.asked(proven against the real binary), so it is gated only by its/harness/authorizeand runs in the bot; the bridge's bypass detection skips relayed tools by name. Skipping them is sound, not a new hole in the honest cannot: relayed tools are admitted by roster and never decided per call by the gate (authorizeToolCallallows any tool on the run's roster, refusing only during the write-up), and their effect happens only in the bot behind its walls — the token's scope, branch protection,spawn_run's limits — never in the container, so asession.tool.*record under a relayed name carries no container effect for the four-effect rule to catch. The rule's job is the harness's own tools, whose effects run in the container; the gate overpermission.asked(item 2) is those. The conversation: the thread's earlier turns are imported as an authored session (openCodeImportBody: one store message per seedChatMessage,POST /api/experimental/session/importinto the run's location), the request is aprompt { delivery: "queue" }whose answer is read — as is the prime's (the import or the create) and a follow-up turn's — and an answer outside 2xx is aharness_errornaming the request and the server's answer at once and the run's failure by that name (OpenCodeRequestRefusedError), never a wait on the feed for an execution that never began; aqueueprompt the server admitted owes the feed the session's ownsession.execution.startedwithinFIRST_EVENT_BOUND_MS(the readiness bound,OPENCODE_READY_MS: a server that took the prompt starts its execution well inside the time it takes to come up) — the one record that lifts the bound (executionStartedFor): the tailer's reconnect sweep (its note and the permissions and messages refills it writes for every session it knows, whether or not anything changed), the server's events that name no session (provider.updated,websearch.updated) and a record read catching up on a re-attach lift nothing, since a wedged server's feed is not silent, only silent of the execution — past which the run fails by name (OpenCodeSilentError) with aharness_errorcarrying the phase, the session, the feed offset, the last feed record and the tails ofserve.errandtailer.err, the interrupt posted and the process ended (asteerlands at the running execution's next step boundary, which a long tool call may put minutes away, and is not bounded); the same start marks the execution as the loop's own, and until it the bridge observes inearliermode — one three-valued mode,OpenCodeBridge.observing(own | earlier | catching-up), set by the loop before each record: every record before the start is an earlier execution's — the tail of the write-up a previous loop interrupted at its finale, which the server sends once the post-turn's prompt is posted; measured against the real binary, the interrupt drops an ask pending at it (gone from the pending list, nopermission.replied, a reply to it afterwards refused 404), the tool failsaborted(Tool execution interrupted), the step failsaborted, then the execution's end or failure and, after it, the refills land, and the interrupt answers 200 on an idle session too ({ interrupted: false }), so an ending's interrupt after the execution ended by itself is no refusal — and in that mode nothing decides: no reply, no bypass, no settle, no tool event on the record; every event of the pinned binary's execution carriesassistantMessageID(verified in its schema: the step, text, reasoning and tool events share it), so the steps the loop saw in its own execution are its own by construction (OpenCodeBridge's own steps, learned inownandcatching-upmode) and a settle naming any other step — an earlier execution's, landing however late and however many post-turns later — is set aside whenever it lands, nothing handed turn to turn for it, in the loop's own mode — and there alone; catching up, the dead generation's records keep their own rules — under asettle_set_asidenote naming the call and the step, information and not a failure, so a foreign tail and a step lost with the stream are told apart on the record; an ask teaches its step whichever way it came — the stream's event or the store's permissions refill after a dropped stream — and a tool's ask for a call the record never saw called — an ask naming its call (sourceof typetool); one naming no call opens nothing — opens the call from what the ask names: the tool under the record's word for its action (an MCP tool under its tool half), and for a permission over something other than a tool (external_directory,doom_loop: the pinned binary's two beside the tools' own actions) the tool of the part the ask'ssourcenames in the mirror's store — its assistant message, its tool part, the tool's own input leading the call's record and the directory anexternal_directoryask reached beside it under its own key (anexternal_directoryask answered once the call's line is already on the record cannot amend it and leaves adirectory_reachednote naming the call and the directory; the asks held before the call opened ride its line at whichever site opens it — its own ask, the stream'ssession.tool.called, a refill naming its part, or its settle — so the note is a genuinely late ask's alone; "on the record" is atool_callline written (announced), never a name alone: a call the stream only named (session.tool.input.started, itssession.tool.calledlost) opens under the stream's name at its own ask or at the settle of a held resource ask, so the loop's end can cut it, and stays the stream's record hole only when no ask of its own ever came) — or, the store having shown no such part yet, the call held unopened until a refill names it — the one mechanism for an ask read ahead of its part, whichever order the feed brings them — opened once (the stream'ssession.tool.calledthat follows opens nothing twice), and opened at its settle under the permission's own name with atool_unnamednote when none did; the tool's own ask and a resource permission's ask for one call are each answered (the asks are told apart by request id, never by the call they share);doom_loop— OpenCode's repeat guard, the same call made over and over — is refused under its own name, judged before any tool's name is read off the action, so the model changes course rather than loop, the call it names opened under the tool's word (an assumption, not a measurement: fourteen identical shell calls, successful and failing alike, raised nodoom_loopask from the pinned binary under the launch's rules, so what the refusal does there — a tool error the model reads, or a failed step — is unmeasured); a refusal on a call is sticky — the tool's own ask allowed after it lifts nothing, and a success executed anyway is the gate bypassed; so the tool it lets run is judged and recorded on atool_callthe record announced, never an orphan result and never a phantom one; the store's refills feed the mirror and a compaction lands as its note and row in every mode; a failure is noted as whose it was (a model call of an earlier execution failed (…); continuing, or the proxy's turn-budget refusal by its own name and its 403,an earlier execution reached the proxy's turn budget (…); continuing, never a failed model call; catching up,… while the bot was away), the aborted execution's failed step is not said again, and the records that carry no decision — a tailer note, an event kind no table names — are surfaced as in every mode, so a post-turn on the session never reads an earlier execution's tail as its own and never loses its feed's own notes; a steer or an interrupt whose answer the loop does not wait on is aharness_errorwhen the server refuses it, whenever that answer comes, the loop left or not — to the record alone once the loop has left, never to the card the ending closed, and the record is open for it: the run finishes only after the harness'send(), which kills the server, cutting whatever has not answered, and returns once every request the loop posted has settled (OpenCodeConnection.posted), so no answer can reach a finished record — and says nothing only when the request itself failed after the loop left, that kill having cut it; a control reset (item 6) under one of the loop's writes is resolved from the server's own state, never re-sent blind: the feed re-attached in place under aresumednote; aqueueprompt told landed by a user message with its text the loop did not know the store to hold — that row then the prompt's own, recorded as one whose answer came is (OpenCodeConnection.writes,knownMessageIds) — (OpenCodeConnection.knownMessageIds: the import's, a re-attach's store, the refills the loops before read and the message each steer this generation posted became — a steer's answer names it, measured, and a steer whose answer named none or was cut by the reset is told from the store the same way, one verdict for both — the rows newer than what was known when the steer was posted, never what was learned since: its row the follow-up delivered, the id learned; no row and the store idle (below the oldest prompt the loop posted after the steer, its newest row the idle marker, an imported row or none), the steer lost and handed back; no row with an execution under way — the ordinary timing, a follow-up arriving mid-step — the store cannot yet say, since a steer into a running execution lands only at its next step boundary (measured), so the verdict waits for the boundaries the loop reads off its feed (StepBoundaries, counted onOpenCodeConnection.boundaries: a step's end or failure, the execution's end, the idle) and reads the store again at each — the row there, landed and folded in, the run continuing; the idle marker (an imported row, or nothing) newest since the steer with no row, lost — the store's word, never a count of boundaries — and handed back for the run stage's fresh turn, never steered again by this loop (a steer told lost while the server still held it would reach the model twice): held with the same person's later follow-ups behind it, in order — the model never reads a person's later follow-up before an earlier one; another sender's still goes out, and a parent run's steers are never held (a program's steer gets no fresh turn: the settlement sets it aside, so a later one waiting behind a lost one would never be read) — and requeued to the front of the inbox once the loop has left, the drainer stopping only on a refusal; an unresolved steer's own follow-up is handed back too, the run failing by name and its session over, so a fresh turn repeating what the server may have taken is the record's word kept, and the drainer asks no stop of the run's control — it ends the loop by the failure's name through the connection (OpenCodeConnection.failure, every connection carrying the slot: the interrupt posted, nostoppednote, the run failing as any named failure does and its projections showing a failure, not a kill), so the dispatcher's settlement, seeing no stop, hands the follow-ups handed back on for the fresh turn where an operator's stop would drop them — never a follow-up dropped; the workspace's release reads the record, not the failure's name: a command the run's ending may have left running in the workspace (callsInFlightover the run's own events, read by the run loop once the harness session has ended and before the record is sealed, the same events the release reads for the branches it hands over) tears the workspace down at once (releaseModeFor'salways, as after a hard stop), since a release that waits for idle would be refused by the command and hold the workspace past the run — and the record says why (aworkspace_torn_downnote naming the calls); such a command is a call the ending cut, its result markedcut— pi's abort (the tool's own failed end after it, marked by pi's bridge; a tool that exited clean before pi handled the abort settles, unmarked), OpenCode's interrupt (a call still open when the loop left on an interrupt it posted, closed marked), a session's end after an abort or an unsettled turn (closeOpenSpans) — whatever the run's status, and once cut a call stays cut whatever lands for it later (the post-turn's bridge reads the earlier execution's aborted settle as its own, an unmarked result for the same call), or a call left open when the run failed, was interrupted or hard-stopped (a steer unresolved while a tool ran, a server gone silent mid-call); a run that completed or stopped softly with a call unpaired — a relayed tool that ran in the bot, a result lost to a transport gap — left nothing running and pairs the workspace as any orderly end does (a clean settle leaves such a straggler unmarked on both harnesses), as does a failure with nothing in flight (an opening prompt whose store listing failed, a gate reply unresolved); the events read are the registry's bounded backlog (runRegistry/backlog.tsdrops the oldest past its count or byte bound), so a cut result whose call's line a long run evicted counts by itself — the harness's own word that the call was ended and not settled, named by its tool and id, the call's own line back when it is announced again — and the read is taken once, at the harness session's end, under the run's status then: a throw after a clean end (a publish, a join) fails the run without re-reading underfailed, which would count a relayed call's unpaired line as a command in flight and note a cut twice, while an end that itself throws is no clean end — the process may still run with its command — so a run not already interrupted is failed before the read and its original workspace is retained (an interrupted run stays interrupted, its card and status agreeing), and an end failing in the loop's own catch is aharness_errornote: the unconfirmed producer retains custody and the loop's error is the one that propagates; a gate bypass (HarnessGateBypassedError, the failure every harness raises for it) tears the workspace down whatever the record shows, since what ran in it was never vetted; an operator's hard stop landing beside the drainer's failure wins: the run ends as the stop — itsstoppednote written, the hard stop's answer given — and the failure stays on the record as itsharness_errornote, never the run's end (OpenCodeHarness.openyields the drainer's failure to the stop); a follow-up held behind an earlier one leaves its ownfollow_upnote; measured against the real binary: a steer into a running execution is announcedsession.inbox.enqueuedat its POST andsession.inbox.deliveredat the step boundary it lands at, right after that step'ssession.step.ended, its row in the store there — before the execution's terminal event, the execution running a step for it — and a steer arriving after the end starts a new execution at once, its row in the store before the answer; a steer enqueued when the execution is interrupted is dropped with it (nosession.inbox.delivered, no row, no new execution), and one enqueued when the execution fails is delivered into a new execution the server starts at once — so the idle marker newest since the steer with no row, read after any terminal transition, is the server's word that it took nothing; the loop leaving the feed with no row and the store still showing the execution under way (a hung model call the finale interrupts; a hung tool is cut at the loop's end instead and its write-up's execution brings the boundary), unresolved — a steer answered without an id the same — the batch's follow-ups not yet posted handed back to the inbox with it — a store that cannot be read or a steer unresolved failing the run by the same name,OpenCodeWriteUnresolvedError, one rule for both writes — read once every request posted and not waited on has answered: a steer's answer, or its first store read when the answer named no id or the reset cut it, never its wait on a step boundary, which only the loop's own feed reading delivers) and told lost by none, re-issued once — the store read newest first down to the newest row the loop knew when it posted the prompt — a steer posted since, known by its answer, landed after the prompt and is read past — (readStoreSince, one pager with the re-attach's whole-store read —readStorePages—order=desc&limit=200on every page, the cursor followed, one page in practice and never the whole store; measured against the real binary, whose listing is its insertion order — not the rows' ids, not theirtime.created: an import stamped an hour ahead still listed before the prompt posted after it — answers 50 rows newest first by default, at most 200 a page and a 400 above, lists a queued prompt's message the moment it is admitted, and keeps the ids an import carries), never one unqueried page, a store that cannot be read leaving the outcome unresolved; a gate reply told landed by its ask gone from the pending asks and lost by the ask still pending, re-issued once, a 404 then being the ask dropped meanwhile (the binary's way) and no failure; a steer never re-sent, pi's rule; a state that cannot be read, or a re-issue that meets the reset again, failing the run by name (OpenCodeWriteUnresolvedError; for a reply,OpenCodeReplyFailedErrorcarrying it) with aharness_errornaming the request; an operator's soft stop requested once a write-up is under way is onestoppednote in mode soft and no second steer, the answer under the ending already under way, and a hard stop that follows a soft one writes its ownstoppednote, so the record shows both actions; the loop'srun.agentspan endserroron a failed model call as on every failure by name, andokon the finale's abort as pi's does;session.execution.failedis the execution's terminal transition — measured against the real binary, whoseprovider.no-routefailure (Model unavailable: <provider>/<id>) is the session's last event, nosession.idlefollowing — so the run settles on it, failing by the provider's words at once or, once winding down, closing by the wind-down's answer with the failure as its note, and never waits past it (the proxy's turn-budget refusal excepted: it is the wind-down's trigger, and the write-up steered starts an execution of its own); the follow-ups and the wind-down areprompt { delivery: "steer" }— save a wind-down — the time budget's, the turn guard's, the proxy's turn-budget refusal's, an operator's soft stop's — that finds a tool call open (doingNow's structured reading, worded bydoingWords; decision 0046, unit seven, OpenCode's half): a steer is delivered at the running execution's next step boundary (measured against the pinned binary:session.inbox.deliveredright aftersession.step.ended), which a hung step never reaches, so the loop posts the session'sinterruptfirst and reads its answer three ways once it has come — and only if the loop still runs: a stop, a failure or the finale landing while the interrupt is in flight, or a hard stop requested in the round-trip and not yet read by the loop's check, leaves the write-up unposted, no execution nobody reads —interrupted(it landed on the live execution: atool_cutnote beside the wind-down's, written only now that the cut is a fact and naming the calls open at the landing — the tool open at the decision may have completed in the round-trip and another begun — the calls still open markedcut— a tool that completed during the round-trip settled on its own, read as the loop's and unmarked — and the write-up posted as aprompt { delivery: "queue" }),idle({ interrupted: false }: the tool completed during the round-trip and its execution ran on to its own end — nothing cut, notool_cutnote, no write-up posted, the loop reading that execution's own settle and its last text as the answer — the model's own, wearing no wind-down label, awrap_upnote saying the instruction was never posted and how the wait ended — the execution finished on its own, or failed on the provider, or the interrupt was never answered and the finale bound ended the wait, read off the end the loop left on before the failure the wind-down's note holds, which the finale sets too — never an idle session or a provider failure claimed for a finale (wrapUpNeverPostedNote, pi's undelivered-wrap-up rule), and what ended the wait said in the unlabelled answer too when it was a failure or the finale (unlabelledAnswer), never dropped from the thread; should that execution end instead on the proxy's turn-budget refusal, the wind-down's decision stands with nothing posted, so the refusal starts the write-up as a steer into the idle session — measured, a steer after the end starts an execution at once — the finale clock re-stamped at its post, never a finale run out with nothing executing), or the failure (an answer outside 2xx, none, or a 2xx saying neither: nothing was interrupted and the run fails by that name at once —OpenCodeRequestRefusedErrorfor a refusal — as any refused request does, never a steer that waits the command out nor a finale run out, the open call closed markedcutwhen the loop leaves on the failure's own interrupt); the queued write-up is registered as the loop's own write (ownPrompts, set aside by a follow-up steer's resolution as the opening prompt is), which starts the write-up's own execution with the write-up's whole allowance ahead of it; the interrupted execution's tail — the step failingaborted, the usage, itsinterruptedend and the refills, landing only with that queued prompt (measured, the fake'sinterruptSettlesLate) — is read in the bridge'searliermode as a late settle at a step boundary, never as the loop's end, and itsinterruptedend is the cut's from the moment the interrupt is posted (OpenCodeBridge.cutInterrupt, set at the post, cleared when the answer isidleor a refusal): whenever it lands and in whatever mode — before the interrupt's own answer (the fake'sinterruptAnswersAfterTail), with the next queued prompt inearliermode (measured), or after the write-up's ownsession.execution.started(lateTailAfterNextStart) — it is set aside, under asettle_set_asidenote when it lands in own mode, and never settles the loop, and so is asession.idleunder the cut — a deprecated status event in the pinned schema, redundant to the durablesession.execution.*transitions the write-up ends with, so a trailing idle of the cut execution landing after the write-up's start settles nothing — while every other end in the loop's own mode —succeeded, a failure — is the loop's own, so a write-up whose predecessor's end was never serialized still settles or fails by its own words (the fake'sowedEndNeverSerialized); the loop is not disowned at the post — the round-trip's records stay its own, since a tool completing in the window and its execution's own end (theidleanswer) must be read as the loop's, never dropped as an earlier execution's — and the tail's order (the step failing before the end, as the fake emits it) is an assumption the cut step's id makes harmless; the kind decides because nothing else can — the schema's execution shapes (originally read in@opencode/schema2.0.3,session-event.js,Execution; the current package pin is item 12's) give the foursession.execution.*eventssessionIDalone,interruptedadding itsreason, no execution id to match an end to its start by, and a natural completion endssucceeded— under the named assumption that the write-up's own execution ends with a durablesession.execution.*transition (measured forfailedandsucceeded), the deprecated idle never its only end; the cut execution's steps'abortedfailures in that tail — the step open when the interrupt was posted and every step the execution began before the interrupt landed (the tool completing in the round-trip and the execution moving on to a model call the interrupt then cuts; the fake'scutLandsOnNextStep), those steps alone — are noharness_error, the write-up's own steps, begun after the landing, failing as ever (anan OpenCode step failednote for the write-up's own aborted step; the fake'swriteUpStepAbortsplaces that step'sabortedfailure with no interrupt behind it — a contrivance, not a measured shape, putting the one failure type the cut's steps swallow where the cut cannot own it); the cut tool's own outcome is the loop's own result markedcutwherever it lands — riding the tail inearliermode (the one settle that mode lets through: a call incutCallswas opened in the loop's own mode; the fake'shungToolSettlesInTail), before the interrupt's answer in own mode, or after the write-up's execution has started — and a tool failingabortedunder the cut interrupt, its ask dropped before it ran (the measured shape of an ask pending at the interrupt; the fake'shangAtAsk), is the interrupt's own doing: markedcut— by timing, as every cut mark is, anidleor refused answer afterwards unable to unmark it, the server's own contradiction if it comes — and no gate-coverage note for a call with no ask the bot answered — its shape an assumption, not a measurement: the fake's recorded late success stands in for it, the one interrupt measured against the pinned binary being of an ask pending at it (the tool failingaborted), not of a running tool, so the conformance row asserts the mark on both harnesses and the failure on pi alone, and the mark is by timing (the calls open when the interrupt is posted) rather than by outcome until the live probe says what the binary does; the finale clock starts at the queued prompt's landing — a prompt the server refuses fails the run by name at once (OpenCodeRequestRefusedError), and one lost on its transport — no answer, the loop still running — fails it by name too (the post'sharness_errornaming the transport), never a finale run out for an execution never started, and a post that never answers is bounded by the post's own moment; the calls still open when the loop leaves are closed markedcutonly when an interrupt was posted at, or landed on, a live execution — an ending's, or the loop-end cut's answeredinterrupted— never after a loop-end interrupt that cut nothing (idle, refused), so a straggler at a clean settle stays unmarked and the release pairs the workspace for it, and the closed result's reason names the path the loop left on from the two facts the interrupts record where they are posted (interrupts: the cut once it landed, an ending's interrupt named by the path posting it — neverendedalone, which a bypass and a reply left unresolved leave undefined too): the cut with the write-up settled, the cut then an ending (a gate bypass, a reply left unresolved, a hard stop, a failure by name, the finale), or an ending with no cut; the silent ending's interrupt is posted after the exit's close and names no open call (none can be open before the execution's start); whether the interrupt ends the command's own process is the live probe's to say, the release reading the cut call as a command that may run on (drained besidedriveOpenCode; the wind-down also refuses relayed tools at the door as pi's does —LiveHarness.toolsBlockedreads the bridge's write-up state through the connection — and a steer the server never took is handed back to the inbox for a fresh turn, never recorded as folded in; a model call that fails once the run is winding down is aharness_errornote and the wind-down's answer stands, the same rule as pi's, and the budget note reads the open tools or the started step offOpenCodeBridge.doingNow), the hard stop isinterrupt, an operator's soft stop steersSOFT_STOP_INSTRUCTIONunder astoppednote in modesoftand answers under the ⏹ label, the write-up is bounded by the lease'sfinaleMspast which the loop interrupts the session and leaves without a settle (item 5), and the post-turns are one moreprompton the same session; every model reference the harness sends — the create, the seed's import, a rebuild's import — names the configuration's one provider (PROXY_PROVIDER, the keyopenCodeConfigwrites the model under) and never the bot's provider name, since OpenCode resolves the reference against the configuration the launch wrote; the effort tier rides the model ref'svariantexactly when the configuration declares it (openCodeVariantIdover the card's variants), so the session selects<model>#<tier>and the variant'sbodyoverlay spells the wire's word; a run without a card, or a tier the card refuses, selects none and the tier is left to OpenCode's default. The survival word is authored-session: a rebuild imports the record into a fresh store with each call in flight a completed/error tool content carrying the settlement note, and the mirror primes the settlement turn (OpenCodeBridge.prime) so the ledger's first step, the store's rows and the model's view agree — the record then rebuilds a transcript with a result for every call.findprobes the recorded port (any answer, even the password-guarded 401, isalive-here);endkills the server and its tailer and removes the root. The survival ceiling is OpenCode's own:driveOpenCode's container-gone read (saysContainerReplacedon the feed) settles the open call on the record (closeOpenSpans— a failedtool_resultcarrying the replaced note), builds the record as pi's is (the mirrored rows throughprojectStore, the last turn's calls settled), writes asandbox_restartednote naming both containers' words, and throwsOpenCodeContainerReplacedError(message, said, was, now, record)with nothing killed or removed in the container that answers now, soprepareRelaunchre-opensopenwith the record — the registration taken over withregistry.replace(its relayed calls kept), onerelaunched after the container was replacednote. A resume naming this container probes the recorded port with the row's password (probeRecordedServer; without one when the row carries no bearer hash) and re-attaches onto a server that answers it (reattachOpenCode): the session's store read back page by page (a store that does not end within its page bound is refused, never continued on in part) and the mirror aligned past the ledger's rows by turn (OpenCodeBridge.adoptStore,ledgerTurnCount— a ledger user row is one projected turn per tool result and one for its text, so the flattened ledger and the store's projection align from the first message) so the results and steers pending for the next step land as its user turn and nothing of the transcript is written twice; the asks pending on the server decided through the gate before the feed is read, as on a fresh open; the relayed call in flight answered from the record when the plugin asks the relay again, never re-run; then — every check passed and nothing changed before — the row's bearer adopted onto this generation's proxy (a refused re-attach leaves the dead generation's hash refused there) and the tailer kept where its pid answers, else restarted over the same feed withkeepLog, the password and the server's pid; the feed read from the row'slogOffset— the dead generation's records up to the feed's edge at the re-attach read catching up (OpenCodeBridge.observingincatching-up: their tool events narrated again; for a call whose result the ledger holds, the ask that generation decided and its echo are its own word and a settlement under its watch is no bypass; the gate during the bot's absence: a call of OpenCode's own the record shows in flight at the death whose ask the server no longer holds pending was answered while the bot was away — by the dead generation an instant before it died or by the model's shell with the server's password, and the run cannot tell by whom — so its echo or its settlement met catching up is the gate bypassed and the run fails closed, at most one model call lost, the note readingan ask pending at the bot's death was answered while the bot was away; the run cannot tell by whom; its execution's end or failure aharness_errornote and never this generation's settle) and this generation's records live; the continue (CONTINUE_PROMPT, pi's words, on every resume) steered into the execution under way, or queued when the store's last message is theidlemarker; the row rewritten with the tailer, the container and the feed's edge as its offset,relaunchesunchanged, and the offset following each refill whose steps landed (OpenCodeConnection.saveOffset); oneresumednote in pi's shape —OpenCode still runs in the container (pid N, port P); continuing its session with M min of budget left — K call(s) were in flight…. A server that answers but cannot be re-attached — the row carries no bearer hash, the password is refused, the server info names another version than the pin, the session or its pending asks are refused, the store does not end within its page bound, the feed cannot be read from the offset or is shorter than it — is retained with its tailer, root, feed, session and original pointer; the run fails by name with typed unconfirmed custody rather than removing private state or starting another producer; a row naming another container is the orphan, neither probed nor ended here. The mirror's join is by message id (OpenCodeBridge's store map, upserted by every refill and projected whole): a refill of the changed messages alone — the real tailer's every refill after its first — lands the same steps as one of the whole store. The identity's own tools are the record's words (shell → bash,glob → find), so a tool call lands under the same name the roster names across harnesses — and a rebuild's import writes those words back as the session's own names (openCodeSessionToolName:bash → shell,find → glob, a relayed tool's name kept), so the rebuilt session reads a history whose tools its own table holds — the tool table the run had before the roll — and the first tool call after a rebuild runs; a call under a record word all the same is refused by the server before anything runs (no tool of that name exists) and noted as the transient by the session's own name for the tool, never as the deny rules' doing, which would read as a run without a workspace.
The relay clause includes launch metadata: the existing runner passes only tool names, descriptions and input schemas from its registered run into both launch adapters. Prompts and native allowlists derive from that snapshot. New adapters register locally without GET /harness/tools; actual authorization and execution still use the bot on every call. This grants no cached authority and changes no admitted deadline, producer custody or resume decision. Retained processes keep their original files, and the old discovery endpoint remains for those consumers.
Validation criteria
| Criterion | Proof |
|---|---|
| A successor opened on the durable post-turn clock gets provider tool eligibility during execution and clears the temporary mark after success or failure on either harness. Ancillary steps preserve their selected substantive report; a later substantive correction clears that selection. | [unit] src/core/harness/contract.test.ts::openThroughSeam — the seam's door::a %s successor restores proxy tool access…, src/core/harness/pi/harness.test.ts::runPiHarnessOpen — the session stays open for one more turn::a substantive answer correction clears the ancillary publication selection, src/core/harness/opencode/harness.test.ts::hosted Review originating lifecycle::binds a fresh same-session follow-up check… |
| 3: both adapters load frozen launch declarations while discovery is unavailable; schemas remain exact and a current refusal blocks execution before the same-id relay. Partial registration never completes setup. | [unit] src/core/harness/launchTools.test.ts::runner-owned tool registration::%s registers launch definitions without discovery and still asks the bot for authority; src/core/harness/opencode/pluginSource.test.ts::the OpenCode relay plugin::rejects setup when registration fails after adding one tool; src/core/harness/opencode/process.test.ts::launchOpenCode — the server started through the seam and found ready::fails by name when the configuration did not take… |
| 3: OpenCode's relayed calls keep a malformed-body 4xx final and wait through a resuming bot without changing the original call id. | [unit] src/core/harness/opencode/pluginSource.test.ts::the OpenCode relay plugin::keeps a %s authorization refusal final without relaying, ::waits through a resuming bot and keeps the original id through pending relay answers |
| 2: OpenCode's shared shell gate allows quoted source search patterns and refuses a real environment dump after the search | [unit] src/core/harness/opencode/bridge.test.ts::openCodeToolNameWord and judgeOpenCodeAsk — the gate in pi's words::allows source searches but refuses environment dumps through the shared shell gate |
12, 13: each workspace run has a separate temporary directory beneath its existing owned root, outside configuration and checkout. OpenCode supplies that path as $TMPDIR; file-tool admission uses the same run boundary as Pi, and legacy launch facts confer no new grant. Cleanup follows the existing producer-custody and owned-root rules. | [unit] src/core/harness/opencode/process.test.ts::openCodeLaunchArgs and the environment::hands the server exactly the run's variables…, src/core/harness/pi/toolRules.test.ts::judgeToolCall — run temporary files::*, src/core/harness/opencode/harness.test.ts::OpenCodeHarness — the re-attach onto a still-answering server::restores temporary file reads only for recorded scratch-capable OpenCode:…, ::retains the actual launch temporary-directory capability through saved facts and reattachment, src/core/harness/container.test.ts::ExecHarnessContainer — each operation is one command over the executor::remove takes the run's directory down as one tree, and nothing else |
| 1: the harness starts with the bearer in its environment and no key, and every model call goes through the proxy | [unit] src/core/harness/pi/harness.test.ts::runPiHarness — a run on pi from the first file to the answer::writes pi's files, starts it with the bearer in the env and no key…, [unit] src/core/harness/conformance.test.ts::conformance — pi::credential: the process is started with the run bearer… |
| 1: the proxy serves exactly three dialects — Anthropic messages, OpenAI chat completions and OpenAI responses — and a fourth path under a valid run bearer is refused by name, never forwarded; a harness needing a fourth is a change to the record | [unit] src/channels/modelProxy.test.ts::the model proxy's paths::serves exactly three dialects… |
1: pi's failed terminal results distinguish proven provider failure and refusal from local cancellation and unknown outcomes; only a proven provider failure or refusal carries ProviderFailure.cause, and unclassified outcomes never claim a provider refusal | [unit] src/core/harness/pi/bridge.test.ts::turns, narration and the answer — the loop's rules::keeps local aborts and unknown terminal results outside the provider-failure types, ::turns, narration and the answer — the loop's rules::keeps proven provider refusal, permanent failure and transient failure as distinct terminal types, src/core/harness/pi/harness.test.ts::runPiHarness — a run on pi from the first file to the answer::an unknown terminal model result fails honestly without retrying or claiming a provider refusal |
1, 5: a failed model answer carries one typed terminal result; only a proxy-authenticated provider failure or an explicit provider refusal may carry a ProviderFailure.cause into the harness, which retries only the typed transient and rate-limited set with bounded attempts and time and renders local or unknown endings safely, with no payload or provider URL | [unit] src/core/providerConformance.test.ts::ProviderFailure — the closed failure matrix::*, src/core/harness/pi/harness.test.ts::runPiHarness — a run on pi from the first file to the answer::a typed billing failure ends the run without another model prompt, ::the harness's park decision is the typed cause set, not a second prose classifier; [gap] OpenCode preserves the typed cause through session.execution.failed, holds provider-down executions and resumes them from the plane's release instead of ending the run |
| 2: every call is decided in the bot — a relayed tool allowed by name, the harness's own tools judged by the rules, every tool refused during the write-up — and the gate's coverage is checked from the stream: a call that ran undecided fails the run closed, a call the harness refused itself is a note | [unit] src/core/harness/pi/relay.test.ts::authorizeToolCall — the gate::*, src/core/harness/pi/bridge.test.ts::the gate's coverage — every call that ran was vetted::*, src/core/harness/pi/harness.test.ts::runPiHarness — a run on pi from the first file to the answer::a tool call pi ran without asking the gate fails the run closed…, [unit] src/core/harness/conformance.test.ts::conformance — pi::gate: every tool call the harness runs is decided by the bot…, ::gate: a command the harness ran without asking fails the run closed…, [unit] src/core/harness/conformance.test.ts::conformance — opencode (fake serve, gate and record)::gate: every tool call the harness runs is decided by the bot…, ::gate: a command the harness ran without asking fails the run closed…, [unit] src/core/harness/opencode/bridge.test.ts::openCodeToolNameWord and judgeOpenCodeAsk — the gate in pi's words::*, ::the acceptance examples, end to end against the fake serve::* |
| 2, 13: OpenCode's synchronous permission gate cannot resolve a source commit before replying, so with Git Door it refuses a standalone literal shell push; ordinary shell work remains allowed but cannot forward a receive-pack without the runner's one-use source grant, and runner-owned checkpoints use their own admission | [unit] src/core/harness/opencode/bridge.test.ts::the gate's honest cannot, the compaction row, the budget stop, the unknown kind::fails closed on OpenCode shell publication without pi's source-bound admission while leaving reads runnable, src/core/modelProxy/gitBindings.test.ts::GitBindings::consumes one typed harness push authorization bound to source, destination and old head |
2, 13: a gate reply OpenCode answers 404 is read against the pending asks — the ask gone, the server withdrew it (the reject cascade after a sibling's refusal): one ask_withdrawn note naming the call, the reply decided and the sibling's refusal, the server's own reject echo no bypass, the declined call settled by the server's failure, one listing and no blind re-send, the loop not stopped; the step's session.step.failed {aborted} is not a harness_error (the cascade's own end, named in the ask_withdrawn note); if the execution ends interrupted, the loop re-prompts the model with the refusal in a queue prompt (a decline_cascade note) so the model can continue — exactly as it does after a single refusal — rather than end the run answerless; the ask gone with no refusal of the bot's in the step, withdrawn and not fatal all the same (the note says no refusal is on the record) but the reject echo judged as any reply is — a bypass against a decided once, fail closed; the ask still pending, OpenCodeReplyFailedError as for any reply that did not land, no note; against the real 2.0.24 binary, a step with two shell calls, one refused, declines the sibling with permission.rejected without running it, then continues to a successful answer in one execution, with no second prompt or decline_cascade | [unit] src/core/harness/opencode/bridge.test.ts::the loop — a reply that cannot be posted, and the narration's timing::a permission-reply POST the server answers 404 for an ask its pending list no longer carries — the reject cascade…, ::a permission-reply POST the server answers 404 for an ask its pending list no longer carries, with no refusal of the bot's in the step…, ::a permission-reply POST the server answers 404 while its pending list still carries the ask…, [unit] src/core/harness/opencode/testing/realDriver.test.ts::OpenCode against the real @opencode/cli binary::a step with two shell calls, one refused and one allowed: the reply to the sibling meets 404 and is read as the ask withdrawn — one ask_withdrawn note, no reply-failed error, no bypass on the server's own reject echo — and the server continues with the refusal and answers without a second prompt |
| 3: the relayed tools are served as declared, run in the bot under the run's context, joined by call id when a call outlives one request, and settled from the record after a generation died | [unit] src/core/harness/pi/relay.test.ts::relayedToolDefinitions::*, src/core/harness/pi/relay.test.ts::runRelayedTool — a native tool run in the bot for pi::*, src/core/harness/pi/relay.test.ts::relayToolCall: a relayed call that outlives one request::*, src/core/harness/pi/relay.test.ts::RelayedCalls.settle — a call in flight when the previous generation died::*, [unit] src/core/harness/conformance.test.ts::conformance — pi::relay: a relayed tool is served to the model under its own name… |
4: every event kind the harness emits has a disposition, the turn's events are the record's vocabulary, the turns are mirrored into ledger steps, and an unknown or impossible kind is a harness_error note naming it, said once per kind for the run | [unit] src/core/harness/pi/bridge.test.ts::PI_EVENT_DISPOSITION — every event kind pi's protocol documents is decided::*, src/core/harness/pi/bridge.test.ts::the bridge speaks the loop's vocabulary — the same turn, the same events::*, src/core/harness/pi/mirror.test.ts::*, src/core/harness/pi/bridge.test.ts::the notes — compaction, harness errors, dialogs, the unknown::an extension error, an unknown kind and an impossible kind are harness_error notes naming them…, [unit] src/core/harness/conformance.test.ts::conformance — pi::record: the run's events are the record's vocabulary…, ::record: an event kind the harness's table does not name…, [unit] src/core/harness/opencode/bridge.test.ts::OPENCODE_EVENT_DISPOSITION — every event the server streams is decided::*, ::projectStore — the store's messages as pi-shaped turns, the seed skipped::*, ::the gate's honest cannot, the compaction row, the budget stop, the unknown kind::*, [unit] src/core/harness/conformance.test.ts::conformance — opencode (fake serve, gate and record)::record: the run's events are the record's vocabulary…, ::record: an event kind the harness's table does not name… |
| 4: OpenCode session metadata updates carry opaque annotations; the bridge treats them as structure, emits no harness error or turn, and does not settle the execution | [unit] src/core/harness/opencode/bridge.test.ts::OPENCODE_EVENT_DISPOSITION — every event the server streams is decided::session.metadata.updated is structure under the pinned event vocabulary, not a failure or session ending |
5, 13: the wind-down owns the ending on every harness — a write-up whose last model call fails closes with the write-up's answer naming the failed call and a harness_error note, never as a failed model call, and the budget note says the run was on a model call when the clock ran out; pi's note carries the typed renderer sentence, while OpenCode keeps its provider words until the item-1 gap closes; the same row runs pi over its scripted double and OpenCode over the fake serve | [unit] src/core/harness/conformance.test.ts::conformance — pi::conversation: a write-up whose last model call fails ends with the write-up's answer and a harness_error note, src/core/harness/conformance.test.ts::conformance — opencode::conversation: a write-up whose last model call fails ends with the write-up's answer and a harness_error note, src/core/harness/opencode/bridge.test.ts::wind-down parity, an undelivered follow-up, and the alive-here reconciliation::doingNow: nothing before a step, the model call while a step is open, the open tools by name while they run, nothing once the execution settles |
| 5: every harness hands the run loop the ending that labelled its answer as one structured ending, and the finale answer composed over it with the loop's facts says the same words on pi and OpenCode for every branch the loop can establish — clean and pushed, salvaged, unpushed and kept, unpushed and torn down, the write-up's text | [unit] src/core/harness/conformance.test.ts::conformance — pi::conversation: the budget's ending is handed to the run loop as a structured ending…, src/core/harness/conformance.test.ts::conformance — opencode::conversation: the budget's ending is handed to the run loop as a structured ending…, src/core/harness/conformance.test.ts::conformance — pi::conversation: the budget's ending carries the write-up's text to the run loop…, src/core/harness/conformance.test.ts::conformance — opencode::conversation: the budget's ending carries the write-up's text to the run loop… |
| 5: the seed is the thread so far with the request as the prompt; a follow-up, the wrap-up and the write-up are steers; a hard stop ends the process | [unit] src/core/harness/pi/harness.test.ts::runPiHarness — a run on pi from the first file to the answer::a seed with the thread's earlier turns starts pi on a session…, ::a thread follow-up is steered into pi…, ::the wrap-up warning is steered once…, ::a hard stop aborts pi…, [unit] src/core/harness/conformance.test.ts::conformance — pi::conversation: the thread's earlier turns seed the process…, ::conversation: a thread follow-up is steered into the running process…, ::conversation: a hard stop ends the process… |
5: an operator's soft stop steers the write-up on every harness — one stopped note in mode soft, the model's next answer under the ⏹ label, no harness_error, the process ended; on OpenCode a relayed tool asked during that write-up is refused with the stop's words | [unit] src/core/harness/conformance.test.ts::conformance — pi::conversation: an operator's soft stop steers the write-up…, src/core/harness/conformance.test.ts::conformance — opencode::conversation: an operator's soft stop steers the write-up…, src/core/harness/opencode/bridge.test.ts::the loop — a refused request, a silent server, and a hung turn::a soft stop whose write-up comes answers under the ⏹ label with the write-up, and the relayed tools are refused meanwhile |
5, 13: a model call that never answers ends by the wind-down within the finale bound on every harness — the budget's note saying a model call was in flight, or the stop's note in mode soft; the write-up steered and never answered; the finale's card line; the call in flight aborted and the loop leaving without a settle; the process ended; the run answering the wind-down's reason-alone line — never a failed run, never a replaced verdict. On OpenCode the harness_error is the wind-down's note naming the finale bound (finaleAbortReason), the answer's clause names it too, one write-up steer and one interrupt are posted, and the server, its tailer and its root are ended as after any loop | [unit] src/core/harness/conformance.test.ts::conformance — pi::conversation: a model call that never answers ends by the wind-down within the finale bound…, ::conversation: a soft stop on a model call that never answers ends the same way…, src/core/harness/conformance.test.ts::conformance — opencode::conversation: a model call that never answers ends by the wind-down within the finale bound…, ::conversation: a soft stop on a model call that never answers ends the same way…, src/core/harness/opencode/bridge.test.ts::the loop — a refused request, a silent server, and a hung turn::the budget on a hung turn…, ::a soft stop on a hung turn ends the same way…, ::a write-up steer the server refuses is a harness_error at once, never swallowed, and the finale still ends the run by the wind-down |
5, 13: every answer to a request the OpenCode harness makes is read — the prime (the seed's import, the create), the prompt, a resume's continue, a follow-up turn's prompt — and an answer outside 2xx is a harness_error naming the request and the server's answer, said first, and the run's failure by that name (OpenCodeRequestRefusedError): one POST, no prompt after a refused prime, no wait on the feed, the process ended | [unit] src/core/harness/opencode/bridge.test.ts::the loop — a refused request, a silent server, and a hung turn::the prompt the server refuses fails the run by name at once…, ::a resume's continue the server refuses is named as the continue, ::the prime the server refuses — the seed's import, or the create of a seedless run — fails the run by name with a harness_error first, before any prompt, src/core/harness/opencode/harness.test.ts::the post-turn on the run's session — refused, answered by silence, or after a hung turn::refused: the turn throws OpenCodeRequestRefusedError… |
5, 13: an admitted queue prompt whose session starts no execution within FIRST_EVENT_BOUND_MS fails the run by name (OpenCodeSilentError) — the tailer's reconnect sweep (its note and the two refills for the session, as the real tailer writes them) and a server event that names no session lift nothing — with the diagnostics on the harness_error: the phase (the prompt, the continue, the follow-up turn's prompt), the session, the feed offset, the last feed record and the tails of serve.err and tailer.err; the interrupt is posted, the process ended, and no replaced verdict is taken | [unit] src/core/harness/opencode/bridge.test.ts::the loop — a refused request, a silent server, and a hung turn::an admitted prompt whose execution never starts within the bound fails the run by name with the diagnostics…, ::a resume's continue answered by silence names the continue, src/core/harness/opencode/harness.test.ts::the post-turn on the run's session — refused, answered by silence, or after a hung turn::answered by silence: the turn throws OpenCodeSilentError… |
5, 13: a post-turn after a hung turn — the loop ended at the finale, the aborted execution's tail landing only once the post-turn's prompt is posted, as the pinned binary ends an interrupted execution: the step failing aborted, the usage, then the settle or the failure and, after it, the refills — is read in the bridge's earlier mode and decides nothing of that tail (no reply posted, no bypass, no tool event on its record for a call this loop did not open — a call the loop-end cut left open settles there as its own result marked cut — the settle set aside, a failure noted as an earlier execution's — the proxy's turn-budget refusal by its own name and its 403, never a failed model call), surfaces what carries no decision (a tailer note on the card, an unknown event kind as a harness_error, the earlier execution's compaction as its note), waits for its own execution's start and answers its own text, with no harness_error beyond the wind-down's and the earlier failure's; the loop's span ended ok, the finale being the wind-down's ending; a tool the loop before cut at its end whose late outcome lands only after a post-turn's own execution has started is that execution's still, its assistantMessageID naming a step no loop of this session saw start, and its settle is set aside in own mode under a settle_set_aside note naming the call and the step, no bypass, no result, nothing handed turn to turn, the loop's own record keeping the call closed marked cut, and no harness_error at all (the cut is no failure); a late outcome that lands in the loop's own write-up execution, or rides the interrupted execution's tail before it, is the loop's own result, marked cut (the tail's let through in earlier mode as a cut call's, never dropped for a synthetic failure at the exit); the interrupted execution's interrupted end landing before the interrupt's answer or after the write-up's start is the cut's, set aside under a settle_set_aside note, its aborted step no harness_error, never the loop's settle — the write-up answers; the write-up's own failure when the cut's end was never serialized is the write-up's, the run closing by the wind-down's answer with the failure as its note, never set aside, never a finale run out; a tool whose ask the interrupt dropped fails aborted before it ran and lands marked cut with no harness_error and no reply posted; a hard stop requested in the round-trip and unread at the answer leaves the write-up unposted; a cut's interrupt never answered lets the finale bound end the wait, the wrap_up note and the unlabelled answer naming the finale, the record's harness_error naming the wait the bound ended — the cut tool, the interrupt unanswered — and no model call that failed, the cut call closed marked cut; a write-up prompt lost on its transport fails the run by name at once, no finale; an idle-answered execution ending on the proxy's budget refusal starts the write-up as a steer into the idle session, the write-up answering; a loop-end interrupt answered interrupted: false cuts nothing — no tool_cut note, the execution's own last text the answer, unlabelled, under a wrap_up note that the instruction was never posted and whether the execution finished or failed, a model call failing on the provider in the round-trip said in that answer, a straggler at the clean settle unmarked and not in flight; the write-up's own step failing aborted after the landing is an an OpenCode step failed note, never the cut's; a step begun during the interrupt's round-trip and cut by it fails aborted with no harness_error, the tool_cut note naming the model call the interrupt met; one the server refuses fails the run by name at once with no steer and no finale, the open call closed marked cut; a gate bypass in the write-up's execution after the cut words the cut call's closed result for that path; an ask answered from the permissions refill after a dropped stream teaches its step and opens the call from what it names, so the tool's settle is judged and recorded on an announced tool_call; in earlier mode the bridge itself replies to no ask, reads no bypass or settle, writes no tool event, answers no permissions refill, lands a compaction row and still feeds the mirror from a messages refill; catching up, a dead generation's execution failing is said by the bridge as history — a failed model call while the bot was away, or the proxy's turn budget reached while the bot was away | [unit] src/core/harness/opencode/harness.test.ts::the post-turn on the run's session — refused, answered by silence, or after a hung turn::after a hung turn: the loop ended at the finale…, ::a tool call cut at the loop's end: the budget note names it…, ::a tool that completes on its own while the loop-end interrupt is in flight…, ::an operator's hard stop landing while the loop-end interrupt is in flight…, ::a tool call cut at the loop's end whose write-up prompt the server refuses…, ::a tool call cut at the loop's end whose late outcome lands only during the first post-turn…, ::a tool call cut at the loop's end whose interrupt the server refuses…, ::a tool call cut at the loop's end whose interrupted execution's end the server serializes only after the write-up's execution has started…, ::a tool call cut at the loop's end whose interrupted execution's end the server serializes before it answers the interrupt…, ::a tool call cut at the loop's end while its ask was still pending…, ::the interrupted execution's end never serialized and the write-up's own execution failing on the provider…, ::an operator's hard stop requested while the loop-end interrupt is in flight and still unread when the interrupt answers…, ::a tool call cut at the loop's end whose write-up prompt fails on its transport…, ::a tool that completes on its own while the loop-end interrupt is in flight, whose execution then ends on the proxy's turn-budget refusal…, ::the hung tool completes during the interrupt's round-trip and the execution moves on to its next step…, ::a tool that completes on its own while the loop-end interrupt is in flight, whose execution then fails on the provider before the answer lands…, ::the write-up's own step failing…, ::a tool call cut at the loop's end whose interrupt is never answered…, ::a gate bypass in the write-up's execution after a loop-end cut…, ::a tool call cut at the loop's end whose own outcome rides the interrupted execution's tail…, ::a loop-end interrupt that cut nothing…, ::after a hung turn whose aborted execution then fails on the proxy…, ::after a hung turn whose aborted execution ends on the proxy's turn-budget refusal…, ::after a hung turn whose tail carries a dropped stream's note, an event kind no table names and a compaction…, src/core/harness/opencode/bridge.test.ts::the bridge's observing mode — an earlier execution's tail is not this loop's to decide::*, src/core/harness/opencode/bridge.test.ts::readStoreSince — the newest rows, page by page, down to what was there before::* |
5, 13: the interrupt an ending posts — refused by the server, a harness_error whenever the answer comes, the loop left or not, to the record alone once the loop has left and never to the closed card, the record open for it since the harness's end() kills the server and returns only once every request the loop posted has settled and the run finishes after end(); cut by the caller's kill after the loop left, no note, the record carrying the wind-down's harness_error alone; a soft stop requested once the budget's write-up is under way is one stopped note in mode soft, no second steer, the answer under the budget's label; a soft stop then a hard stop write two stopped notes, soft then hard, the hard stop's abort line the answer; the loop's run.agent span ends error on a failed model call | [unit] src/core/harness/opencode/bridge.test.ts::the loop — a refused request, a silent server, and a hung turn::the interrupt an ending posts that the server refuses is a harness_error whenever the answer comes…, ::the interrupt an ending posts that answers only once the caller's kill cuts it leaves no note…, ::a soft stop requested once the budget's write-up is under way is acknowledged…, ::a soft stop then a hard stop write two stopped notes, soft then hard…, src/core/harness/opencode/harness.test.ts::the post-turn on the run's session — refused, answered by silence, or after a hung turn::the run's span ends error on a failed model call, as the outcome says, ::a refused interrupt whose answer lands only as the process is ended is still the record's…, ::the stream drops as a step begins and the ask reaches the bot through the permissions refill alone… |
6, 13: a control reset under an OpenCode write is resolved from the server's own state, never re-sent blind — the feed re-attached in place under one resumed note; a queue prompt told landed by a user message with its text the loop did not know the store to hold and lost by none, re-issued once, the second admitted — the store read newest first down to the newest row known when the prompt was posted, one page on a session longer than one page, a steer landing after the prompt read past and never hiding it, and a steer this generation posted whose row carries the prompt's exact text known by the id its answer named (or, the answer cut by the reset or naming no id, learned from the store — at the step boundaries the feed delivers when an execution is under way, the ordinary timing, the run continuing — and the follow-up folded in, or handed back for a fresh turn when the idle marker is newest since the steer with no row of it — the store's word, never a count, and never steered again by this loop; the store unreadable, or the loop leaving with no row and the store still showing the execution under way, the run failing by name as for the prompt — a steer answered without an id included — with the batch's unposted follow-ups handed back), never read as the prompt landed; the prompt told landed recorded as the loop's own write by the row's id; a gate reply told landed by its ask gone from the pending asks (the tool's result on the record) and lost by the ask still pending, re-issued once, a 404 on the re-issue read against the pending asks again as item 2 reads one; a store or pending-asks listing that cannot be read, or a re-issue that meets the reset again, fails the run by name — OpenCodeWriteUnresolvedError for the prompt, OpenCodeReplyFailedError carrying it for a reply — with a harness_error naming the request and, for a reply, the interrupt posted | [unit] src/core/harness/opencode/harness.test.ts::OpenCodeHarness — the resident's control plane resets under a write::*; the re-issue's 404 read against the pending asks: ::a gate reply the reset cut, still pending at the re-list, re-issued once and answered 404 with the ask gone by then is the ask withdrawn…, ::a gate reply the reset cut, still pending at the re-list, re-issued once and answered 404 while the ask stays listed fails the run closed by name… |
5, 13: session.execution.failed settles the run — a model call that fails outside the wind-down fails the run by the provider's words at once, with nothing awaited past the failure; the fake serve fails an execution as the real server does (the failure event, the two refills, the store's idle marker, no session.idle) | [unit] src/core/harness/opencode/bridge.test.ts::the loop — a refused request, a silent server, and a hung turn::a model call that fails outside the wind-down fails the run by the provider's words at once… |
5, 13: the answer is the store row the execution's end promises — the tailer refills the store after session.execution.succeeded and interrupted, and the last step's own refill (the row carrying the answer) lands after the event too, so the loop settles on the refill stamped with the terminal reason (or on the tailer's note that this refill failed), read off the feed, never on the event alone and never on a timer; session.idle causes no refill and settles at once; only the loop's own end owes a refill — the dead generation's end replayed while catching up is discarded history and arms nothing; the fake serve writes the last step's refill and the terminal reason's after the terminal event, as measured against the binary | [unit] src/core/harness/conformance.test.ts::conformance — opencode::conversation: the answer is the store row the execution's end promises…, src/core/harness/opencode/bridge.test.ts::the loop — a refused request, a silent server, and a hung turn::the refill the execution's end owed fails in the tailer…, src/core/harness/opencode/bridge.test.ts::*::the dead generation's end, replayed while catching up, owes this loop no refill…, src/core/harness/opencode/testing/realDriver.test.ts::OpenCode against the real @opencode/cli binary::drives a run end to end…, src/core/harness/opencode/testing/realDriver.test.ts::OpenCode against the real @opencode/cli binary::a re-attach after a failed tool call imports… |
13: every model reference the harness sends — the create of a seedless run, the seed's import, a rebuild's import — names the configuration's one provider, switchboard, never the bot's provider name; the fake serve resolves the session's reference as the real server does — admitted at the create and at the prompt, the execution failing at once with Model unavailable: <provider>/<id> and no idle after it — so a harness naming the wrong provider hangs the table on a loop that waits for an idle and fails it by name on one that settles on the failure; the real binary's row carries the bot's provider name on the run's model, so the real resolver is the receipt that the reference the harness sends resolves | [unit] src/core/harness/opencode/harness.test.ts::the model reference on every request that carries one names the configuration's provider::a fresh run of one turn creates its session with switchboard/<id>…, ::the fake serve resolves the session's reference as the real server does…, [unit] src/core/harness/opencode/testing/realDriver.test.ts::OpenCode against the real @opencode/cli binary::drives a run end to end… |
13: a rebuild's import writes the session's own tool names — the record's bash/find back to OpenCode's shell/glob, a relayed tool's name kept — so the rebuilt session's history names the tools its own table holds and the first tool call after a rebuild runs; a call under a record word the identity holds otherwise (bash for shell) is refused by the server before anything runs and noted as the transient by the session's own name for the tool, never as the deny rules' doing | [unit] src/core/harness/opencode/session.test.ts::openCodeSessionToolName::maps the record's words to the session's own names…, ::openCodeStoreMessages — the seed as store messages::a relayed tool keeps its own name in the import…, [unit] src/core/harness/conformance.test.ts::conformance — opencode::survival: the first tool call after a rebuild runs…, [unit] src/core/harness/opencode/bridge.test.ts::a pre-execution settlement is narrated by what the facts prove (F2), and a call open when the container is replaced is settled on the record::a call under the record's word for a tool the identity holds (bash for OpenCode's shell) settled with no ask is a tool_refused note naming the transient… |
| 6: the facts on the row find the process alive, elsewhere or dead, and the record rebuilds it | [unit] src/core/harness/pi/harness.test.ts::runPiHarness — after a bot restart::*, src/core/harness/pi/harness.test.ts::runPiHarness — the container replaced under a live run::*, [unit] src/core/harness/conformance.test.ts::conformance — pi::survival: the row's facts name the harness…, ::survival: a resume whose facts name another container…, ::survival: a resume whose facts another harness wrote is refused… |
7: a row's facts are read by the shape the row names — pi's with or without the discriminator, the second harness's, no facts for a harness this build does not know or a shape missing a field — with unknown keys kept and relaunches read as 0 when absent | [unit] src/core/harness/contract.test.ts::harnessFactsOf — a row's facts, read by the harness that wrote them::* |
7: pi's object declares the tables the loop and the bridge already read; its open is the loop that exists — a scripted run through either door writes the same events, steps, facts and files — with the deployment's compaction thresholds behind it | [unit] src/core/harness/contract.test.ts::PiHarness — pi as the contract's object::declares pi's name, history, disposition table, effort map and built-in tools…, ::open is runPiHarnessOpen…, ::open carries the deployment's compaction thresholds into pi's settings… |
7: find preserves alive-here observations and another-harness disowning; foreign placement or sampled absence is typed uncertainty that cannot authorize ending or release; end ends the pid and removes the root the facts name, best-effort, and leaves another harness's facts alone | [unit] src/core/harness/contract.test.ts::PiHarness — pi as the contract's object::find holds foreign or sampled-absent original custody…, ::find: another harness's facts are another-harness with no container command at all…, ::end kills the pid and removes the root the facts name… |
7: pi's open keeps the refusal of another harness's facts as a defence — before anything is filed, started or registered, with a harness_error note and HarnessMismatchError naming both harnesses as an interruption | [unit] src/core/harness/contract.test.ts::PiHarness — pi as the contract's object::open refuses another harness's facts before anything is filed, started or registered… |
7: factsBelongTo is the seam's one comparison; a refused relaunch's interruption and the mismatch are both HarnessInterruptedErrors, read by the loop for the card's reason and by the dispatcher for the refusal token | [unit] src/core/harness/contract.test.ts::harnessFactsOf — a row's facts, read by the harness that wrote them::isPiFacts narrows the union to pi's shape; factsBelongTo is the seam's one comparison…, src/core/dispatch/runLoop.test.ts::the pi harness — the container replaced under a living bot: the relaunch ceiling::the worktree refused by name…, src/core/dispatch/runLoop.test.ts::the pi harness — the container replaced under a living bot: the relaunch ceiling::the third finding closes the run interrupted naming the bound… |
7: openThroughSeam refuses a foreign row before the harness is asked anything — a harness_error note, a progress line, HarnessMismatchError naming both harnesses, open never called — and opens the run on the harness otherwise, handing deps and run through untouched | [unit] src/core/harness/contract.test.ts::openThroughSeam — the seam's door::* |
7: relaunches and a key this build does not know survive a parse-and-rewrite round trip through a re-attach and through a restart on the transcript | [unit] src/core/harness/contract.test.ts::PiHarness — pi as the contract's object::relaunches and a key this build does not know survive a parse-and-rewrite round trip… |
7: the run stage opens every run through the seam's door (openThroughSeam) and names no harness; the source scan forbids pi's function by name in the run stage | [unit] src/core/harness/oneHarness.test.ts::one harness — …::the run stage has one loop: the harness object's open form… |
7, 8: a finish plan whose row carries OpenCode's facts is judged and ended by the OpenCode harness off the roster though the preset's word says pi — pi asked nothing, no process started, the post-steps run with the answer; a judge that answers another-harness for the row it was picked for ends nothing and says so in a resumed note naming the row's word and the judge; a resume mid-loop whose row carries OpenCode's facts opens on the OpenCode harness with the row's facts as its resume, pi never opened, and the run completes on OpenCode's answer | [unit] src/core/dispatch/runLoop.test.ts::a resume with the answer in hand …::a … plan whose row carries OpenCode's facts is judged and ended by the OpenCode harness off the roster…, ::a … plan whose judge answers another-harness…, ::a resume mid-loop whose row carries OpenCode's facts opens on the OpenCode harness off the roster… |
8: the roster's words are one list — HARNESS_NAMES equals the facts' discriminator by type and reads pi, opencode; DEFAULT_HARNESS is pi — isHarnessName admits those words and nothing else; HARNESS_SCOPES reads user, channel, defaults; harnessNamed picks the resolved word off the roster and pi for none, and harnessForPreset makes the same pick for one layer's words | [unit] src/core/harness/roster.test.ts::the harness roster — the names, the default and the pick::* |
8: the harness block parses a mapping of presets to the roster's words and an absent block leaves the field unset; an unknown preset, a word that is not a harness (codex, native, a case slip, a non-string) and a non-mapping fail the load by name, naming the two harnesses | [unit] src/config.test.ts::harness block (harness.<preset>: pi or opencode)::* |
8: the same words under channels.<id>.harness and users.<id>.harness resolve user > channel > the deployment's block per preset, each naming its scope, an unset layer falling through and no layer yielding no key; runtime overrides set, win over the static word, persist and clear; a bad word, an unknown preset and a non-mapping under a scope are refused at load naming the path and both harnesses, a scope that is not a mapping (a scalar, a list) refused by name before its harness is read, defaults.harness refused pointing at the block, and a stored overrides document is held to the same rule naming the backing; config show renders the effective harness per named preset with its scope | [unit] src/config.test.ts::harness as a scope setting (users.<id>.harness, channels.<id>.harness)::* |
8: config set me --harness.<agent> opencode moves one person's runs of that preset and nobody else's, shows with its scope, clears with config clear me; the channel form rides config:write; a word that is not a harness is refused by the schema naming both, an unknown preset by the handler, neither echoing the value | [unit] src/core/commands/config.test.ts::config set --harness.<agent> and config show's effective harness::* |
8: the opencode block parses compaction.buffer and compaction.keepTokens as positive integers, either alone, an empty compaction block, and an absent block leaves the field unset; any other value, a non-mapping and an unknown key at either level — pi's words included — fail the load by name | [unit] src/config.test.ts::opencode block (opencode.compaction.buffer, opencode.compaction.keepTokens)::* |
8: harness: { general: opencode } opens a fresh general run on the OpenCode harness off the roster; a preset the block does not name, a preset worded pi, and no block at all open on pi; the picked object is the only one opened and is handed no facts | [unit] src/core/dispatch/runLoop.test.ts::the configuration word — harness.<preset> picks a fresh run's harness off the roster::* |
| 8: the word through the scopes at the loop — the deployment's block alone opens a general run on OpenCode, the channel's word beats the deployment's, the user's beats the channel's, a user's word for another preset falls through to the channel's, no word anywhere opens on pi; the picked object is the only one opened and is handed no facts; two requesters in one process open the same preset on different harnesses off one roster; a resume whose row carries pi's facts opens on pi with them though the requester's own scope says opencode now, OpenCode never opened | [unit] src/core/dispatch/runLoop.test.ts::the harness word through the scopes — user beats channel beats the deployment's block::*, src/core/dispatch/runLoop.test.ts::a resume with the answer in hand …::a resume mid-loop whose row carries pi's facts opens on pi with the row's facts… |
8: run_meta.harness is the word's pick for the fresh run — opencode for a coding run under harness: { coding: opencode }, pi for a general run under the same block and for every run without one; a process without a roster names none | [unit] src/core/dispatch/provision.test.ts::registerRun — the run's row on every surface before the attach::run_meta carries the harness object's name when the process has one, and no harness field without |
8, 10: run_meta.harnessScope names the scope whose word picked the harness — user under users.<id>.harness, channel under channels.<id>.harness, defaults under the top-level block — and is absent when no layer named the preset; the timeline fold keeps harness and a scope the roster knows and drops any other; the run page's facts bar reads opencode harness (user scope) | [unit] src/core/dispatch/provision.test.ts::registerRun — the run's row on every surface before the attach::run_meta names the scope whose word picked the harness — user, channel or defaults — and no scope when no layer named the preset, src/channels/runTimeline.test.ts::createRunTimeline — run_meta (item 19)::keeps \harness` and a known `harnessScope`, and drops a scope that is not one of the roster's, web/src/pages/runPage.test.ts::RunPage — history mode::shows the run meta line: agent · model · effort · linked repo · the branch linked to its tree · the head sha linked to its commit · GitHub-marked PR; a hostile repo never links` |
8, the precondition: under harness: { coding: opencode } a coding run opens on the roster's OpenCode over the fake serve and, the container replaced with a bash call in flight, is relaunched from the record in the replacement — nothing killed or removed for the old server, the workspace re-attached, the bearer rotated with the meter kept and the old secret refused, the row's facts OpenCode's with relaunches: 1, the new container and the new hash, one sandbox_restarted and one resumed note, the in-flight call's tool_result carrying the replaced note, the replacement's store importing the record with that settlement — and the run completes on the continuation; pi is never started | [unit] src/core/dispatch/runLoop.test.ts::the OpenCode harness — the container replaced under a living bot, reached through the configuration word::* |
8: a resume whose row names a harness this build does not know is rebuilt on the preset's harness, opened with no facts, nothing judged or ended, and one resumed note names the word, the pid and the container as neither judged nor ended here and the harness the run was rebuilt on; a finish with such a row runs its post-steps with the same note, the pid and container unknown when the row did not record them | [unit] src/core/dispatch/runLoop.test.ts::a resume with the answer in hand …::a resume whose row names a harness this build does not know is rebuilt on the preset's harness… |
8: the roster is the wiring's — src/index.ts and src/cli.ts construct both harnesses by class — the run stage imports no harness class and constructs none, and the agent registry exports no roster, no names and no pick | [unit] src/core/harness/oneHarness.test.ts::one harness — the native loop, both provider adapters and the native tool table are gone (harness-pi.md item 1)::the roster lives in the process wiring…, ::the run stage has one loop…, ::no preset declares a harness, and the registry exports no table of harnesses |
7: a finish plan's leftover is ended through the object in the container the facts name, and retains the workspace when original placement is unknown while publishing the saved answer without another producer | [unit] src/core/dispatch/runLoop.test.ts::a resume with the answer in hand …::on the pi harness no pi is started and the one the previous generation left is ended at its recorded pid and root…, ::on the pi harness a foreign original finish… |
| An OpenCode follow-up records its user request, tool exchanges and final answer after the prior conversation, so a completed post-turn survives a checkpoint or process failure. | [unit] src/core/harness/opencode/harness.test.ts::hosted Review originating lifecycle::binds a fresh same-session follow-up check to that turn's narrower clock… |
| Both harnesses keep the saved seed independent of caller array edits, and pi journals every post-turn before teardown. Successor review clocks reserve no initial-loop allowance again; the clock survives the durable launch intent and normal initial loops retain their reserves. | [unit] src/core/harness/pi/harness.test.ts::runPiHarnessOpen — the session stays open for one more turn::records the follow-up after its original seed…, ::a successor retains all…; src/core/harness/opencode/harness.test.ts::the post-turn on the run's session — refused, answered by silence, or after a hung turn::a successor remains able to use tools… |
7: the dispatcher runs the request again after a mismatch, as after a refused relaunch, with the refusal harness_mismatch | [gap] The refused relaunch's path is proven through dispatch() (harness-pi.md item 16, the refusal workspace_lost). The mismatch is reachable only through openThroughSeam from a caller that is not the loop (the loop picks a resumed row's harness by the row's own word, item 8), proven at the seam (src/core/harness/contract.test.ts, the door's refusal and its HarnessInterruptedError shape); the loop's own path for a row it cannot judge is the named rebuild of item 8, so no dispatch-level test of the mismatch's restart exists. |
| 9: the start captures birth identity and PID through a dedicated pipe closed before the program begins, with the detached wrapper's stdio redirected to /dev/null so model code retains none of the exec's descriptors (execution.md item 24); another program with no filter carries no grep; a shell fragment as the program is refused | [unit] src/core/harness/container.test.ts::harness launch identity::*, src/core/harness/container.test.ts::the container scripts::another program with no filter carries no grep… |
9: a start that names a port exports it first and says it on the first line, picked in the container with node for free or as given, the placeholder among the arguments becoming the variable, and the placeholder with no port named refused by name; the exec container reads the port from the first line and the pid from the last, and a port that did not come back is a named failure | [unit] src/core/harness/container.test.ts::the container scripts::a start that names a port exports it first…, src/core/harness/container.test.ts::ExecHarnessContainer — each operation is one command over the executor::a start that names a port reads it from the first line… |
9: a request is curl into loopback with --max-time under the executor's timeout, the body on stdin or from a file, never -f, its parts checked, a secret header's value in the exec's env and never the command text; the answer's status, lowercased headers and body are parsed with a 1xx skipped; over the executor a 2xx and a 5xx parse alike — a 200 whose body carries the runtime word is that 200 — and the container-gone word is rethrown | [unit] src/core/harness/container.test.ts::the container scripts::a request is curl into loopback…, ::parses curl's answer…, src/core/harness/container.test.ts::ExecHarnessContainer — each operation is one command over the executor::request runs curl over the executor… |
9: identity rethrows the executor's typed word that the container is gone, and the seam's own; isContainerGone knows both | [unit] src/core/harness/container.test.ts::ExecHarnessContainer — each operation is one command over the executor::identity rethrows the executor's typed word…, src/core/harness/container.test.ts::stdoutOf — an executor's answer as the operation's stdout::runtime words in stdout are data; typed replacement errors remain the replacement condition |
9: makeRoot answers the root the harness proposes on the exec container, and a root made beside it on the bot host, another harness's prefix included | [unit] src/core/harness/container.test.ts::ExecHarnessContainer.makeRoot::*, src/core/harness/botHostContainer.test.ts::BotHostHarnessContainer: the seam is harness-neutral in fact::makes the root beside whatever root the harness proposes… |
9: the bot host starts the program it is given with no filter when none is named, hands a start that asks for a free port one from the host with the placeholder and the environment filled and a given port passed through, refuses the placeholder with no port named before it makes anything, and reaches a loopback server with a bounded fetch carrying a secret header as a header, a port nothing listens on or a server that does not answer in time a named failure | [unit] src/core/harness/botHostContainer.test.ts::BotHostHarnessContainer: the seam is harness-neutral in fact::starts the command it is given, not pi…, ::a start that asks for a free port is given one from the host…, ::request reaches a server on the host's loopback… |
9: a finish plan whose container is gone under find ends nothing, notes it and completes with the answer | [unit] src/core/dispatch/runLoop.test.ts::a resume with the answer in hand …::…plan whose container is gone under the question… |
| 9: the harness over the seam is unchanged — pi's files, its start, its log, its re-attach and its death through the fake and the scripted double | [unit] src/core/harness/pi/harness.test.ts::runPiHarness — a run on pi from the first file to the answer::*, src/core/harness/pi/transport.test.ts::* |
10: run_meta carries the harness object's name when the process has one, and no such field without | [unit] src/core/dispatch/provision.test.ts::registerRun — the run's row on every surface before the attach::run_meta carries the harness object's name…, src/core/dispatcher.test.ts::live run-view wiring (Area 2)::publishes the request as a redacted … event before any tool event, with an attachment suffix |
| 11, 1 to 6: every clause is one or more rows of one conformance table run through one driver interface against every harness the tree has, pi over the fake container and the scripted double; pi passes every row | [unit] src/core/harness/conformance.test.ts::conformance — pi::* |
| 11: the table holds every clause and the parity rows under unique ids; the lint refuses a row whose check read neither the run events nor the ledger steps and passes one that read either | [unit] src/core/harness/conformance.test.ts::the table::holds the six clauses…, ::the lint: a row whose check reads neither the run events nor the ledger steps is refused by name… |
11: a limit a harness declares is asserted, never skipped: a declared row's run must fail (the verdict cannot), a declared row that passes is a failure naming the stale declaration, an undeclared failure is fail, and the matrix prints the declared cell with its reason beneath the table | [unit] src/core/harness/conformance.test.ts::the table::a declared cannot is asserted, never skipped… |
| 11: the matrix prints every harness × row, pi green on every row, a harness without a driver absent, and the script prints the same table | [unit] src/core/harness/conformance.test.ts::the table::the matrix prints every harness × row… |
11, a second harness: the same table passes for a second implementation's driver with none of pi's hooks or files, over a fake serve driving the real OpenCodeHarness and against the real @opencode/cli binary; removing one clause's behaviour fails the suite once per clause | [unit] src/core/harness/conformance.test.ts::conformance — opencode::* (the full table, the real OpenCodeHarness over the fake serve), ::conformance — opencode: the six mutation rows (each clause switched off fails its row)::*, [unit] src/core/harness/opencode/testing/realDriver.test.ts::OpenCode against the real @opencode/cli binary::drives a run end to end… (credential, gate, relay, record, conversation against the real binary, and the id-join receipt). The inject-only rows — a tool run with no ask, a forged reply — no external process can produce; they are the fake serve's, and the real binary confirms the join the detection rests on. |
11, OpenCode's gate and record (U11): the gate and record rows pass for OpenCode's driver over the fake serve, every tool call decided in the bot over the HTTP ask; the gate's honest cannot is enforcement by detection — an effect the bot did not decide fails the run closed, and the note names which of the four it saw: a call with no ask, a reply the bot did not send (one for an ask never decided, or a second for one it did), a reply that differs from the bot's decision, a success after the bot's refusal — so the bot's decision is not final by construction, its one declared cell (the loop-end tool cut it owed — decision 0046's unit seven, its OpenCode half — is green since the bridge interrupts the hung step and queues the write-up, item 13); a reply the bot cannot post stops the run by name rather than leave the ask hanging; the two P2 walls (a per-run credential scoped to the run's branch; the harness process and the model's shell as different users) are the gap rows below | [unit] src/core/harness/conformance.test.ts::conformance — opencode (fake serve, gate and record)::the matrix shows OpenCode green on every gate and record row against the fake serve, with the declared cannot cells, ::gate: the bot's decision is final by construction…, [unit] src/core/harness/opencode/bridge.test.ts::the gate's honest cannot, the compaction row, the budget stop, the unknown kind::a forged \once` for an ask the bot rejected — the effect differs from the bot's recorded decision — is a bypass, ::a permission.replied the bot did not send — one that raced ahead of the bot's decision, for an ask it never saw — is a bypass (a forged approval), ::a second permission.replied for the same request id — a duplicate after the bot's echo — is a bypass, ::a tool success for a call the bot rejected ran against the reject and is a bypass; the rejection's own failure is not, ::the loop — a reply that cannot be posted, and the narration's timing::, ::parity with pi — the mirror and the friction analyzer read OpenCode's record as they read pi's::` |
6, the ceiling on pi: a container replaced under a living bot relaunches pi from the record in the new container — nothing probed, ended or removed for the old process, the workspace re-attached, the bearer rotated with its meter kept and the old hash refused, one resumed note, relaunches = 1, the run completed as the one run it was; the worktree refused by name and the third finding close the run interrupted (the latter naming the bound, no fourth start) with a second sandbox_restarted note saying why and the request run again, and the row learns the binding each relaunch re-attached on; a row write that throws inside the rotation relaunches nothing | [unit] src/core/dispatch/runLoop.test.ts::the pi harness — the container replaced under a living bot: the relaunch ceiling::*, src/core/dispatcher.test.ts::run ledger write-through …::a live pi run whose resident container is replaced under it is relaunched in the replacement…, ::a relaunch whose re-attach the resident refuses…, ::the roll order every deploy has… |
| 6, the ceiling's steps by name: the bound, a row without facts, an own-store harness and a bearer that cannot be rotated refused with nothing written; the worktree refused before the rotation with the run's bearers standing; the rotation writing the row once with the new hash and the count and handing back the resume — the record, the budget left from the deadline, the rotated facts, the two containers' words — and the re-attached round; a row write that throws propagating with both secrets verifying | [unit] src/core/dispatch/relaunch.test.ts::* |
6, the ceiling's first gate: a recorded binding re-attaches mid-run with no gate context — the same round back, a foreign backend refused by name — and pi starts again in a replacement container from a session rebuilt from the ledger's rows, the call in flight settled; and the ledger after that rebuild holds the settlement turn, a result for every call. Passed in the fakes, which prove the seam composes; the resident's reuse: true re-attach onto a rolled container is proven only by the live row (16, live in harness-pi.md), owed before stage A closes | [unit] src/core/dispatch/runLoop.test.ts::the relaunch ceiling — the mid-run re-attach spike (the record's first gate)::* |
6, the record across two deaths: a process rebuilt from the record with a call in flight writes the settlement turn onto the ledger as its first step's user turn from the seed index, with the continue's echo, and the supported protocol projection uses those same rows — every harness, through the conformance table; on pi the record a second replacement carries equals the resumed transcript plus the ledger's rows with a result for every call, the session's tool results are the ledger's, and across the roll order every release has (a relaunch, then a bot death with pi inside its next call) planResume over the ledger yields a result for every tool_use and its bot-side settlement projection preserves those results; unverified third-container continuation remains held and claims no native model restoration | [unit] src/core/harness/conformance.test.ts::conformance — pi::survival: a process rebuilt from the record with a call in flight writes the settlement turn onto the ledger: the next step's rows are the settlement results with the continue's echo as one user turn from the seed index, then the assistant turn — and the supported protocol projection uses those same rows, so the record rebuilds a transcript with a result for every call at the next death, src/core/harness/pi/harness.test.ts::runPiHarness — the relaunch in the replacement container::the record and the ledger agree across a relaunch…, src/core/harness/pi/harness.test.ts::runPiHarness — after a bot restart::the explicit replacement protocol rebuilds the transcript…, src/core/harness/pi/mirror.test.ts::PiMirror — the rows it wrote, kept for a relaunch::prime puts a rebuilt session's settlement turn before the next step's user content…, src/core/dispatch/runLoop.test.ts::the pi harness — the container replaced under a living bot: the relaunch ceiling::two deaths preserve the relaunch transcript… |
| 6, OpenCode's rebuild is an import: a process rebuilt from the record with a call in flight imports the record into a fresh store AND writes the settlement turn onto the ledger, so the store rows, the ledger rows and the model's view agree | [unit] src/core/harness/conformance.test.ts::conformance — opencode::survival: a process rebuilt from the record with a call in flight writes the settlement turn onto the ledger… (the shared row all drivers run; OpenCode's import folds each settlement into the store as an error tool content, and OpenCodeBridge.prime writes it as the ledger's first step's user turn). |
6, a re-attach after a failed tool call imports: every error-state tool content the rebuild authors — a result the record marked an error, a call in flight settled by its note — carries the error: { type, message } OpenCode's session-message schema requires of that state (Session.StructuredError), typed in OpenCode's own words (tool.execution for a tool that ran and failed, aborted for one cut by the death), so the import of a record holding a failed call is accepted and the run continues from it; the scripted double refuses a part without them as the binary does (400 InvalidRequestError, Missing key at …), so a body the fake takes is one the binary takes | [unit] src/core/harness/opencode/session.test.ts::openCodeStoreMessages — the seed as store messages::a call whose following result the record marked an error becomes an error tool content typed as the tool's own failure…, src/core/harness/opencode/session.test.ts::openCodeStoreMessages — the seed as store messages::a call in flight at a death (no following result) carries the settlement note in its tool content, src/core/harness/conformance.test.ts::conformance — opencode::survival: a re-attach after a failed tool call imports…, src/core/harness/opencode/testing/realDriver.test.ts::OpenCode against the real @opencode/cli binary::a re-attach after a failed tool call imports… (the real server decodes the import against its schema; the row is what the double's refusal was measured against). |
6, the ceiling on OpenCode: a container replaced under a living OpenCode run is driveOpenCode's own container-gone read (saysContainerReplaced on the feed read) — the open call's span ended and put on the record as a failed tool_result carrying the replaced note, the record built as pi's is (the seed or resumed transcript the base, the mirrored rows through projectStore, the compactions, the last turn's calls settled, the counters, the deadline), a sandbox_restarted note naming both containers' words, and OpenCodeContainerReplacedError(message, said, was, now, record) thrown with nothing killed or removed in the container that answers now — so prepareRelaunch re-opens open with the record, taking the run's registration over with registry.replace (its relayed calls kept — the same calls object, a still-running call in flight and never re-run), probing and ending nothing at the row's pid, port or root, importing the record with the in-flight calls settled, carrying the relaunch count onto the row with the new pid and container, one relaunched after the container was replaced note (src/core/harness/opencode/harness.test.ts::OpenCodeHarness — the relaunch in the replacement container, and a resume whose server is gone::a relaunch takes the run's registration over with its relayed calls kept…). The end-to-end proof through the run loop — a living bot, the container replaced with a call in flight, OpenCode relaunched from the record, the run completed — is the configuration word's precondition and is bound on item 8's row below, since it needs the word to configure a run on OpenCode. The neutral row asserts both the RECORD's settlement (the last assistant turn's calls, the note in the result's place — what prepareRelaunch rebuilds from) and the run's own tool_result event of it — the one failed result the call gets, carrying the replaced note — because both drivers hold the call open at the replacement: the fake serve plays the ask and the bot's reply, then stops before the result; pi's scripted double is told to leave the call in flight (holdCallOpen), so the strong case is the one every harness runs | [unit] src/core/harness/conformance.test.ts::conformance — opencode::survival: the container is replaced with a tool call in flight: the run fails with the seam's container-replaced verdict carrying the record the loop's relaunch rebuilds from — the mirrored transcript with the in-flight call settled by the replaced note — a sandbox_restarted note names both containers' words, the in-flight call is on the record as a failed tool_result carrying the note, and nothing is killed or removed in the container that answers now (the shared row every driver runs), src/core/harness/opencode/bridge.test.ts::a pre-execution settlement is narrated by what the facts prove (F2), and a call open when the container is replaced is settled on the record::closeOpenSpans settles every call still open with the replaced note: each is a failed tool_result on the record carrying the note, and none is left open |
6, one more command before the crash judgement: a process found dead with a call in flight and no command having failed with the executor's word takes one container command before judging — that command failing with the word is the executor's word (the seam's verdict by type, said the word, condition tagged word); that command answering another identity than the one recorded when the process started is the verdict by the changed identity (said nothing, condition tagged identity, the sandbox_restarted note carrying the identity's sentence in the words' place); either with the in-flight call settled on the record and failed on the stream with the replaced note, and nothing killed or removed; that command answering the recorded identity leaves the crash judgement standing — no verdict, no sandbox_restarted note, the process ended and its root removed — every harness through the conformance table; the seam's helper alone judges the word, the changed identity, and no verdict for the same word, a word missing on either side or a command that failed otherwise; the tag's invariant — words present exactly when the tag is not identity (word and the resident's transport carry the command's words) — refused at construction; OpenCode end to end against the fake serve, the same-word death keeping its crash with the server and its tailer ended | [unit] src/core/harness/conformance.test.ts::conformance — pi::survival: the process is found dead with a tool call in flight and no command has returned the executor's word…, ::survival: the process is found dead with a tool call in flight, no command has returned the executor's word, and the one more container command answers another identity…, ::survival: the process is found dead with a tool call in flight, no command has returned the executor's word, and the one more container command answers the identity recorded…, src/core/harness/conformance.test.ts::conformance — opencode::survival: the process is found dead with a tool call in flight and no command has returned the executor's word…, ::survival: the process is found dead with a tool call in flight, no command has returned the executor's word, and the one more container command answers another identity…, ::survival: the process is found dead with a tool call in flight, no command has returned the executor's word, and the one more container command answers the identity recorded…, src/core/harness/container.test.ts::replacedVerdict — one more container command before a dead process is judged to have died where it ran::*, src/core/harness/contract.test.ts::HarnessContainerReplacedError — the condition's tag and the words it carries::*, src/core/harness/opencode/bridge.test.ts::an OpenCode found dead before any command returned the executor's word — one more container command before the crash judgement::* |
6, the third failure shape — a container command that fails on its transport with no word takes the one more command too: the word on it is the verdict by the word, a changed identity the verdict by the identity (each with the record, the in-flight call settled and failed on the stream with the replaced note, one sandbox_restarted note, nothing killed or removed), the recorded identity calls for a probe of the recorded PID: a live process re-attaches at the last consumed record with no second process, while a proven dead one leaves the original transport error standing (no verdict, no sandbox_restarted note, a harness_error naming the negative judgement); an ambiguous probe fails explicitly and never authorizes relaunch, including on a resident (harness-pi.md item 16; pi's rule — OpenCode's bridge still fails by name there); and the one more command waits through a container that is down — the not-running answer from the probe itself re-sent after the executor's backoff until the container answers, the notes saying the wait began and how long it took, never a judgement — every harness through the conformance table; the seam's helper alone judges the shape — by the executor's typed waitable reason first, on the error or in its cause chain, then by the container-down words (the SDK's Network connection lost among them) or its own typed down answer for an answered or untyped failure; never the word, a control file lost, a command that failed as a command, or a typed refusal whatever its words — the live shape typed and untyped taking the one more command and a typed refusal failing by name at once, throws the down answer typed from identity, and bounds the wait by the start gate's own constants on the harness's clock — wall-clock time from the wait's start, a hanging probe counted, one command's overshoot at most — running out with no verdict; the wait observes the run — the hard-stop signal ends it at once mid-pause, the deadline before a re-send that would pass it, each said in the note — and the run then ends as the stop (the abort line as the answer, one stopped note in mode hard, no verdict) on every harness; under the one more command alone an infra failure that reached no container is a down answer to wait on, while identityOrNothing names nothing for it outside; the type decides first — a typed refusal is no name even when its words are the container's, an answered or untyped failure is read by the words; one restore is one wait of this bound whatever route the resident answered it by — the hydrate path's 503 and the wake path's strike on a still-restoring resident re-send through the same pauses and decide the same; the platform's gone-for-a-moment wording is composed from the resident client's one list | [unit] src/core/harness/conformance.test.ts::conformance — pi::survival: the in-flight container command fails on its transport with no word, the one more command finds the container not running, and a hard stop is requested while it is down…, src/core/harness/conformance.test.ts::conformance — opencode::survival: the in-flight container command fails on its transport with no word, the one more command finds the container not running, and a hard stop is requested while it is down…, src/core/harness/container.test.ts::replacedVerdict — the one more command waits through a container that is down (the restore window), bounded like the start gate::the bound is wall-clock time from the wait's start…, ::the wait observes the run…, src/core/harness/container.test.ts::ExecHarnessContainer — each operation is one command over the executor::identityOrNothing is the name for the record…, src/core/harness/container.test.ts::ExecHarnessContainer — each operation is one command over the executor::identity throws the container down under the question…, src/execution/execInfraReason.test.ts::*, src/core/harness/container.test.ts::replacedVerdict — the one more command waits through a container that is down (the restore window), bounded like the start gate::a sleep that rejects ends the wait with that failure…, src/execution/residentWake.test.ts::isContainerRolling: the refusals that name a container gone for a moment::the platform's gone-for-a-moment wording is one exported list…, src/core/harness/pi/harness.test.ts::runPiHarness — the container replaced under a live run::the wait observes the run…, src/core/harness/opencode/bridge.test.ts::an OpenCode whose container command fails on its transport with no word — the one more command runs here too, and waits through a container that is down::the wait observes the run…, src/core/harness/conformance.test.ts::conformance — pi::survival: the in-flight container command fails on its transport with no word (the platform kills the container under it and the WebSocket closes with 1006 before any word) and the one more command fails with the word…, ::survival: the in-flight container command fails on its transport with no word and the one more command answers another identity…, ::survival: the in-flight container command fails on its transport with no word and the one more command answers the identity recorded…, ::survival: the in-flight container command fails on its transport with no word and the one more command finds the container not running…, src/core/harness/conformance.test.ts::conformance — opencode::survival: the in-flight container command fails on its transport with no word (the platform kills the container under it and the WebSocket closes with 1006 before any word) and the one more command fails with the word…, ::survival: the in-flight container command fails on its transport with no word and the one more command answers another identity…, ::survival: the in-flight container command fails on its transport with no word and the one more command answers the identity recorded…, ::survival: the in-flight container command fails on its transport with no word and the one more command finds the container not running…, src/core/harness/container.test.ts::saysTransportLost — the third failure shape: a container command failed on its transport with no word::*, src/core/harness/pi/harness.test.ts::runPiHarness — the container replaced under a live run::the live shape, typed…, ::the live shape, untyped…, ::a typed refusal or an answered failure whose words are not the container's is NOT the third shape…, src/core/harness/container.test.ts::replacedVerdict — the one more command waits through a container that is down (the restore window), bounded like the start gate::*, src/core/harness/container.test.ts::ExecHarnessContainer — each operation is one command over the executor::identity throws the container down under the question…, src/core/harness/opencode/bridge.test.ts::an OpenCode whose container command fails on its transport with no word — the one more command runs here too, and waits through a container that is down::* |
6, the replaced word never outranks a live process: the executor says replaced while the row's recorded pid still answers alive — the harness re-attaches in place, records the disagreement in one resumed note (the executor said replaced; the row's pi answers alive in this container; re-attached), the run answers, relaunches untouched and one process, never the verdict; on both drivers | [unit] src/core/harness/conformance.test.ts::conformance — pi::survival: the executor says replaced while the recorded pid still answers alive…, ::conformance — opencode::survival: the executor says replaced while the recorded pid still answers alive… |
6, cold-sandbox transport recovery: an /exec Network connection lost. with a confirmed unchanged container identity and recorded PID still alive is not a replacement — both harnesses re-attach from the last consumed log record, the final answer is delivered once, no second model call or sandbox_restarted note, relaunches unchanged; a repeated loss with no record hits the in-place bound, never a relaunch beside a live process; a lost write resolves through pi's response id or OpenCode's server store and never re-sends a prompt whose outcome is still unknown; a missing recorded identity, missing answer or failed identity probe leaves liveness unresolved even if a replacement reused the recorded PID, and a down/ambiguous liveness probe observes the run's stop and deadline and fails by name when it cannot prove safety; changed identity or an executor word with a proven dead PID alone authorize the durable relaunch | [unit] src/core/harness/conformance.test.ts::conformance — pi::survival: a cold sandbox loses /exec with Network connection lost while the recorded pid stays alive…, src/core/harness/conformance.test.ts::conformance — opencode::survival: a cold sandbox loses /exec with Network connection lost while the recorded pid stays alive…, src/core/harness/conformance.test.ts::conformance — pi::survival: repeated /exec loss with a live recorded pid…, src/core/harness/conformance.test.ts::conformance — opencode::survival: repeated /exec loss with a live recorded pid…, src/core/harness/pi/harness.test.ts::runPiHarness — the resident's control plane reset under a live pi::a cold sandbox loses /exec while a prompt write is in flight…, src/core/harness/opencode/harness.test.ts::OpenCodeHarness — the resident's control plane resets under a write::a live server's prompt POST loses /exec after landing…, ::an unresolved prompt POST after /exec loss fails without a second delivery, src/core/harness/reattach.test.ts::classifyTransportLoss — a cold sandbox's lost exec is not a dead process::*, src/core/harness/conformance.test.ts::conformance — pi::survival: a cold sandbox loses /exec and the identity probe returns no name…, src/core/harness/conformance.test.ts::conformance — opencode::survival: a cold sandbox loses /exec and the identity probe returns no name…, src/core/harness/conformance.test.ts::the table::unknown identity refuses a faulted read even when the final output is already buffered |
| 6, resume naming this container: a resume whose row names the container this run holds probes the recorded port before anything is started — with the row's password when the row carries a bearer hash — and re-attaches onto a server that answers it (the row below); a server that answers but cannot be re-attached (no bearer hash on the row, the password refused, another version than the pin, the session refused, a store that never ends, the feed unreadable from the row's offset) retains its original producer, tailer, root, feed, session and pointer under typed unconfirmed custody, with no cleanup, new launch or workspace release; a row whose server does not answer or names another container retains original custody with no ending, deletion, new producer or new facts | [unit] src/core/harness/opencode/harness.test.ts::OpenCodeHarness — the re-attach onto a still-answering server::a server that answers but…, src/core/harness/opencode/bridge.test.ts::wind-down parity, an undelivered follow-up, and the alive-here reconciliation::a resume naming this container whose answering server refuses the session retains original custody without a fresh start, src/core/harness/opencode/harness.test.ts::OpenCodeHarness — the relaunch in the replacement container, and a resume whose server is gone::a resume without a recorded server response…, [unit] src/core/harness/conformance.test.ts::conformance — opencode::survival: a resume whose facts name this same container and carry the bearer hash re-attaches to the live process…, ::survival: a resume whose facts name this same container but whose process no longer answers here takes the dead-process path exactly… (the shared rows every driver runs: the alive-here row hands the row's bearer hash, so both drivers re-attach onto the live process — no second one started, the live one ended only at the session's end — pi over the scripted double playing an already-running pi, OpenCode over the fake serve answering the row's port with the hash as its password; the re-attach's own detail is the row below) |
6, OpenCode re-attach: a resume whose OpenCode still answers in this container with the row's bearerHash as its password re-attaches onto it rather than ending it — no second server, the row's bearer adopted, the store read back and the mirror aligned past the ledger's rows so the in-flight call's result lands as the next step's user turn and nothing of the transcript is written twice, the relayed call in flight answered from the record when the plugin asks again and never re-run, the continue steered into the execution under way, the row rewritten with the tailer, the container and the feed's edge as its offset with relaunches unchanged and the offset following each refill's steps, one resumed note in pi's shape; a tailer that died is restarted over the same feed with keepLog, the password and the server's pid, the feed read from the row's offset with nothing before it said again and everything after it read, the note and the row carrying the new tailer; an ask pending on the server is decided through the gate exactly once — allowed or refused — the tool running or failing on that reply and its result reaching the record; a transcript with a compaction row aligns the same way, the first step landing past the transcript and the row; the row's bearer joins this generation's proxy only once every check has passed — after a refused re-attach the dead generation's bearer is still refused at the proxy, after one that went through it verifies there | [unit] src/core/harness/opencode/harness.test.ts::OpenCodeHarness — the re-attach onto a still-answering server::re-attaches onto the server with the row's password…, ::a tailer that died with the bot is restarted over the same feed with keepLog…, ::an ask pending on the server at the re-attach is decided through the gate — … — exactly once, the tool runs or fails on that reply, and its result reaches the record, ::a transcript with a compaction row aligns too…, ::the row's bearer joins this generation's proxy only once every check has passed… |
6, a bot roll under a live process re-attaches in place, no rebuild: the re-attach's store read decodes the shape the pinned binary actually answers — a cursor page sends the cursor and the limit alone (a cursor combined with order is a 400 InvalidCursorError, measured; the fake serve refuses the combination the same way), a page the transport's per-stream cap cut mid-JSON (the resident's exec truncates curl's answer past its cap on a long run's store) is re-asked at half the rows down to one row a page, and only a one-row page that still does not parse — or a page the server refuses — refuses the re-attach, the refusal quoting the answer's first bytes beside the shape expected; proven against the fake serve and against the real binary, where the new generation continues the same server and session — same pid, port, root and session — instead of rebuilding from the record | [unit] src/core/harness/opencode/harness.test.ts::OpenCodeHarness — the re-attach onto a still-answering server::a bot roll under a live process whose store overflows the transport's page cap re-attaches in place — the read pages smaller, no rebuild, ::a server that answers but…, src/core/harness/opencode/bridge.test.ts::readStoreSince — the newest rows, page by page, down to what was there before::a page the transport cut mid-JSON is re-asked smaller — the same cursor, half the rows — until it fits, and the read completes whole, ::a one-row page that still does not parse is the shape mismatch, refused with the answer's first bytes beside the shape expected, src/core/harness/opencode/testing/realDriver.test.ts::OpenCode against the real @opencode/cli binary::a bot roll under a live process re-attaches in place, no rebuild: the new generation continues the same server and session, and the run answers |
| 6, the gate during the bot's absence: a call of OpenCode's own in flight at the death whose ask is no longer pending at the re-attach was answered while the bot was away — its echo or its settlement met catching up fails the run closed as the gate bypassed, nobody alive named for the reply, no reply posted, no second server, the server and its tailer ended; an exchange the ledger already holds, read again because the row's offset lagged the write, is the dead generation's word — adopted, not replied to, and not written twice | [unit] src/core/harness/opencode/harness.test.ts::OpenCodeHarness — the re-attach onto a still-answering server::an ask pending at the bot's death that was answered while the bot was away…, ::an exchange the ledger already holds, read again because the row's offset lagged the write… |
| 13, the join by message id: a refill of the changed messages alone (the real tailer's every refill after its first), of the whole store again (a restarted tailer's first, the fake's every one) or of a message read again in a changed state writes each step once, and the answer is the last text-only turn | [unit] src/core/harness/opencode/bridge.test.ts::the store's join by message id — a refill of the changed messages alone, or of the whole store again, writes each step once::* |
6, own store: a harness that keeps its own store and finds it gone closes the run interrupted and its request runs again; a quoted seed enters the record as a text part of the request turn and never as prior assistant turns | [gap] No own-store harness exists; the rule is the contract's. |
| 1, the roster: configuration validation refuses a harness whose declared wire is not in the proxy's roster | [gap] The roster is the proxy's three paths (the row above); a harness object declares no wire yet. |
| 2, P2: a coding run's container holds a credential that can push only to the run's branch (a push proxy in the bot or a scoped token), so the one-push-target rule is a wall and not a rule | [gap] P2 by the maintainer's decision recorded in record 0038's fifth amendment; the residual exposure is a push to any unprotected branch and a GitHub API write with the token the container holds, bounded by branch protection and the token's scope. |
| 2, P2: the harness process and the model's shell run as different users, so the run bearer and a server's password are unreadable from the shell | [gap] P2 by the maintainer's decision recorded in record 0038's fifth amendment; the residual exposure is the shell reading the harness's secrets from its environment and, on a harness whose approval lives in its own server, forging a permission reply, detected by the bridge after one tool call. |
12: every image pins @opencode/cli at one exact version beside pi, the wrapper's install script allowed by name and scoped to it, the version text proven at build, the resident again as worker1, the bot's in its runtime stage before its user; the CLI, protocol and schema devDependencies are at the same exact pin | [unit] src/deploy/imageOpenCodeHarness.test.ts::the three images carry one OpenCode::*, src/deploy/imageOpenCodeHarness.test.ts::Dockerfile::*, src/deploy/imageOpenCodeHarness.test.ts::deploy/cloudflare-resident/Dockerfile::*, src/deploy/imageOpenCodeHarness.test.ts::deploy/cloudflare-sandbox/Dockerfile::*, src/deploy/imageOpenCodeHarness.test.ts::the resident image proves OpenCode as a thread user::*, src/deploy/imageOpenCodeHarness.test.ts::the bot image::* |
12: the run's files live under one root of the run's own directly under /var/tmp, outside the shared temp directory, with per-run XDG roots, the tailer a second seam process whose log is the feed, the same layout under a recorded root | [unit] src/core/harness/opencode/process.test.ts::openCodeRunPaths::* |
| 12: the server is started on the seam's picked port with exactly the run's variables — the bearer, the bot's URL, the roots, both project-config switches, the catalogue and update switches, the in-memory store, the password — and no provider key whatever the bot holds; the password is the bearer's hash and never the bearer | [unit] src/core/harness/opencode/process.test.ts::openCodeLaunchArgs and the environment::*, src/core/harness/opencode/process.test.ts::openCodePassword::* |
| 12: the agent's rules put the ask-on-all rule first and the identity's denies last, so under the last-match evaluator every asserted action asks and the denied tools are hidden; the built-in tools and the harness note follow the identity | [unit] src/core/harness/opencode/process.test.ts::the gate's rules and the identity's tools::* |
| 12: the Effect decoder used by the harness tests is pinned to the exact Effect dependency declared by both OpenCode protocol and schema packages; Dependabot never upgrades it independently, so a decoder bump cannot split the schema representation from the pinned binary's contract | [unit] src/deploy/imageOpenCodeHarness.test.ts::OpenCode's schema decoder pin::* |
12: the configuration validates against the pinned v2 schema on both dialects and every identity (and the schema refuses a bad value), names the proxy as the one provider with the bearer's variable as its key and no secret in the file, makes switchboard the default primary agent and removes the title agent, references the plugin directory, switches every phone-home and side effect off, and carries the compaction thresholds when set and the run's card when one came — limit.context from the window, capabilities.input from the inputs, one variant per tier with the wire's word (a refused tier none; a budget Anthropic model none at all), the cap field as compatibility.maxTokensField, and the session's variant the tier exactly when declared; the loaded document is held against it by key | [unit] src/core/harness/opencode/process.test.ts::the configuration writer::*, src/core/harness/opencode/process.test.ts::configProblem — the loaded document held against what was written::* |
12: readiness — the server info from /api/info with the password within the bound, the configuration echoed with every clause-carrying key, the relay’s own active plugin inventory entry within the same bound — then the tailer, ready once its connected note is in the feed; each failure by name at once (the password refused, another version on PATH, an invalid info shape, the server exited, the file not loaded, a key dropped, activation failed even when the relay has no id), a container gone the typed error, the port, the root, the tailer's pid and the feed offset on the facts | [unit] src/core/harness/opencode/process.test.ts::launchOpenCode — the server started through the seam and found ready::* |
13: the workspace's release reads the record at the run's end — a command the ending may have left running (callsInFlight: a call cut by the ending's abort or interrupt, its result marked cut, whatever the status and whatever lands for it later; a cut result whose call's line the bounded backlog evicted counts by itself, named by its tool and id, its own line back when the call is announced again; a call open when the run failed, was interrupted or hard-stopped) releases always, torn down as after a hard stop, with a workspace_torn_down note naming the calls; the read is taken once, at the harness session's end, so a throw after a clean end neither re-reads a relayed call's unpaired line under failed nor notes a cut twice, while a session whose end itself throws fails a run not already interrupted before the read and retains its original workspace for the unconfirmed ending — an interrupted run stays interrupted, card and status agreeing — and an end failing after the loop's own error is a harness_error note, the loop's error the one that propagates; a run completed or stopped softly with a call unpaired (a relayed tool) or a failure with nothing in flight (an opening prompt unresolved) releases if-idle; pi's aborted settle carries the mark and a tool that exited clean in the abort's window does not; OpenCode's hung tool stays cut through its post-turns; a late external_directory ask leaves a directory_reached note, while asks held before the call opened ride its line at whichever site opens it — its own ask, the stream's call, or its settle — and a call the stream only named opens at its own ask or its settle, so the end can cut it; a gate bypass releases always whatever the record shows; an operator's hard stop landing beside the drainer's failure ends the run as the stop, the failure a note | [unit] src/core/runRecord.test.ts::callsInFlight — the commands a run's ending may have left running (docs/reference/specs/harness.md item 13)::callsInFlight reads the record for the commands a run's ending may have left running…, ::a cut result whose call the record no longer holds counts by itself…, src/core/harness/opencode/harness.test.ts::the post-turn on the run's session — refused, answered by silence, or after a hung turn::a tool call cut at the loop's end: the budget note names it…, src/core/harness/opencode/bridge.test.ts::the bridge's observing mode — an earlier execution's tail is not this loop's to decide::an external_directory ask that arrives once its call is already open…, ::an external_directory ask held for a call the store had not named…, ::an external_directory ask held before the stream's session.tool.called opens the call…, ::an external_directory ask held for a call the stream named but never opened…, ::a call the stream named whose own ask arrives…, src/core/harness/pi/bridge.test.ts::the bridge's spans — one tool.<name> per call under run.agent, ended with the call's outcome::a call an abort was sent for ends marked…, src/core/reviewRound.test.ts::releaseModeFor (per-agent attach/release pairing)::a command still in flight at the run's end forces always too…, src/core/dispatch/runLoop.test.ts::runLoop — the model turn and everything that rides on it::the tool the finale interrupted…, ::the tool pi's abort settled…, ::a clean completion with a relayed tool's call unpaired on the record…, ::a follow-up's steer unresolved with a command in flight…, ::a server gone silent with a call open…, ::the opening prompt unresolved — nothing in flight…, ::a gate bypass — the call already settled on the record…, ::a long run whose hung command's line the backlog evicted before the end…, ::a throw after a clean harness end — a relayed tool's call unpaired on the record…, ::a throw after a clean harness end that cut a call…, ::a harness session whose end() throws with a call open…, ::the loop throws with a live session and the session's end() throws too in the catch…, ::an interrupted run whose session's end() throws…, src/core/harness/conformance.test.ts::conformance — pi::conversation: a tool call in flight at the loop's end is cut…, src/core/harness/opencode/harness.test.ts::OpenCodeHarness — the resident's control plane resets under a write::a harness failure by name and an operator's hard stop landing in one tick…, ::a follow-up's steer into a hung tool's execution the reset cut, then the loop-end cut… |
12: the tailer's feed, replayed through pi's log transport by offset, yields every event in the order fed with the password on every request, appends the pending asks the moment their read answers and the store's messages after its pages at a step's end, both reads issued at once — an unanswered ask holds the server's turn and waits on nothing — appends an unchanged message once and a changed one again, notes a dropped stream and reconnects with a refill that covers the gap, notes a refill that fails — a read refused — and goes on refilling (its queue's chain never rejects), says a record the feed refused on stderr (a write's failure is the stream's error event, for the file the feed is as for a pipe, never a throw from the write — handled, so it is never an uncaught exception) and, the feed gone for good (a bad descriptor, a reader gone: every later write fails the same way), exits non-zero so a re-attach finds its pid gone and restarts it; a permissions read answering no object is the permission refill's own note, never the chain's; and exits when the server's process is gone; a refused password is noted and retried | [unit] src/core/harness/opencode/tailer.test.ts::the tailer::* |
12: every route the harness calls and every shape it reads is the pinned protocol's and schema's, built from the packages at the pin and decoded from complete server response samples, including settled tool content; the installed CLI, protocol and schema versions equal the client's version; real fresh starts, record rebuilds and same-server re-attaches answer that exact version from authenticated /api/info | [unit] src/core/harness/opencode/client.test.ts::the routes are the pinned protocol's::*, src/core/harness/opencode/client.test.ts::the shapes are the pinned schemas', from server response samples::*, src/core/harness/opencode/client.test.ts::the parsers::*, src/core/harness/opencode/testing/realDriver.test.ts::OpenCode against the real @opencode/cli binary::* |
12 live: a run on a staging container starts the server through the seam and answers valid server info from /api/info | [gap] Human-gated, owed on the tracker: a deployment with harness: { coding: opencode }, a coding run in a scratch repository on the resident, its record complete on the run page with one refused command visible as tool_refused; a bot roll under an OpenCode run ending completed with the resumed note naming the path taken; a resident roll under an OpenCode run ending completed with relaunches: 1. |
OpenCode launch identity
| Criterion | Proof |
|---|---|
| Server and tailer retain their separate launch births in ready facts. Legacy facts remain unattested; malformed tailer evidence is dropped. | [unit] src/core/harness/opencode/process.test.ts::launchOpenCode — the server started through the seam and found ready::retains distinct server and tailer launch births in the ready facts, src/core/harness/contract.test.ts::harnessFactsOf — a row's facts, read by the harness that wrote them::preserves the OpenCode tailer's launch identity separately and drops malformed evidence, src/core/harness/opencode/harness.test.ts::OpenCodeHarness — the re-attach onto a still-answering server::tailer-only restart retains session custody and replaces birth evidence… |
Canonical child allowance
A canonical child uses the absolute bound committed at its original admission. Setup, downtime, resume and container recovery consume that allowance. Post-loop turns and finales cannot extend it; their one-minute minimum is capped by the actual remainder. Expiry admits no model prompt. Ordinary runs retain their existing lease policy.
| Criterion | Proof |
|---|---|
| Both harnesses preserve the absolute bound when model admission follows attachment downtime. | [unit] src/core/harness/pi/harness.test.ts::a carried absolute deadline bounds…, src/core/harness/opencode/harness.test.ts::an absolute admitted deadline bounds… |
| Post-loop turns consume only the absolute remainder; expiry prevents further prompts and a hung turn cannot admit a finale afterward. | [unit] src/core/harness/pi/harness.test.ts::a canonical post-loop turn…, ::an absolute deadline ends a hung post-loop turn… |
| Delayed model admission and queued writes cannot begin after the original deadline. Abort and gate replies remain deliverable. | [unit] src/core/harness/pi/harness.test.ts::startup consuming the absolute deadline sends no model instruction, src/core/harness/pi/transport.test.ts::PiRpcTransport::expires queued model instructions at the FIFO write while permitting abort and gate replies, src/core/harness/opencode/harness.test.ts::expiry after lease admission prevents the OpenCode initial model request |
Typed container execution
| Criterion | Proof |
|---|---|
| Container operations use the executor's structured exit and truncation facts; stdout remains exact data. Missing capability, truncated answers, nonzero exits and unknown transport outcomes never authorize success or a repeated write. | [unit] src/core/harness/container.test.ts::ExecHarnessContainer — typed execution authority::* |
| An idempotent command retry consumes its original absolute operation deadline, capped by the admitted run deadline. Cancellation and expiry prevent another command; every command carries the original hard-stop signal. | [unit] src/core/harness/container.test.ts::ExecHarnessContainer — original operation deadline::* |
| OpenCode's readiness deadline includes setup and every readiness phase; expiry or cancellation admits no later server/tailer launch, poll or session request. | [unit] src/core/harness/opencode/process.test.ts::launchOpenCode — the original deadline and cancellation::* |
| The run's admitted deadline and current run-control lease scope reach both remote factories and the host factory; a cancelled/expired host run creates no root. Transport deadline abort bounds waiting and does not establish physical termination. | [unit] src/core/harness/botHostContainer.test.ts::harnessContainerFor — original run scope::*, src/core/harness/botHostContainer.test.ts::BotHostHarnessContainer — typed transport uncertainty::* |
| Unknown or truncated recorded-server, session or feed collection never proves a process dead, authorizes cleanup or starts a second server. | [unit] src/core/harness/opencode/harness.test.ts::OpenCodeHarness — the contract's object::find retains an unknown probe instead of declaring the recorded process dead…, src/core/harness/opencode/harness.test.ts::OpenCodeHarness — the re-attach onto a still-answering server::unknown recorded… |
Producer custody and physical control
| Criterion | Proof |
|---|---|
| A pending launch is durably acknowledged under the original run and workspace owner before submission; a recovered unknown start never creates another process. Server and tailer custody is committed before readiness and session mutation. | [gap] The current facts callback queues a write. An owner-fenced acknowledged producer transition and exact backend operation reconciliation remain required before this capability is activated. |
| Deadline cancellation and archive capture use an atomic birth-bound capability for the actual owned process and every descendant writer, excluding peers and preventing respawn throughout capture. | [gap] The current container exposes PID-based observation and termination. Neither stored birth text nor a transport abort establishes physical quiescence. Real pi/OpenCode partial-launch, descendant, held-stream and capture-barrier proofs require the backend capability. |
| Cached initial sandbox seeds are refused by the baseline gate before any identity command; a freshly restored seed still reads typed physical identity and completes the baseline before model admission. | [unit] src/core/dispatch/runLoop.test.ts::runLoop first coding test::holds a cached initial seed before any baseline or model work, src/core/dispatch/runLoop.test.ts::runLoop first coding test::a freshly restored sandbox seed reads current typed identity before its baseline and model |
Admission and lifecycle control
| Criterion | Proof |
|---|---|
| Hard stop and model-budget expiry refuse fresh startup, prompts and session mutation while preserving typed original-producer cancellation, bounded observations and shutdown. A control retry uses its one original operation bound. Control transport completion is not an atomic physical-quiescence receipt. | [unit] src/core/harness/container.test.ts::original producer control after admission ends::*, src/core/harness/pi/transport.test.ts::PiRpcTransport — the original factory control scope::*, src/core/harness/botHostContainer.test.ts::original host producer control after admission ends::* |
| Unknown or fenced shutdown retains the original producer paths; an end does not remove private data after an unconfirmed kill. | [unit] src/core/harness/opencode/harness.test.ts::OpenCodeHarness — the contract's object::an unknown shutdown retains the producer root… |
| An unconfirmed producer ending retains the original workspace even after hard stop or an in-flight call; a settled ending preserves the existing release path. | [unit] src/core/dispatch/runLoop.test.ts::runLoop — the model turn and everything that rides on it::an unconfirmed producer ending retains its original workspace…, src/core/dispatch/runLoop.test.ts::runLoop — the model turn and everything that rides on it::a settled original producer ending retains the existing release path, src/core/dispatch/runLoop.test.ts::runLoop — the model turn and everything that rides on it::a failed ending record drain retains the original workspace |
| A failed local ending inside harness open carries a typed unconfirmed outcome to the same dispatcher retention path; a missing returned session never confirms shutdown. | [unit] src/core/harness/opencode/harness.test.ts::OpenCodeHarness — the re-attach onto a still-answering server::an opening failure preserves a failed local ending…, src/core/dispatch/runLoop.test.ts::runLoop — the model turn and everything that rides on it::a typed unconfirmed opening ending retains the original workspace… | | A partial launch, unknown recorded probe, or failed restart cleanup before session handoff retains original custody and cannot authorize a new producer. Clean prelaunch refusal still starts no process. | [unit] src/core/harness/pi/harness.test.ts::runPiHarness — a run on pi from the first file to the answer::an opening failure preserves an unconfirmed…, ::an unknown launch outcome retains…, src/core/harness/pi/harness.test.ts::runPiHarness — after a bot restart::recorded…, src/core/harness/opencode/harness.test.ts::OpenCodeHarness — the re-attach onto a still-answering server::recorded…, src/core/harness/opencode/process.test.ts::launchOpenCode — the server started through the seam and found ready::an unknown…, ::a readiness failure preserves…, src/core/harness/opencode/process.test.ts::launchOpenCode — the original deadline and cancellation::a hard stop during setup admits no detached server |
| An answering recorded producer that cannot be continued retains its original root, feed, session and pointer. Version, authentication, session/store/feed or bearer-adoption refusal is not permission to end it, remove private state, relaunch or release its workspace. Exact-current-version continuation remains supported. | [unit] src/core/harness/opencode/harness.test.ts::OpenCodeHarness — the re-attach onto a still-answering server::a supported prior OpenCode 2.0.12 session…, ::a server that answers but…, ::the row's bearer joins this generation's proxy…, ::re-attaches onto the server with the row's password…, src/core/dispatch/runLoop.test.ts::runLoop — the model turn and everything that rides on it::a typed unconfirmed opening ending retains the original workspace… |
| Original recorded reentry with no complete response, sampled absence, foreign placement or incompatible pi root/wire/bearer retains its producer and pointers. Unbound first attachment and compatible original continuation remain supported; the existing explicit replacement protocol is separate and establishes no physical capture authority. | [unit] src/core/harness/contract.test.ts::original pi producer custody::*, src/core/harness/opencode/harness.test.ts::OpenCodeHarness — the re-attach onto a still-answering server::holds an original OpenCode producer…, src/core/harness/contract.test.ts::PiHarness — pi as the contract's object::find holds…, src/core/harness/conformance.test.ts::conformance — pi::survival: a foreign original producer…, ::survival: sampled absence…, src/core/harness/conformance.test.ts::conformance — opencode::survival: a foreign original producer…, ::survival: sampled absence… |
| Known original container placement requires a positively matching current identity before any pid or HTTP probe. An unavailable identity retains typed custody in open and find. Legacy facts without a container keep their existing behavior; they do not prove physical placement or birth. | [unit] src/core/harness/contract.test.ts::original pi producer custody::open holds a known original container…, ::find holds a known original container…, src/core/harness/opencode/harness.test.ts::OpenCodeHarness — the contract's object::find holds a known original container…, src/core/harness/opencode/harness.test.ts::OpenCodeHarness — the re-attach onto a still-answering server::open holds a known original container… |
Durable launch intent
| Criterion | Proof |
|---|---|
| A new tracked harness run records its original harness and logical command policy atomically with the existing resumable seed, before a producer exists. Attaching rows remain setup-only. | [unit] src/core/dispatch/run.test.ts::claimRun — the ledger claim once the prompt exists::records original … launch intent in the resumable seed before a producer exists |
| Both harnesses acknowledge the irreversible begun phase of each launch ordinal before external process start. An unknown launch write admits no start; a lost start response retains the same launch and admits no replacement. An acknowledged prepared launch can continue after restart with its original permissions and allowance. | [unit] src/core/harness/contract.test.ts::durable launch intent::*; src/core/dispatch/runLoop.test.ts::tracked Review command receipt binding::recovers prepared … permissions and allowance without producer facts |
| The existing state owners preserve original launch policy and harness, allow prepared-to-begun advancement within an ordinal, and refuse rollback, permission substitution or a foreign generation. Only the existing vouched replacement decision prepares a next ordinal; producer receipts stay bound to their actual ordinal. Same-ID reservation reads preserve the original state rather than minting restart authority. Unknown writes reconcile against their original witness; neither an absent producer receipt nor current labels authorize replay or legacy policy backfill. | [unit] src/core/dispatch/run.test.ts::claimRun — the ledger claim once the prompt exists::a same-ID reservation preserves an unknown begun launch instead of minting a prepared one; src/core/runLedger/checkpointState.test.ts::durable launch state transaction::*; deploy/cloudflare-memory/harnessLaunch.test.ts::durable harness launch in SQLite::*; src/core/runLedger/harnessPolicyAck.test.ts::canonical original harness policy ACK::reconciles only the original unknown launch write…; src/core/harness/sessionPolicy.test.ts::durable launch intent closed contract::* |
| Every existing restart-from-request decision after a typed container replacement and matching producer receipt acknowledges the next prepared attempt before its predecessor closes, including the relaunch ceiling and a refused bearer rotation. Workspace reattachment refusal alone does not prove the producer ended or grant another launch. | [unit] src/core/dispatch/runLoop.test.ts::the pi harness — the container replaced under a living bot: the relaunch ceiling::a … refusal leaves a prepared same-ID restart after the predecessor finish fails; src/core/dispatch/run.test.ts::claimRun — the ledger claim once the prompt exists::a same-ID reservation preserves an unknown begun launch instead of minting a prepared one |
| Legacy launch policy absence and unknown original start outcomes are recovered from original accepted evidence without replay. | [gap] This source hardening cannot reconstruct missing policy or process receipts from labels, recorded usage or current configuration. Runtime recovery requires the original owning operation's evidence. |
Hosted Review commands
| Criterion | Proof |
|---|---|
| Ordinary text keeps its existing delivery ordering. A live required-context predicate detects later media provenance and rechecks it after staging; missing proof preserves the original input without delivery or consumption. | [unit] src/core/harness/opencode/harness.test.ts::OpenCodeHarness — the resident's control plane resets under a write::checks newly required inherited context after staging while ordinary input starts without an extra guard await |
| Required native media and inherited media context receive current source proof before import and model entry, and again after follow-up staging. Missing capability or source loss preserves the original input without text-only delivery. | [unit] src/core/dispatch/runLoop.test.ts::runLoop — the model turn and everything that rides on it::binds the initial source guard to the exact current media turn and original message address, ::prepares native media through original source IO atomically and refuses an unproved second input without retaining first bytes; src/core/harness/pi/harness.test.ts::runPiHarness — the resident's control plane reset under a live pi::holds required inherited media context when its guard capability is missing despite no original media digest, ::holds the original native media prompt when source proof is lost during seed import; src/core/harness/opencode/harness.test.ts::OpenCodeHarness — the resident's control plane resets under a write::holds the original native prompt when source proof is lost during initial session import |
| OpenCode uses its existing file transport and an exact request identity for native admission. Missing or mismatched acknowledgments, transport loss and binary 5xx remain uncertain and authorize no repost or consumed sequence. Allowed image normalization is admission evidence, not original-pixel or model-consumption proof. | [unit] src/core/harness/opencode/media.test.ts::OpenCode native media identity::*; src/core/harness/opencode/harness.test.ts::OpenCodeHarness — the resident's control plane resets under a write::uses existing files for an original … image/PDF input with its full admitted identity, ::holds possibly admitted native media after … ACK without a second prompt or consumed sequence, ::holds an initial binary HTTP 503 as an unknown write without reposting the prompt |
| Criterion | Proof |
|---|---|
New bound/tracked Review registers run_check directly, removes native OpenCode shell through the pinned editor and appends a final shell deny. The bot gate rejects native shell independently; coding and explore retain their own permissions. Existing CodeMode/subagent/egress denies remain in force. | [unit] src/core/harness/opencode/process.test.ts::hosted Review permission policy::*; src/core/harness/opencode/pluginSource.test.ts::hosted Review plugin table::*; src/core/harness/opencode/bridge.test.ts::hosted Review native permission admission::* |
| A compatible recorded session resumes only under its original acknowledged logical launch policy; current classification cannot upgrade it. Missing, malformed or foreign policy required for hosted commands remains held before producer effects. Fresh tracked policy-bearing facts require a known canonical ACK before model entry; false or thrown saves retain the actual started producer without replacement. Explicit untracked native and native legacy paths retain their prior behavior without gaining canonical policy. Neither the logical contract nor command receipts attest an effective native table or physical custody. | [unit] src/core/harness/contract.test.ts::hosted Review retained session policy::*; src/core/dispatch/runLoop.test.ts::tracked Review command receipt binding::* |
| Original logical command policy is one closed v1 contract for both harnesses: actual native/hosted route and identity from trusted launch, captured with the original facts. Compatible original continuation preserves it; missing, malformed or mismatched hosted policy holds without cleanup, launch or new facts. | [unit] src/core/harness/sessionPolicy.test.ts::original session policy closed contract::*; src/core/harness/contract.test.ts::original hosted policy compatible continuation::*; src/core/harness/contract.test.ts::original hosted policy uncertainty remains held::* | | First tracked policy-bearing facts must receive a known canonical ACK before model entry. Unknown or throwing saves hold the actual producer/root/session; a boolean refusal does not manufacture a private store witness or prove physical termination. | [unit] src/core/harness/contract.test.ts::original session policy canonical first-fact ACK::* | | Original legacy resumed-review policy can be verified from an actual original accepted launch contract. | [gap] Older harness facts contain no acknowledged sessionPolicy. Generic claim tool definitions precede hosted launch selection; labels, source version or a tool receipt cannot backfill original policy. No failed original model replay or SDK probe is authorized by this source repair. |
| A same-run typed unconfirmed opening retains its original checkpoint cause rather than gaining another custody wrapper; dispatch's existing single unwrap sees that cause. A foreign-run error cannot replace current identity. Unknown ACK still holds the original producer with no model or ending effects, and opening/ending fields retain their meanings. | [unit] src/core/harness/contract.test.ts::original session policy canonical first-fact ACK::holds the newly started …, ::a foreign … custody error cannot replace the current run's identity, ::holds the actual started … |
| A successful OpenCode execution after a refusal settles without a second prompt; interrupted decline cascades retain their recovery prompt. | [unit] src/core/harness/opencode/testing/realDriver.test.ts::OpenCode against the real @opencode/cli binary::a step with two shell calls… |
| Criterion | Proof |
|---|---|
| Pi and OpenCode expose the active lease to relayed read-delegation tools. A valid requester spawn receives a finite positive remainder and returns its child result; an unknown budget stays held in the orchestrator. | [unit] src/core/harness/opencode/bridge.test.ts::relayed read delegation budget::*; src/core/dispatch/runLoop.test.ts::runLoop — the model turn and everything that rides on it::delegation keeps its saved source through the spawn path: %s |
Native source input capability
The pinned OpenCode API accepts caller-assigned IDs and metadata on synthetic input. resume: false keeps that input in its native inbox. This capability alone does not enable Switchboard source delivery, authorize delivery to an ended run, prove a model read the input, or acknowledge a Switchboard checkpoint.
The current Switchboard launch sets OPENCODE_DB=:memory:. A confirmed server exit loses that native session; this configuration is not qualified for source identity recovery after process replacement. A controlled fixture on the same pin uses a file database inside its owned run root and reads the original queued input IDs and metadata after a new native process starts. The fixture changes no production setting and resubmits no source input.
This measures controlled process exit and restart. Abrupt failure, container replacement, production store policy, trusted source admission, native mirrors and canonical checkpoint acknowledgment remain integration gates. File-store API capability alone does not qualify a delivery caller.
| Criterion | Proof |
|---|---|
| Two synthetic inputs with identical text retain distinct IDs and metadata in the native inbox. Reusing an ID with changed content returns the original input and preserves both original inputs. Enqueue without resume makes no extra model call. A consumer must check saved content, not only HTTP success and input ID. | [integration] src/core/harness/opencode/testing/realDriver.test.ts::OpenCode against the real @opencode/cli binary::keeps distinct synthetic input identities when their text is identical |
| Current memory-store launch returns 404 for the original native inbox after confirmed server exit. An isolated file-store fixture retains both original equal-text input IDs and metadata in the same session. Both old and new processes answer the pinned version, and the fixture sends no source input after restart or additional model request. | [integration] src/core/harness/opencode/testing/realDriver.test.ts::OpenCode against the real @opencode/cli binary::checks queued source state after native exit with %s storage |