Skip to content

trunk-merge/pr-1810/4d6c2826-5942-4688-8233-45a40cce8935-bisection - #1981

Closed
trunk-io[bot] wants to merge 17 commits into
mainfrom
trunk-merge/pr-1810/4d6c2826-5942-4688-8233-45a40cce8935-bisection
Closed

trunk-io[bot] wants to merge 17 commits into
mainfrom
trunk-merge/pr-1810/4d6c2826-5942-4688-8233-45a40cce8935-bisection

Conversation

@trunk-io

@trunk-io trunk-io Bot commented Oct 8, 2026

Copy link
Copy Markdown
Trunk Merge Pull Request Banner

This pull request was created and is being managed by Trunk Merge.

This pull request is based on the main branch at SHA 3a26d4b7d5e578a597b54c13c446067be6921b6a.

See more details here.

When CI completes, this pull request will be closed automatically.

Pull Requests Being Tested

This pull request is testing the changes from pull request 1810, stacked on pull request 1774.

Batch Bisection

This pull request is in a batch bisection. Pull requests successfully tested by this PR will re-enter the main queue.

rigel-mintaka and others added 17 commits October 6, 2026 23:50
…G-4452)

When the Runner's shared-stream ERRORED send stalls, it falls back to a
one-shot stream. Frames still buffered on the cancelled shared stream can
then be delivered after ERRORED and republish the session as live.

The hub now marks a session ERRORED and drops its later lifecycle frames.
A lifecycle lock serializes the guard with the status publish, so an
in-flight frame cannot publish after ERRORED. A recovery command (resume
Start, Reload) clears the mark under the same lock as the command's queue
admission, so a command that never reached the Runner leaves it set. A
re-enroll clears all marks. Trace frames still relay.

Co-authored-by: Matt Wilkinson <matt@rigel.build>
…ssion (RIG-4673)

A recovery command clearing the guard at admission left a window before the
Runner ran it, in which a dead-lifetime frame could still publish. The hub now
records ERRORED's RunnerSeq per session and drops lifecycle frames at or below
it. RunnerSeq is Runner-wide and monotonic, so new-lifetime frames pass on
their own; re-enroll resets the counter and clears the map. The recovery-
admission path (relayRecovery, router admit) is removed.

Co-authored-by: Matt Wilkinson <matt@rigel.build>
…ollment (RIG-4673)

Each container socket built its own Gateway counter, so a resumed session's
new socket restarted RunnerSeq at 1 and fell under the hub's ERRORED
boundary. agentHost now passes one SeqCounter to every Gateway, matching the
proto's per-Runner contract. The hub also stamps an enrollment generation, so
an ERRORED delivery paused across a re-enroll cannot reinstall a boundary the
re-enroll cleared. The stale-frame test now covers settle and presence edges.

Co-authored-by: Matt Wilkinson <matt@rigel.build>
…eqs close gaps (RIG-4673)

PublishEvents now stamps the hub's enrollment generation when the stream
opens. A session frame from an older stream is dropped before the tail relay,
lifecycle edges, and ERRORED's lost-session cleanup, so a resumed session
cannot be unbound by its dead process's late ERRORED.

Container Gateways share one RunnerSeq counter on separate streams, so a lower
seq can arrive after a higher one. The hub now tracks skipped seqs (bounded)
and SeenGap reports only those still unseen.

Co-authored-by: Matt Wilkinson <matt@rigel.build>
…cking per enrollment (RIG-4673)

An RWMutex now fences session-frame delivery (read) against enroll (write), so
the generation check, tail relay, and lifecycle edges cannot straddle a
re-enroll. ERRORED's detached cleanup carries its enrollment generation and
skips if a re-enroll has happened, so it cannot unbind a re-bound session.
Re-enroll resets the RunnerSeq gap tracker, and stale-stream events no longer
feed it.

Co-authored-by: Matt Wilkinson <matt@rigel.build>
…est (RIG-4673)

Separate streams can deliver one session's frames out of seq order, so an
ERRORED at seq 5 could land after the resumed READY at 6 and retire it. The
hub now keeps the highest accepted lifecycle seq per session and drops any
older lifecycle frame, ERRORED included, before the tail relay. Deliver holds
the enrollment read lock for the whole event, so a re-enroll cannot reset
sequence state between the generation check and its use.

Co-authored-by: Matt Wilkinson <matt@rigel.build>
Co-authored-by: Matt Wilkinson <matt@rigel.build>
…generation (RIG-4673)

A lifecycle frame now takes lifecycleMu before its seq is recorded, so a lower
seq cannot overtake a higher one that is still mid-delivery. Sessions reads its
router and enrollment generation as one pair, and enroll holds the write lock
until the new router is installed. Generations start at 1, so a PublishEvents
stream opened before the first Enroll is fenced too. lifecycleSeqs becomes a
bounded LRU. ERRORED cleanup's generation check is a synchronous helper with
its own test.

Co-authored-by: Matt Wilkinson <matt@rigel.build>
…(RIG-4673)

A cold binding lookup ran under the hub-wide lifecycleMu, so one slow store
read stalled lifecycle delivery for every session. Each session now has its
own refcounted lock held from seq record through publication. lifecycleMu
only guards the seq LRU and the lock map.

Co-authored-by: Matt Wilkinson <matt@rigel.build>
…-4742)

The detached ERRORED cleanup unbound whatever row held the session id when
it ran, so a resume that re-bound the same id in the same enrollment could
be unbound and archived by the old lifetime's cleanup.

A binding now carries the durable row version (xmin) and a cache lifetime.
The cleanup passes the binding it saw; dropLostSession skips a different
one, and releaseSession re-checks the cache around a delete conditioned on
that version. DeleteSessionBinding takes a version and reports a removal,
so a peer's re-bind is also left alone.

Co-authored-by: Matt Wilkinson <matt@rigel.build>
…G-4742)

xmin is a 32-bit transaction id and repeats after wraparound, so an old
cached version could match a later re-bind. binding_version is a fresh UUID
per upsert. The conditional release is a separate DeleteSessionBindingVersion,
and DeleteSessionBinding is back to its unconditional form for Stop. A cached
binding whose durable write failed has an empty version, which matches no
row, so its cleanup cannot delete a peer's row.

Co-authored-by: Matt Wilkinson <matt@rigel.build>
A cached binding whose durable write failed has an empty version. A legacy
row also has the column default '', so a versioned delete with '' could
remove it. The limited release now skips the store for an empty version.
The removed check no longer reads only, which nilaway could not prove
non-nil.

Co-authored-by: Matt Wilkinson <matt@rigel.build>
…ll versions (RIG-4742)

A cached binding with no durable version now checks for a competing row
before releasing. If one exists, the session was re-bound elsewhere: the
stale cache entry is dropped and no loss is reported. The migration also
gives pre-existing rows a real version, so no row keeps the '' default.

Co-authored-by: Matt Wilkinson <matt@rigel.build>
…sion (RIG-4742)

A cleanup that found its row re-bound evicted only the session's cache
entry. The reverse account entry still named the session, so delivery for
the old account could reach the new owner's session. Evict both.

Co-authored-by: Matt Wilkinson <matt@rigel.build>
A stale-version delete records nothing; the current-version delete ends
its open interval.

Co-authored-by: Matt Wilkinson <matt@rigel.build>
…h enroll (RIG-4742)

A binding learned through SessionForAccount had no version or lifetime, so
its ERRORED cleanup took the version-less path, found its own row, and
never released or reported it. The reverse read now returns the version.

A Stop's release now takes bindingWriteMu, as promotion does since the
rebase onto the enroll serialization, so its delete cannot land between
an enroll's map-clear and its reap and hide the session from the sweep.

Co-authored-by: Matt Wilkinson <matt@rigel.build>
@github-actions

github-actions Bot commented Oct 8, 2026

Copy link
Copy Markdown

Compass engineering docs preview: https://trunk-merge-pr-1810-4d6c2826.compass-eng-docs.pages.dev

Deployed from trunk-merge/pr-1810/4d6c2826-5942-4688-8233-45a40cce8935-bisection at d0567c7.

@trunk-io trunk-io Bot closed this Oct 8, 2026
@trunk-io
trunk-io Bot deleted the trunk-merge/pr-1810/4d6c2826-5942-4688-8233-45a40cce8935-bisection branch October 8, 2026 05:46
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