Repository navigation
fix(server): a thread's strip no longer takes in another agent's tab - #207
Merged
Merged
Conversation
The overlay records any tab the thread's agent-browser session newly binds (LazurioPlatform F47 point 4). agent-browser records a fresh daemon's own pick of a tab, the first live one of the browser, even after a failed `tab <id>`, so `lazurio browser window` could leave the thread's session on a tab another agent had pinned and was working in (Lazurio/LazurioPlatform#974). The watch on the socket directory picks such a binding up within 100 ms and the strip then holds and shows that tab. The Platform now removes such a binding after a failed bind, but only after the daemon has written it. A new binding is now taken into the strip only when the thread's strip has the tab already, or no other strip holds it and no other session's binding names it. preview_open and a person's holds are unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This was referenced Nov 14, 2026
immakermatty
marked this pull request as ready for review
November 14, 2026 23:17
agentrozjedemeai
approved these changes
Nov 14, 2026
agentrozjedemeai
left a comment
Collaborator
There was a problem hiding this comment.
No blocking findings.
Non-blocking: The focused thread-tabs tests and release contract passed. check:changed passed format, lint, knip, GraphQL and typecheck, but its unrelated AgentContextBudget test failed locally on Node 24.22.2 (the repo pins 26.12.1); CI is still running. I did not verify the behavior in a browser.
Order and migrations: release this overlay together with or before Lazurio/LazurioPlatform#986 to close the interval before its failed-binding cleanup.
— Pablo
6 of 9 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.
Status: in progress (Draft). Companion to Lazurio/LazurioPlatform#986, which fixes Lazurio/LazurioPlatform#974 on the Platform side.
Problem
The overlay adds to a thread's strip any tab the thread's agent-browser session
t3-<id>newly binds (LazurioPlatform F47 point 4). agent-browser (0.37, and still the 0.43 candidate) writes a binding even after a failedtab <id>, and that binding names the tab a fresh daemon picked itself at attach: the first live tab of the browser, whoever's it is. In pingdotgg#974,lazurio browser windowfailed to bind a thread's session to its new window, and the session was left on a tab another agent had pinned and was working in. The watch on the socket directory saw the binding within 100 ms, so the strip held that tab and the thread's panel showed it.LazurioPlatform#986 now verifies the binding and removes one a failed bind left on another tab. That happens only after the daemon has written it (about 0.2 s measured, longer when the command outlasts the runner), which is still well inside this watch's 100 ms debounce. So the overlay has to refuse the tab too.
Fix
A new binding of the thread's session is taken into the strip only when one of these holds:
readBindingskeeps which sessions each tab is bound to (boundBy), andrefreshchecks it together with the holder files it already reads. A skipped binding logsthread-tabs-binding-not-recorded.preview_open, a person's holds, archive and the reconciliation are unchanged.Why not "only bindings confirmed by a window record"
LazurioPlatform pingdotgg#971 writes
windows/<session>.jsononly for a new window thatlazurio browser windoworlazurio apps openopened. Taking in only bindings that such a record confirms would drop the tabs F38 point 2 relies on:lazurio browser openbinds the thread's session to a tab the hub opened, without a record, and T3 shows that tab only because the binding is new. It would also drop an agent's owntab newinside its session. The record answers whose window a session is. It does not say which tab an unrecorded binding names, so the overlay refuses what is evidently another's instead.Verification
apps/server/src/lazurio/threadTabs.test.ts, new case in "tabs an agent opens": a binding to a tab another session is bound to, or another strip holds, is not taken in; one the strip holds already is revealed; the thread's own next window is recorded. It fails onmain(expected [ { …(2) } ] to be null) and passes here (37/37 in the file).scripts/lazurio-release-contract.test.mjsfollows the new shape (52/52).vp run check:changed: format, lint, knip, graphql and typecheck pass.src/provider/AgentContextBudget.test.tsfails locally (measuredcodexAdditionalContextBytes8838 against 7327). It fails the same way with a clean environment, it does not touch this change, and Fork CI onmain439c780 passed it. The local run used Node 24.22.2, not the pinned 26.12.1. CI decides.docs/operations/lazurio-overlay.md("Jak záložka do pásu vlákna přijde") states the rule.Only files in the overlay's own
apps/server/src/lazurio/, its spec and its contract test change, soallowed_upstream_changesis untouched.Made with Claude Opus 5.5 in Claude Code (T3 Code thread).
Agent: environment a480495c-25e0-4e51-828b-1dbf1b77d62f · T3 thread 22786896-3028-4190-962d-8b4986732ca0
🤖 Generated with Claude Code
Note
Fix thread strip conflicts so a thread only takes tabs it owns
readBindingsreader and the newanothersTabconflict helper. Therefreshprocessor uses this to guard each fresh thread-session binding.Macroscope summarized 4b910af.