BuilderProof editorial team14 min read7 views

Does the Second Tab Know? A Proposed Axis for Multi-Tab State Coherence (September 2026)

An AI app builder is validated in one browser tab, and every defect in this class needs two. A pre-registration for a multi-tab state coherence axis, with the platform documents that state both the hazard and the remedy.

Updated on September 23, 2026

Flat line diagram of two identical browser windows side by side on a cream background. The left window holds one solid navy filled circle, the right holds one pale grey hollow circle, and a short dashed navy line runs between them. No text appears in the image.
Flat line diagram of two identical browser windows side by side on a cream background. The left window holds one solid navy filled circle, the right holds one pale grey hollow circle, and a short dashed navy line runs between them. No text appears in the image.
On this page

Quick Answer (September 2026). An AI app builder is validated in one browser tab. Every defect in this class needs two. This is a pre-registration for a proposed BuilderProof axis measuring what the second open document of a generated application does when something changes in the first: a sign-out, a role change, a token refresh. No builder is scored here and no vendor is placed. The argument is only that the property is real, that its failures are invisible in the loop that produces the code, and that the platform documents both the hazard and the remedy in places that never reference each other.

Why this needs its own axis

We have already named this problem once, in writing, and declined to score it.

Our concurrent-write safety proposal opens its limitations section with the heading "The single-tab measurement problem cuts both ways", and continues: "If the defect is invisible in a preview, it is also hard to demonstrate in a screenshot. A static read of the export is verifiable and cheap, but it measures the shape of the code rather than an observed failure." That is an honest caveat about its own measurement of write contention. It is not a claim about what a second document shows, and that axis makes none. The vocabulary exists in our corpus; the subject does not.

The second reason is a sentence on our own output-quality leaderboard, which states that every tool in this cohort now produces something that looks right, and what separates them is the shape of the code underneath. That page is the right place to judge the artefact, and it is the reason this axis is not a code-quality complaint. The code rendering each document here is, in isolation, correct. Both tabs are running the same correct build. The defect lives in the space between them, which is precisely why a measurement of the artefact cannot reach it.

What the sources actually say

MDN The platform ships two mechanisms for one document to tell another that something changed, and both are specified not to notify the document that acted.

The first is the storage event. MDN states it "fires when another document that shares the same storage area (either localStorage or sessionStorage) as the current window updates that storage area", and then, plainly: "The event is not fired on the window that made the change." Its reach differs by storage area, and the difference is the whole game. For localStorage, "the event is fired in all other browsing contexts that are in the same origin as the initiating document. This includes other tabs with the same origin." For sessionStorage, it is fired only in contexts sharing "the same top-level browsing context", which MDN spells out as "only includes embedded iframes, if any, in the same tab, and not other tabs." A build that keeps its session in sessionStorage has no cross-tab channel at all, and nothing about the code will look wrong.

The second is BroadcastChannel, which MDN describes as "a named channel that any browsing context of a given origin can subscribe to", allowing "communication between different documents (in different windows, tabs, frames or iframes) of the same origin". Messages reach "all BroadcastChannel objects listening to the channel, except the object that sent the message."

Two different APIs, defined a decade apart, and each carries the same exclusion of the acting document.

WHATWG The standard is more direct than either, and it is the strongest source here because it states the hazard and then explicitly declines to solve it. The HTML Living Standard, in its Web Storage section, says: "This specification does not define the interaction with other agent clusters in a multiprocess user agent, and authors are encouraged to assume that there is no locking mechanism." It then supplies its own worked example: "A site could, for instance, try to read the value of a key, increment its value, then write it back out, using the new value as a unique identifier for the session; if the site does this twice in two different browser windows at the same time, it might end up using the same 'unique' identifier for both sessions, with potentially disastrous effects."

That is the standard describing this exact defect class, in two windows, and instructing authors to assume nothing protects them.

The same section carries a second fact that a generated app will get wrong by default. "After creating a new auxiliary browsing context and document, the session storage is copied over." A duplicated tab therefore inherits session storage, while a newly opened tab does not. One application, two ways of arriving at a second document, two different starting states.

The remedy exists and arrived separately. The Web Locks API, in MDN's words, "allows scripts running in one tab or worker to asynchronously acquire a lock, hold it while work is performed, then release it. While held, no other script executing in the same origin can acquire the same lock, which allows a web app running in multiple tabs or workers to coordinate work and the use of resources." It is available only in secure contexts, and available across browsers since March 2022.

So the seam is clean. One document says the hazard exists and tells you to assume you are unprotected. Another document supplies the protection. Neither references the other, and nothing in a generated project joins them.

The control that carries no information

There is a test a developer will run, and the platform has specified it to prove nothing.

Sign out. Watch the page update. It does, correctly and immediately, because the document that acted re-rendered its own state locally. That observation is compatible with a build that has a perfect cross-document channel and with a build that has none at all, and it is the only observation a single open tab can produce.

The same trap catches the developer who tries to verify the mechanism directly. Write a value to localStorage, listen for the storage event in the same tab, observe nothing, and conclude the channel is broken. It is not broken. It is behaving exactly as MDN documents, and the same is true of BroadcastChannel, which excludes its own sender.

Both readings are wrong, they point in opposite directions, and both are produced by a correct implementation under a single-document test.

The proposed rubric

Weights sum to 100. Nothing below has been scored against any builder.

Scroll to see more

SignalWeightWhat a failing case looks like
A sign-out in one document ends the session in the others22Tab B keeps rendering an authenticated shell with the user's data until it is manually reloaded
Credential refresh is serialised across documents20Two tabs refresh the same token at once and one of them is signed out by the other's rotation
The cross-document mechanism is one specified to reach other documents16State is kept in sessionStorage, so the channel cannot cross a tab boundary by definition
Authorisation changes propagate, not only authentication14A role is revoked, tab B still renders the admin controls, and the refusal only arrives as an opaque failure on click
Cached view state is invalidated in the non-acting document12A record is deleted in tab A and tab B lists it indefinitely
Storage scope is chosen deliberately9A duplicated tab behaves differently from a newly opened one and nothing in the code anticipated either
A returning document revalidates when it becomes visible7A tab left open for a day shows yesterday's state the moment it is focused

Why the first signal carries the most

Six of these seven signals produce staleness. A stale list is wrong, it is annoying, and a reload fixes it.

The first produces a misrepresentation about the user's own account. An authenticated shell rendered after a sign-out tells someone that a thing they just did did not happen, on a machine they may have signed out of precisely because they were about to hand it to somebody else. The consequence is not a wrong number on screen; it is a correct action that appears to have failed.

It is also the only signal whose remedy requires no server involvement of any kind, which is what makes its absence a design omission rather than an infrastructure cost.

Four postures

Level 0, Isolated. Each document is an island. No cross-document mechanism appears anywhere in the export.

Level 1, Announced. A mechanism exists and carries at least the sign-out event to other documents.

Level 2, Coherent. Authorisation changes and cached view state propagate as well, and the mechanism is chosen for the reach it actually has rather than inherited.

Level 3, Serialised. Shared writes to the credential are taken under a lock, so two documents cannot race the refresh at all.

The ladder is not evenly spaced, and it is worth saying why. The step from 0 to 1 is the only one that changes whether a second document is reachable at all, so it is the only step a demonstration can show. The step from 1 to 2 is the only one an ordinary user can notice without signing out, because it is the only one that changes what a document shows while it remains authorised. And the step from 2 to 3 is the only one that produces a guarantee rather than a behaviour: a lock constrains what can happen, where every level below it describes what does happen on the runs you observed.

Reproduction protocol

  1. Build from the fixed prompt and export the project untouched.
  2. Census the cross-document surface in the export: occurrences of BroadcastChannel, a storage event listener, navigator.locks, and any multi-tab option on the auth client. Record zero as zero rather than as absence of evidence.
  3. Run the control and record that it is a control: open one document, sign out, confirm it updates. Both cross-document mechanisms are specified not to fire in the acting document, so this step carries no information and exists to stop it being mistaken for a result.
  4. Open two documents of the same URL in the same browser profile, signed in as the same user.
  5. Sign out in document A. Without touching B, record what B shows at 0 seconds, 30 seconds and 5 minutes, and separately record what happens on B's next data-bearing interaction.
  6. Separate the two failures. Does B render an authenticated shell with stale data, which is a view defect, or does B's next request fail in a way B cannot classify, which is an error-reporting defect? A build can have either without the other.
  7. Authorisation probe: with both documents open and authorised, change the user's role server-side. Record whether B's interface changes, and separately whether B's next privileged request is refused.
  8. Refresh race: leave both documents idle across a token-refresh boundary and record whether either is signed out. Run it three times. A race that fires once in three is a defect, not noise.
  9. Scope probe: duplicate a tab rather than opening a new one. The standard says session storage is copied on duplication, so a build keyed on session storage will behave differently for the two cases. Record both.
  10. Provenance probe: separate "the framework's auth client happens to ship cross-tab behaviour" from "this application chose it", by reading the export for an explicit option rather than inferring from observed behaviour.

What this axis is not

Not our session-lifetime and revocation axis. That axis asks whether the server can end a session. This one asks whether the other open document finds out. Stated both ways: a build can revoke perfectly server-side, scoring well there, while tab B renders an authenticated shell for as long as it is left open, because revocation is a server-side fact and nothing pushed it to the client. And two documents can stay perfectly synchronised, scoring well here, on a credential the server will honour forever. Read the session-lifetime proposal for what that axis does cover.

Not concurrent-write safety. That axis is two writers contending for one row. This one is one writer and one stale reader who are the same person. Stated both ways: a build can hold a correct optimistic-concurrency check on every write and still show tab B a deleted record indefinitely, because nothing told B; and two documents can stay in perfect sync while the write path underneath silently loses updates.

Not realtime subscription correctness. That axis is about somebody else's write reaching you over a server channel. This one is about your own action in your own other document, which needs no server at all. The sharpest version: a local sign-out is a client-side credential discard that generates no server event, so a flawless realtime subscription is structurally blind to it. The mechanisms differ in the same direction, and this is a genuine composition rather than an overlap: BroadcastChannel and the storage event are local, so they still work when the network does not. Read the realtime subscription proposal for the server-channel half.

Not a code-quality finding. This belongs in the same family as the illusion named in our output-encoding proposal, where the only content available at test time is content the developer wrote. Here the only document available at test time is the document the developer opened. Both are one-actor illusions, and the trap for this one is the single-tab illusion: the development loop produces exactly one document, and an AI app builder's preview pane is a single embedded frame that cannot be opened twice at all, so the surface on which the application is judged is structurally incapable of expressing the condition under which it fails.

Limitations and open questions

  • It is a two-document test. It says nothing about ten, and a lock that serialises two refreshes may behave differently under more.
  • Posture 3 is gated by a browser floor we score elsewhere. Web Locks requires a secure context and has been available across browsers only since March 2022, so a build targeting an older floor cannot reach Level 3 without a fallback. This axis and our browser-support axis are therefore coupled, and neither can see the coupling alone.
  • A tension with our own session-lifetime rubric. That axis rewards short token lifetimes with frequent refresh. Frequent refresh across several documents is exactly what creates the race in signal 2, and the remedy is a lock the browser floor may not permit. Raising the score on one axis raises the failure rate measured by the other. We think the resolution is ordering rather than choice: serialise first, shorten second. We would like the argument against.
  • Neither mechanism is sufficient alone. BroadcastChannel reaches live documents and carries no state, so a document opened later learns nothing; the storage event carries persisted state but never fires in the writer. A build that picks one and stops has a gap either way, and we have not decided whether to score the combination or the coverage.
  • Some of Level 3 may be inherited rather than chosen. Step 10 separates this partly and not completely.
  • The axis is browser-scoped. A native or mobile wrapper has a different document model and is out of scope.
  • It is a point-in-time read of documentation as of September 2026, and every source below is linked so the check can be re-run and disputed.

Corrections, counterexamples from real exports and rubric edits are welcome, and the rubric is published before any score exists precisely so it can be attacked first.

References

Cite this benchmark

Plain text
BuilderProof editorial team. "Does the Second Tab Know? A Proposed Axis for Multi-Tab State Coherence (September 2026)". BuilderProof, September 2026. https://www.builderproof.org/benchmarks/does-the-second-tab-know-multi-tab-coherence-axis-september-2026.
BibTeX
@misc{builderproof-does-the-second-tab-know-multi-tab-coherence-axis-september-2026,
  title  = {{Does the Second Tab Know? A Proposed Axis for Multi-Tab State Coherence (September 2026)}},
  author = {{BuilderProof editorial team}},
  year   = {2026},
  month  = {sep},
  howpublished = {\url{https://www.builderproof.org/benchmarks/does-the-second-tab-know-multi-tab-coherence-axis-september-2026}},
  note   = {BuilderProof, builderproof.org}
}

Frequently asked questions

What is multi-tab state coherence in an AI app builder?

It is a proposed BuilderProof benchmark axis measuring what the second open document of a generated application does when something changes in the first: a sign-out, a role change or a credential refresh. It is a pre-registration as of September 2026, and no builder has been scored against it.

Why would a generated app get this wrong when the code looks correct?

Because the code for each document is individually correct. Both tabs run the same correct build, and the defect lives between them. The platform also specifies both cross-document mechanisms not to fire in the document that acted, so the natural single-tab test observes nothing and proves nothing in either direction.

Is this the same as being able to log someone out?

No. Session lifetime and revocation asks whether the server can end a session. This axis asks whether the other open document finds out. A build can revoke perfectly server-side and still render an authenticated shell in a second tab for as long as it is left open, because revocation is a server-side fact and nothing pushed it to the client.

Does the HTML standard say anything about this?

Yes, and it declines to solve it. The WHATWG HTML Living Standard says authors are encouraged to assume that there is no locking mechanism between documents, and supplies its own worked example of the same value being read, incremented and written back in two browser windows at once, with what it calls potentially disastrous effects.