Split out of #5746 (closed latent-not-live) as the one reading that card measured but could not decide. Filed unassigned, deliberately unlabelled — this needs triage first-touch, and the deciding question is server-side, outside what the domain:ui seat can measure.
The reading
#5746 measured both of its named windows SHUT: on a real apps/console session the metadata seed is never written under the @anon principal, because ConsoleShell's #4042 session gate holds MetadataProvider from mounting until getSession() has already written TokenStorage (true for bearer and cookie-only sign-in — better-auth v1.6.28 returns session.token either way).
Two boots outside those windows do write @anon:
- a guest boot —
ConditionalAuthWrapper with enabled={false} previewMode
both writing objectui:metadata:app:@none:@anon.
Why this is not obviously a defect, and not obviously safe
The argument that these are harmless is that ConditionalAuthWrapper selects those branches only when discovery reports an auth stub / handlerReady:false, or the deployment is a marketplace preview — i.e. precisely when the server is not filtering /meta/* per user, so the cached list is not a permission-filtered artifact and there is no cross-principal disclosure to make.
⚠️That argument is REASONED, not measured.#5746's dev flagged it as such rather than presenting it as a result, which is why it is being carried here instead of being closed with the parent card. Confirming or refuting it means establishing what the server actually serves on /meta/* for a stub-auth or marketplace-preview deployment — a question this repo cannot answer from the client side.
apps/console never takes either branch, so nothing shipped in the console is implicated. The exposure, if any, is in stub/preview deployments.
What #5746 established that bears on this
The parent card's most load-bearing finding is a correction: #5744's wholesale drop does not cover the seed read. React runs child effects before parent effects, so MetadataProvider's seed read (a child effect, newly mounted in the commit where isLoading flips) precedes AuthProvider's purgePreviousUserClientState (a parent effect). The principal-scoped key from #5198 is the sole protection on that boot — measured, not argued: with TokenStorage empty on an authenticated session, a second user booting in the same tab HIT the first user's key and rendered hr-secret.
So a @anon write is only benign for as long as the thing being cached is not permission-filtered. That is exactly the property this card needs someone to establish for the two synthetic-identity branches.
An asset that exists and is not merged
#5746's harness renders the real console mount path — real AuthProvider, real ConnectedShell session gate, real MetadataProvider, with only the two servers doubled, and nothing writing objectui:metadata:* by hand (so it cannot agree with a key format the provider does not produce). It is the instrument that produced every reading above, including the S4/S5 writes this card is about.
It lives unmerged on claude/issue-5746-anon-seed-scope-measurement at packages/app-shell/src/console/__tests__/anonSeedScope-5746.enumeration.test.tsx.
Worth considering — as a recommendation, not a decision — landing it as a regression pin alongside whatever this card rules, given that the main safety property now rests on a single mechanism. Two instrument defects it already caught are documented in its own comments, both of which would otherwise have produced a false "no writes anywhere" reading: jsdom hands out sessionStorage as a Proxy (so this === sessionStorage is never true inside a Storage.prototype method), and vi.restoreAllMocks() does not undo a reassigned property.
Refs: #5746 (parent, closed latent-not-live) · #5198 (the principal-scoped key) · #5744 (the purge that does not cover this) · #4042 (the session gate that shuts both named windows).
Generated by Claude Code
Split out of #5746 (closed
latent-not-live) as the one reading that card measured but could not decide. Filed unassigned, deliberately unlabelled — this needs triage first-touch, and the deciding question is server-side, outside what thedomain:uiseat can measure.The reading
#5746 measured both of its named windows SHUT: on a real
apps/consolesession the metadata seed is never written under the@anonprincipal, becauseConsoleShell's #4042 session gate holdsMetadataProviderfrom mounting untilgetSession()has already writtenTokenStorage(true for bearer and cookie-only sign-in — better-auth v1.6.28 returnssession.tokeneither way).Two boots outside those windows do write
@anon:ConditionalAuthWrapperwithenabled={false}previewModeboth writing
objectui:metadata:app:@none:@anon.Why this is not obviously a defect, and not obviously safe
The argument that these are harmless is that
ConditionalAuthWrapperselects those branches only when discovery reports an auth stub /handlerReady:false, or the deployment is a marketplace preview — i.e. precisely when the server is not filtering/meta/*per user, so the cached list is not a permission-filtered artifact and there is no cross-principal disclosure to make./meta/*for a stub-auth or marketplace-preview deployment — a question this repo cannot answer from the client side.apps/consolenever takes either branch, so nothing shipped in the console is implicated. The exposure, if any, is in stub/preview deployments.What #5746 established that bears on this
The parent card's most load-bearing finding is a correction: #5744's wholesale drop does not cover the seed read. React runs child effects before parent effects, so
MetadataProvider's seed read (a child effect, newly mounted in the commit whereisLoadingflips) precedesAuthProvider'spurgePreviousUserClientState(a parent effect). The principal-scoped key from #5198 is the sole protection on that boot — measured, not argued: withTokenStorageempty on an authenticated session, a second user booting in the same tab HIT the first user's key and renderedhr-secret.So a
@anonwrite is only benign for as long as the thing being cached is not permission-filtered. That is exactly the property this card needs someone to establish for the two synthetic-identity branches.An asset that exists and is not merged
#5746's harness renders the real console mount path — real
AuthProvider, realConnectedShellsession gate, realMetadataProvider, with only the two servers doubled, and nothing writingobjectui:metadata:*by hand (so it cannot agree with a key format the provider does not produce). It is the instrument that produced every reading above, including theS4/S5writes this card is about.It lives unmerged on
claude/issue-5746-anon-seed-scope-measurementatpackages/app-shell/src/console/__tests__/anonSeedScope-5746.enumeration.test.tsx.Worth considering — as a recommendation, not a decision — landing it as a regression pin alongside whatever this card rules, given that the main safety property now rests on a single mechanism. Two instrument defects it already caught are documented in its own comments, both of which would otherwise have produced a false "no writes anywhere" reading: jsdom hands out
sessionStorageas a Proxy (sothis === sessionStorageis never true inside aStorage.prototypemethod), andvi.restoreAllMocks()does not undo a reassigned property.Refs: #5746 (parent, closed
latent-not-live) · #5198 (the principal-scoped key) · #5744 (the purge that does not cover this) · #4042 (the session gate that shuts both named windows).Generated by Claude Code