Skip to content

Require owned provider spawn and one host-awaited open - #28055

Closed
brennanb2025 wants to merge 38 commits into
brennanb2025/agent-start-split-5-stop-workloadfrom
brennanb2025/agent-start-split-6-acquisition-cleanup
Closed

brennanb2025 wants to merge 38 commits into
brennanb2025/agent-start-split-5-stop-workloadfrom
brennanb2025/agent-start-split-6-acquisition-cleanup

Conversation

@brennanb2025

@brennanb2025 brennanb2025 commented Oct 12, 2026 •

Copy link
Copy Markdown
Contributor
Files Added Deleted Net
Test 72 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​188 $\color{#cf222e}{\Huge{\mathbf{−}}}$​9957 $\color{#cf222e}{\Huge{\mathbf{−}}}$​9769
Prod 42 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​190 $\color{#cf222e}{\Huge{\mathbf{−}}}$​383 $\color{#cf222e}{\Huge{\mathbf{−}}}$​193

ELI5

All adapters now use the host's separate process-start and initialization steps, but the shared interface still allowed the old completed-start path and pushed startup event. Those alternate paths made it possible for a new adapter to skip the opening contract. This cleanup makes the existing contract mandatory; chat behavior stays the same.

What Changed

Every adapter must return its process with an acquisition identity and provide a separate awaited open. The old completed-acquisition readiness and catalog branch, pushed started event, unused option hooks, and report-restoration module are removed. Tests answer the actual open call instead of pushing startup events.

Why

Typechecking now requires every adapter to follow the opening path that the preceding pieces implement. Removing the unused alternate path leaves one source for readiness and makes future omissions visible immediately.

Differences from the common pattern

This cleanup introduces no additional product difference. It makes the preceding opening contract required; its startup limits and provider-specific behavior are unchanged.

Linked Issue

Completes the startup alignment from #26561 after #28051, including the readiness behavior folded from #27627 and message-choice behavior folded from #27641.

Visual Proof

N/A — this cleanup removes unreachable code and changes no user-facing layout or interaction.

Testing

  • Manually tested on all supported platforms
  • Automated tests added or updated

Focused adapter contract, host opening, startup order, delivery and Stop tests; Node and CI project typechecks; static checks with the accepted pinned-main HtmlDocPreview exception. No wire or persisted-format change and no user-facing UI change in this cleanup.

Review

Reviewed the owning diff, failure paths and covered races. Tests demonstrate covered behaviors; rendered and real remote-host QA are pending.

Agent skill upstream boundary

  • Not applicable; no upstream skill-installer source is copied or translated.

Notes

Execution stays on the host owning the agent. Folder workspaces and independently updated peers retain their existing paths. Loss of contact is not process-exit evidence. Draft only; no main sync or hosted CI watch.

Checklist

  • Problem, user-facing change, mechanism and approach explained
  • Self-reviewed source and regression evidence
  • Cross-platform, folder, SSH and older-peer behavior considered
  • Final main sync, hosted CI and rendered proof completed

@brennanb2025
brennanb2025 force-pushed the brennanb2025/agent-start-split-5-stop-workload branch from d070825 to ef1ad55 Compare October 12, 2026 21:32
@brennanb2025
brennanb2025 force-pushed the brennanb2025/agent-start-split-6-acquisition-cleanup branch from 73e0d85 to 0c4770f Compare October 12, 2026 21:32
@brennanb2025 brennanb2025 changed the title Remove the unused completed-start acquisition path Require owned provider spawn and one host-awaited open Oct 13, 2026
# Conflicts:
#	config/scripts/vitest-sqlite-runtime-files.mjs
#	src/main/acp/acp-structured-adapter.test-support.ts
#	src/main/acp/acp-structured-handshake.ts
#	src/main/acp/acp-structured-spawn.ts
#	src/main/claude/claude-structured-session-adapter.test.ts
#	src/main/claude/claude-structured-session-adapter.ts
#	src/main/codex/codex-structured-session-adapter.ts
#	src/main/native-chat/agent-session-wire/structured-agent-session-accept-then-deliver.test.ts
#	src/main/native-chat/agent-session-wire/structured-agent-session-acquisition-options.test.ts
#	src/main/native-chat/agent-session-wire/structured-agent-session-acquisition.ts
#	src/main/native-chat/agent-session-wire/structured-agent-session-adapter-router.ts
#	src/main/native-chat/agent-session-wire/structured-agent-session-adapter.ts
#	src/main/native-chat/agent-session-wire/structured-agent-session-attach-flow.ts
#	src/main/native-chat/agent-session-wire/structured-agent-session-create.test.ts
#	src/main/native-chat/agent-session-wire/structured-agent-session-event-recovery.ts
#	src/main/native-chat/agent-session-wire/structured-agent-session-held-start.test-support.ts
#	src/main/native-chat/agent-session-wire/structured-agent-session-host.ts
#	src/main/native-chat/agent-session-wire/structured-agent-session-instant-start.test-support.ts
#	src/main/native-chat/agent-session-wire/structured-agent-session-mutation-context.ts
#	src/main/native-chat/agent-session-wire/structured-agent-session-option-restoration.ts
#	src/main/native-chat/agent-session-wire/structured-agent-session-option-settlement.test.ts
#	src/main/native-chat/agent-session-wire/structured-agent-session-provider-child-record.test.ts
#	src/main/native-chat/agent-session-wire/structured-agent-session-provider-open.ts
#	src/main/native-chat/agent-session-wire/structured-agent-session-provider-started-catalog.test.ts
#	src/main/native-chat/agent-session-wire/structured-agent-session-provider-started.ts
#	src/main/native-chat/agent-session-wire/structured-agent-session-provider-waits.ts
#	src/main/native-chat/agent-session-wire/structured-agent-session-queued-message-rig.test-fixture.ts
#	src/main/native-chat/agent-session-wire/structured-agent-session-send-restarts-failed-start.test.ts
#	src/main/native-chat/agent-session-wire/structured-agent-session-startup-attempt-host.test.ts
#	src/main/native-chat/agent-session-wire/structured-agent-session-startup-attempt.ts
#	src/main/native-chat/agent-session-wire/structured-agent-session-startup-permission-mode.test.ts
#	src/main/native-chat/agent-session-wire/structured-agent-session-startup-picks.test.ts
#	src/main/native-chat/agent-session-wire/structured-agent-session-stop-never-waits.test.ts
#	src/main/native-chat/agent-session-wire/structured-conversation-command.test.ts
#	src/main/runtime/agent-session-record-options.test.ts
#	src/main/runtime/rpc/methods/structured-agent-session-options-read.test.ts
#	src/main/runtime/structured-agent-runtime-registrations.ts
# Conflicts:
#	src/main/native-chat/agent-session-wire/structured-agent-session-startup-attempt-host.test.ts
brennanb2025 added a commit that referenced this pull request Oct 19, 2026
…28046)

* Finish structured agent readiness before delivering held work

* Publish the Codex process before protocol startup

* Publish ACP agent processes before session startup

* Publish Pi at spawn and settle signed-out starts once

* Adapt permission fixtures to startup lifecycle

* Keep model discovery for chats before their first start

* Use one host readiness promise for provider operations

* Await provider opening in the execution host

* Await Claude initialization in host-owned open

* Observe Claude readiness through the host status

* Keep optional readback behind host readiness

* Recheck launch permission after host readiness

* Preserve the awaited child during permission revalidation

* Await Codex protocol open under host ownership

* Await ACP protocol open in the host

* Derive ACP opening from its protocol session facts

* Exercise unanswered ACP options with an explicit silent route

* Await Pi open and fail signed-out construction

* Read Pi catalog facts from awaited opening

* Keep the Pi fixture exit observer

* Record failed owned opening before the first message

* Abort a matching provider open when its child exits

* Cover provider exit during an unanswered host open

* Cover explicit failure facts on a host-stopped child

* Capture message choices per accepted send and preserve picker state

* Apply accepted Claude message choices at prompt handover

* Apply captured message choices at provider dispatch

* Bind native chat choices to accepted message dispatch

* Reset Codex turn choices for each captured message

* Resolve Codex message defaults from native facts

* Align message choice and Pi default fixtures with provider dispatch

* Align option fixtures with saved message choices

* Match Codex message choices to the active turn origin

* fix: let pending commands reach handover refusal

* Abort pre-prompt message choice writes with host-owned wait

* Verify message choices through provider input boundaries

* Keep legacy mobile test hosts explicit about message choices

* Keep startup waits cancellable and preserve operation order

* Derive Codex startup exits from host phase

* Open Codex protocol in background-task test fixtures

* Keep ACP startup ownership until handshake completes

* Run ACP opening catalog fixtures with Node SQLite

* Verify saved ACP picks without live option writes

* Keep ACP catalog bookkeeping from failing an options read

* Restore signed-out restart and fail Pi startup faults

* Run Pi opening catalog fixtures with Node SQLite

* Preserve message choices across cold clients and kept cards

* Remove the unused provider option restore ledger

* Clarify launch choices and legacy option hydration

* Remove remaining restore-ledger forwarding and assertions

* Remove unused ACP and Pi restore bookkeeping

* Keep live choices and delivery order while agents start

* Drop retired startup revision from Codex opening

* Keep live-option cancellation until message choices and clarify catalog reads

* Hold ACP option replies in live-write cancellation regressions

* Remove retired Pi startup revision and match saved-pick behavior

* Check running choices and retained rewind messages after delivery integration

* Apply startup picks and let parked messages release operations [skip ci]

* Remove unused Codex opening report field [skip ci]

* Keep ACP restoration facts local to the provider [skip ci]

* Apply Pi startup picks after readiness and remove unused open facts [skip ci]

* Cover goal changes during the held Codex message wait [skip ci]

* Save a waiting startup pick after Stop ends its opening [skip ci]

* Save choices when startup ends or a replacement is still opening

* Check saved choices separately from Claude startup reports

* Release scripted Codex startup before awaiting queued picks

* Check the saved picker selection in per-message choice fixtures

* Exercise current choices and eager client capabilities in runtime fixtures

* Reuse runtime fixture reads and type the fake connection directly

* Align startup fixtures and preserve observed Claude exits

* Honor queued send authorization in Claude runtime fixtures

* Open Codex protocol sessions before Stop fixture dispatch

* Wait for the opened Codex child before runtime notifications

* Keep repeated permission picks usable and align Codex fixtures

* Validate pending picks against the live option state

* Order startup picks before later messages and retain flow regressions

* Keep reviewed lifecycle contracts while pruning duplicate tests

* Save picks after a proven exit without requiring a child

* Type the startup reply fixture against the Claude control contract

* Keep Codex startup flow contracts and remove overlapping adapter tests

* Restore the committed dependency lockfile after test tooling

* Keep startup recovery flows and remove duplicate Pi handshake cases

* Cover both Pi startup choices in the delivery flow

* Match the Pi prompt entry recorded by the scripted wire

* Honor the before-input callback in the startup reply fixture

* Keep message choice flows and remove overlapping selector tests

* Keep startup option menus independent and show the saved choice

* Exercise startup picks across real menus and the runtime

* Match startup picker fixture to saved message choices

* Keep saved effort visible when picking a model during startup

* Include the running-turn scope in repeated Stop fixture

* Use the current attach contract in import fixtures

* Keep the Codex journal translator within its line limit

* Match ACP startup fixtures to saved picks and late Stop behavior

* Check startup effort after saved picker choices are acknowledged

* Complete Stop target types and keep the effort regression concise

* Use requested picker values in the effort regression acknowledgement

* Require owned provider spawn and one host-awaited open (from #28055)

* Restore the live checks the startup cleanup's deleted tests pinned

One assertion each, in the surviving suites: a stale-generation exit is
ignored, a failed create lets its sink go, a readback before open is saved,
an idle stop that fails is retried, a no-pick Pi start teaches its default,
an older client's pre-spawn failure and packed answer, an undrivable chat
stays readable, the resting slash menu stays on its own host, the main agent
reads apart from subagents, restore publishes status, naming runs off the
host's status feed, and a throwing logger never reaches the operation.

Also corrects the reliability gate note that claimed the send-idempotency
suite replaced the refusal-retry tests.

* Read a rewind in doubt outside the chat's serialize and apply it in the commit

The started settle and the attach's ready-child path read the provider's
history first, then apply what it proves in a short commit that re-checks
the rewind it read.

* Accept messages while the agent starts: run the start outside the chat's serialize

The chat's serialize was both where a send was admitted and where its agent
started, so every slow step of a start (closing-child join, lease
reconcile, recovery probes, resolvers, history read, spawn, sink drain,
provider dispatch) held every later send.

A start now registers in one short step before its first wait: its abort
controller (which Stop, close and quit already reach outside the lock),
its startup clock (the 10-minute ceiling now counts from here) and quit's
drain. Every wait after runs outside the lock, raced with that signal, and
every write is a commit that first re-checks the start is still the
session's. A start that loses the check is late: its spawn is closed
through the post-acquisition failure path and nothing is handed to it.

- The delivery loop's prepare returns a start handle; the loop awaits the
  start outside, then re-prepares. Handover writes the pending row and
  begins the dispatch abort handle in one commit, calls the provider
  outside after re-checking the child, and resolves in a second commit.
- Ready operations claim a start instead of running one in their step.
- A client attach runs the same steps under one serialize, as before.
- An exit reported between spawn and publish is held for the publish
  commit, which ends the child it indexes.
- An unproven close still fails only what was queued when its start was
  asked for.

* Test that a send is accepted at every wait an agent start makes

One whole-flow test holds the start at each wait in turn (closing-child
join, reconcile probe, recovery re-probe, resolver, spawn, sink drain,
open, started recovery, pending row, provider call): a second send is
accepted at once, a Stop is recorded without waiting and nothing reaches
the provider, and what was sent goes to the published child once, in
order. Also quit before spawn, concurrent sends, a lease left recovering,
and an idle sweep racing a send.

* Bound each startup step on its own and drop the startup silence rule

A start no longer ends after 60 s without output: output is not protocol
progress. Each protocol step now has its own bound where its handshake
lives, and one 10-minute ceiling from registration stays as the outer bound.

- Codex: initialize 15 s and thread start/resume on the connection's 30 s
  default again, instead of the startup ceiling.
- ACP: initialize 60 s, authenticate 120 s, session new/load/resume/fork
  300 s; turns stay unbounded and option writes keep their caller's bound.
- Claude: the initialize answer has a 60 s bound; past it the open fails
  with the ordinary startup-failure words and the host ends the child.
- The onOutput plumbing that only fed the silence rule is removed.

* Count Pi ready once it reports its state

Pi's start no longer waits for its model listing and slash commands.
The open returns after get_state and the unknown-provider check; the
listing then arrives as an options report (with the catalog listing the
start resolved) and the commands as a later publish. An empty model list
no longer fails the start as signed out: a signed-out Pi runs the unknown
provider, which still fails it, and a prompt it cannot run is refused
with the sign-in words by the existing prompt path.

get_state keeps the connection's 30 s request bound instead of the
startup ceiling.

* Test that model and effort picked while a chat is created ride its first message

A slow host's create reply arrives after the user picked a model and effort. The picker's view
layers the launch's held picks over its seed and the host's saved selection, and every send
carries what the picker shows, so the first message carries the picks whether the host's status
names its selection or not, and while the last pick is still on its way to the host.

* Start a phone's new empty chat on its first message

The phone's new chat is an agent.launch with no prompt, which always created the chat with its
agent started, while desktop chats start on the first message. The phone now advertises the
create-without-start capability, and a launch with no prompt from a caller advertising it creates
the chat at rest, keyed in the ledger by its create intent as a client's create is. Launches with
a prompt, the CLI (which advertises nothing), orchestration workers and ensure still start at once;
an older host ignores the capability and stays eager.

* Take main's lockfile; the branch changes no dependencies

* Restore main's exact text in files the merge only reformatted

The pre-commit formatter rewrote 37 of main's files staged by the merge, though this branch never changed them, pushing two past the line limit. Committed without the hook because the hook would reformat main's text again; CI lints the result.

* Fit the startup tests to the owned-spawn, host-awaited-open contract

Test doubles gain the mandatory open and an acquisition generation, the
removed started event gives way to the rig's proveStart, and two literal
types are tightened for CI's typecheck. A Stop during a held start writes
no host note on this branch: the taken-back send draws its own
stopped-before-start row, which the startup-attempt test now asserts.

* Fit the remaining CI checks to the startup limits and current releases

- Run agent-launch-at-rest.test.ts in the SQLite Node runtime project.
- Pin the send-options cross-version case to v1.4.228, the first published release with agent-session.send-options.v1; v1.4.226 was never pushed.
- Load the baseline's isStructuredTab from src/shared (moved in v1.4.228), falling back to the renderer path for older baselines.
- End the never-proven start with a short startup ceiling: the silence limit it relied on is gone, and the ceiling counts from registration.

* Read the option stamp from the chat's one host-execution selection

* fix: preserve startup authority and accepted agent choices

* Retain dispatch authority and reconcile accepted options

* fix(native-chat): preserve accepted choices and cancellation authority

* Restore established client selection flow

* Preserve provider output observation and typed startup fixtures

* fix: preserve initial Claude launch choices and effort readback

* test: complete Claude catalog session fixture

* Preserve incoming main files after merge formatting

* Preserve compact handover through startup merge

* Type instant startup fixtures before their open is supplied

* Keep browser sign-in under its existing expiry owner

* Finish the main merge: retired-model display, start rewind cut, new tests

A model the Claude CLI retired is reported again, so the picker shows what the child runs and the
next send moves the chat off it. The start reads a rewind in doubt against the handle it answered
with, the record its commit then applies to. Main's tests follow the start's open: the admission
fixture holds a real turn, and a sign-in close during setup fails the open.

* Type the start's rewind record as the store returns it

* Type the Sleep test's held open as the provider open it replaces

* Sleep counts a chat stopped once the start it aborted leaves it at rest

A start runs outside the chat's lane, so Sleep's step can run before the start it aborted has
settled; it then re-reads the chat once that start is done, instead of reporting it unverified.

* Keep Sleep's start-abort bookkeeping beside the rest of Sleep's stop
@brennanb2025

Copy link
Copy Markdown
Contributor Author

Folded into #28046, which merged as 5319125. Closing this draft; nothing here is lost.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant