Skip to content

fix(session): fence turns to durable session owners - #1550

Merged
Open-Squilla merged 15 commits into
mainfrom
fix/durable-session-owner
Sep 7, 2026
Merged

fix(session): fence turns to durable session owners#1550
Open-Squilla merged 15 commits into
mainfrom
fix/durable-session-owner

Conversation

@lihongguang-0014

@lihongguang-0014 lihongguang-0014 commented Sep 1, 2026

Copy link
Copy Markdown
Collaborator

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_id and session_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.reset extends 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 main at 085bfed00de2cfddf056210a28159f8282f46f77 and 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 retryable STORAGE_BUSY with retryAfterMs: 250; the Python and TypeScript generated contracts include this error.

Compatibility:

  • RouteEnvelope.session_epoch is append-only and preserves positional callers.
  • Legacy ownerless and ID-only tasks/adapters remain supported; modern epoch-bearing work requires explicit owner-aware APIs and fails closed if their storage contract is unavailable.
  • Explicit event epochs, including zero and older values, are preserved. Only missing legacy epochs use the current-epoch fallback.
  • Cron/subagent inputs retain their original message identity without duplicate persistence.
  • Existing task details store owner metadata; no database migration or new table is required.

Non-goals:

  • No routing, plan, or goal-model unification.
  • No provider-selection change or public protocol-version change.
  • No database migration or new persistence table.

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:

  • Current head: 636d89e0d8da7c226a206968404ffd8aa6b15412; CI run 34062079566.
  • All Linux offline and Windows high-risk shards passed.
  • Downloaded JUnit confirms 47 shard-contract tests, 33 RPC architecture-contract tests, and 17 subagent-owner tests passed on each of Windows and Linux, with no skips in these three files.
  • Eleven additional selected regression cases passed on each OS: blocked-provider reset drain, same-epoch/different-session-ID CAS rejection, retired finalizer rejection, stale queued/running/terminal lifecycle events, and recovery owner checks before activation and after preflight.
  • WebUI chat recovery and the complete Desktop recovery E2E matrix passed.

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 result and 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

  • Links point to existing repository files or stable external pages.
  • Code fences and Markdown tables render correctly on GitHub.
  • Examples avoid real secrets, local private paths, and private transcripts.

@Open-Squilla
Open-Squilla self-requested a review as a code owner September 6, 2026 21:26
@Open-Squilla
Open-Squilla added this pull request to the merge queue Sep 6, 2026
@Open-Squilla
Open-Squilla removed this pull request from the merge queue due to a manual request Sep 6, 2026
@Open-Squilla
Open-Squilla added this pull request to the merge queue Sep 6, 2026
Merged via the queue into main with commit cfa8e4b Sep 7, 2026
51 checks passed
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.

2 participants