Repository navigation
feat(native-chat): keep the proof that an agent is gone after the next owner starts - #26667
Closed
brennanb2025 wants to merge 14 commits into
Closed
brennanb2025 wants to merge 14 commits into
brennanb2025 wants to merge 14 commits into
Conversation
…ry other chat Starting, resuming or switching a chat's agent first ran restart reconciliation, which probed every unreconciled session and committed them together, so one slow or failing probe for another chat delayed or failed this chat's action. Acquisition now reconciles only the addressed session; the explicit startup pass still covers all of them, and an owner that isn't proven still can't be granted a writer. Co-Authored-By: OpenAI Codex gpt-6.1-sol <noreply@openai.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…sqlite tests - Startup restore no longer lets one chat's failed lease check skip recovery for the others. - Run the two new SQLite-backed tests in the Node runtime project. - Startup reconcile runs the whole-host pass without a placeholder session id. - Test names describe an injected failing/stalling owner check, not an SSH host.
The restore opens with the whole-host pass again and stops per-chat bookkeeping after the first failure, as on main: on a failing store it makes one lease-check write, not one per chat. User actions stay targeted to their own chat.
…ocks starting a chat After a restart, starting or resuming a chat first settled the status of sends from the previous run, and a failed settlement write failed the start. Settlement is now best effort: unconfirmed sends keep showing as unconfirmed and keep their replay protection, the failure is logged and retried later, and the user's start proceeds. Co-Authored-By: OpenAI Codex gpt-6.1-sol <noreply@openai.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…rovably starts before it A send whose verdict failed to save stays unconfirmed; a later turn can move the resume point the next restart reads from past it, and that history then reads the delivered send as never sent. The reconciler now rejects an absent send only when it was handed over at or after the fence of the owner that last moved that resume point (derived from the record's chain head and the journal fold); otherwise it stays unconfirmed. Presence still settles it. Also: settlement failures are injected at the SQLite transaction in tests and checked on disk; re-attaching to a running agent keeps it when a settlement fails; docs on what a failed settlement leaves now say what is true.
…last moved Round-1 dated the start from the chain head, but every later acquisition re-proves an unmoved resume point as a new link, so one undecided attach left a truly undelivered send unconfirmed forever. The start is now the first of the trailing links that carry the head's handle, leaf included. The same owner can also move the point past a send it handed over (a turn end after an unrecorded accept), so at an equal fence the reconciler now rejects only when the point moved strictly before the handover on that owner's clock; a tie stays unconfirmed. attachJournal no longer samples history itself (only tests did, from the post-acquisition record); callers pass the sampled window.
… and time together A send handed over twice (legacy rows) paired its first handover's fence with its last handover's time. Both now come from one derived firstHandover. Also drop a writer comment about a pending retry path that no longer exists.
…-its-own' into brennanb2025/chat-closed-owner-history
…tlement-best-effort' into brennanb2025/chat-closed-owner-history
…t owner starts The proof that an agent generation died lived in one mutable lease field that the next reservation cleared, so after a failed cleanup or a restart nothing durable said which generation was gone. Record each proven ending as an immutable closed-owner fact in the owner store, in the same transaction as the transition that proved it, keyed by execution scope, session and dead owner fence. Unproven endings write nothing. A staged receipt deletes a fact inside the journal write that settles it, and deleting a session removes its facts. Nothing consumes the facts yet.
9 tasks done
…r-change' into brennanb2025/chat-closed-owner-history # Conflicts: # src/main/native-chat/agent-session-wire/structured-agent-session-attach-flow.ts # src/main/runtime/agent-session-record-store.ts
Bumping the host schema made every older build open this database read-only, refusing all chat writes and launches. The table is now created at every writable open, like the queued-message table, and its one-time migration of old proofs runs in the same transaction that first creates it, so a retired fact never comes back. Drop the stored journal boundary: taken at reservation it came before rows the dead generation still writes, and every row already carries its fence. Register the two new SQLite test files for the Node runtime.
7 of 9 tasks
Contributor
Author
|
Closing as superseded by #26867. This PR kept the proof that an agent is gone after the next owner starts, so that leftover work could be cleaned up later. #26867 removes the need for that proof. Leftover work is now settled when ownership changes:
|
Closed
3 of 6 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
ELI5
After an agent dies, its chat can stay stuck on “Working” or an old approval. If saving the result fails, starting the next owner clears the only saved proof of which agent generation died. A restart can then lose the information needed to finish that old work.
This PR changes nothing users see yet. It keeps the proof after the next owner starts. The next PR in this stack will use it to finish old work when ownership changes, fail a start if that result cannot be saved, and retry at the next ownership attempt. Opening history will stay read-only.
What Changed
The execution host now stores one immutable closed-owner fact per session and owner generation in its existing chat database. Each positive exit, proven eviction, failed acquisition with proof, or proven replacement commits the fact with its ownership transition, before mutable evidence is cleared. Facts contain the proof, the old process identity without its spawn token, and the known journal cutoff. They survive replacement and restart.
The store exposes facts oldest first and passes the committed fact to death listeners while preserving current callers' notification behavior. A journal receipt can delete a fact in the same transaction that saves the result making it unnecessary; deleting the session also deletes its facts. This PR does not invoke that receipt from production. Host-only process snapshots and existing fence comparisons reject stale probes without closing a successor; public wire shapes are unchanged.
The host schema advances to version 5 so an older host uses the existing read-only refusal instead of changing owners without maintaining this history. A one-time migration preserves safely attributable old proof; missing identities and historical cutoffs stay unknown.
Why
Keeping the single mutable field loses old proof when the next owner starts. An in-memory copy cannot survive restart and misses replacement's fresh probe. A “cleanup owed” flag would duplicate state without recording which owner actually died. A past ownership fact preserves the cause and generation, and its delete receipt provides a definite end when the journal result commits.
Compared with the common pattern:
unverifiable.Linked Issue
Maintainer work in the approved lane C stack. No separate issue is linked. This is preparation for the stuck-chat fix, not a claim that this PR alone fixes it.
Visual Proof
N/A — this PR changes host-only ownership persistence and preserves existing UI and ordinary interaction behavior.
Testing
On macOS, the final explicit-file run passed 42 files and 434 tests with two workers and background launch enabled. New real SQLite tests cover positive ownership transitions and rollback, fresh reservation proof, retention after replacement/restart, no proof on expiry/uncertainty/unproven release, stale fence and same-fence identity protection, receipt commit/rollback, record deletion, migration and newer-schema write refusal. Existing ownership, restart, attachment, journal and stored-record tests passed unchanged apart from the state fixture's new history map.
Oxfmt, changed-file oxlint, and the changed-code quality gate pass. React Doctor reports four existing warnings in dependency-stack files and no new findings. Node, web and cli typechecks pass. No build, live SSH/WSL run or rendered UI check is claimed here; CI covers the full suite. Remote and folder scopes are covered by fixtures.
AI Disclosure
Review
Second PR of a stacked series. The branch also contains #26555 and #26577 (merged in, unchanged) because the follow-up builds on them; their diffs are reviewed in those PRs.
Agent skill upstream boundary
Notes
Merge #26555 and #26577 first, then #26664, then this PR. Host schema fencing preserves older-host safety; clients exchange the existing wire shapes. The execution host owns proof and history, including remote and WSL scopes. Folder workspaces require no Git operation. Facts contain no account home, claim key, or spawn token. No retry flag or timer is introduced.
Author: Brennan Benson (@BrennanKB5).
Checklist
N/Awith reasonpnpm lint,pnpm typecheck,pnpm test, andpnpm buildpass (or CI will cover; local preferred)