fix(session): fence turns to durable session owners - #1550
Merged
Conversation
…ble-session-owner-min
Adapt PR #1550 to the post-1572 session reset boundary and preserve explicit event epochs during owner-fenced delivery.
Open-Squilla
enabled auto-merge
September 6, 2026 20:41
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.
Scope
Scope boundary:
Queued or running work can outlive reset or delete/recreate of its logical session key. Previously, late writers could look up the replacement session and acquire its identity. Bind modern admitted turns to an immutable
session_idandsession_epoch, persist that pair in task details, and preserve it through execution, callbacks, events, and restart recovery. Exact-owner storage checks reject retired work instead of letting it write into the replacement transcript or update its state.Coverage includes Web, CLI, Channel, Goal, Cron, and subagent ingress; input persistence and task activation; transcript, finalizer, error, cancellation, and usage writes; lifecycle events; and recovery after restart. Independent
sessions.resetextends its quiesce/drain protection across task, direct-turn, and background writers before rotating ownership. Atomic send/reset paths retain the admitted owner through cancellation cleanup.The branch includes the current
mainat085bfed00de2cfddf056210a28159f8282f46f77and adapts ownership checks to the separated application lifecycle, admission preparation, and direct-turn runtime adapters. If reset cannot fully drain session work, the wire response is retryableSTORAGE_BUSYwithretryAfterMs: 250; the Python and TypeScript generated contracts include this error.Compatibility:
RouteEnvelope.session_epochis append-only and preserves positional callers.Non-goals:
Branch
Base branch: main
Target exception: N/A
Issue
Linked issue: None
If None, reason: repository hardening work without a linked public issue.
Release Note
Release note: Session ownership checks prevent late output from queued, running, recovered, scheduled, and subagent turns from contaminating a reset or recreated session.
Tests
Ruff: the current-head CI lint, test, and build job passed.
Pytest:
636d89e0d8da7c226a206968404ffd8aa6b15412; CI run 34062079566.Build: frontend package validation, release packaging contracts, lint/build, Linux and Windows Gateway Contract verification/determinism, cross-platform hash comparisons, and managed-toolchain artifact jobs passed. Both the aggregate PR
CI resultand complete merge-queue CI passed. The queue ran the full matrix because this PR changes CI policy inputs.Regression tests: added
Notes:
The CI integration tests use real RPC dispatch, TaskRuntime, SessionManager, and isolated SQLite where applicable, with controlled turn/provider bodies. The independent-reset drain test establishes its own quiesce ordering; it is not a substitute for the atomic send/reset late-writer case.
The final two CI-only commits register the new subagent test in the fixed Windows shard/duration inventories and account for the new lifecycle helper functions in the architectural ownership manifest. No test was disabled, assertion relaxed, or timeout increased.
The initial queue run hit one Windows core subprocess startup timeout in
test_unleased_build_services_does_not_sweep_another_process_reservation. The same-head isolated test and complete eight-test file passed locally. In the replacement full queue run, that case passed in 14.861 seconds without a skip, and the Windows core shard had zero failures/errors. The 30-second budget was unchanged. The original timeout is retained as a timing limitation; its unique root cause was not established.The default test path remains offline, deterministic, credential-free, and safe for forks.
Maintainer Live Check
Maintainer live check: no
Surface: gateway
Maintainer-only note: No real user profile, credentialed provider, live channel, or released installer was exercised. CI browser/desktop evidence does not establish those live scenarios.
Safety
Secrets, local-only artifacts, private prompts/transcripts, channel identifiers, AI session artifacts, non-public fixtures, and tests/_private/ contents are not committed.
Third-Party Origin
Third-party origin: none
Details if non-none: The implementation is independently designed. No third-party implementation was copied or adapted, and no dependency was added.
Documentation Changes