Summary
The browser host establishes a TrUAPI bridge with the t3ams product, answers its account_get, and then never responds to its LOCAL_STORAGE_READ requests. The product retries four times and gives up. host-playground performs the same host-storage operation successfully in the same browser, host build and session, so the handler itself is reachable and working.
Reproduced on live paseo.fyi (2026-09-21) against both a published product and a local one.
Evidence
t3ams — read never answered
https://t3ams-spa-dev.paseo.fyi/ (published, resolves to bafybeihb6wcwndrcxk4yfahsmwveuylu3arzclrphr6mctwml5m5pevj6m). Debug → TrUAPI:
resolve.completed Resolved t3ams-spa-dev.paseo → bafybeihb6wcw…
bridge.setup_ready TrUAPI bridge ready (productId=t3ams-spa-dev)
bridge.iframe_load Product iframe finished loading (subdomain)
bridge.first_inbound First message from product received
◀ account_get_account_request wireId=513 traitId=2 methodId=1
▶ account_get_account_response +34ms ← answered
◀ p:1 wire_12 redacted=true byteLength=22 ← LOCAL_STORAGE_READ
◀ p:2 wire_12 redacted=true byteLength=22
◀ p:3 wire_12 redacted=true byteLength=22
◀ p:4 wire_12 redacted=true byteLength=22 ← no ▶ for any of them
wireId 12 is LOCAL_STORAGE_READ.request; the redacted: true shape matches REDACTED_PREFIXES containing local_storage in packages/ui/src/debug-wire-describe.ts:206. The ~10s spacing and exactly four attempts are the product's own read timeout and retry budget, so the product is behaving correctly and simply never hears back.
No dotli:truapi:product-storage:v1:21:t3ams-spa-dev.paseo:* key is ever created.
Identical behaviour with a locally served build via the debug route https://paseo.fyi/localhost:5180/ (productId=localhost:5180), so it is not specific to the published artifact or to DotNS resolution.
host-playground — same operation succeeds
https://host-playground.paseo.fyi/ → Storage → Bytes Write & Read (hostStorage().writeBytes/readBytes) completes, and the host origin gains:
dotli:truapi:product-storage:v1:21:host-playground.paseo:host_playground_bytes
dotli:truapi:product-storage:v1:21:host-playground.paseo:probe-key
Not a version skew
Both products ship @parity/product-sdk 0.21.0 and @parity/truapi 0.7.0. Diffing the 0.7 wire table against the vendored 0.14 one (vendor/truapi, 160 vs 178 entries) shows only four renamed ids — CHAT_CUSTOM_MESSAGE_RENDER_SUBSCRIBE.{start,stop,interrupt,receive} → CHAT_CUSTOM_MESSAGE_RENDER.*. Id 12 is LOCAL_STORAGE_READ.request in both tables, and the account_get exchange on the same bridge round-trips fine.
What appears to differ
Not established — needs host-side instrumentation. Candidates, in rough order of suspicion:
- Timing/ordering. t3ams issues its read within ~1s of
bridge.first_inbound, as part of boot, immediately after account_get. host-playground's read is user-initiated, tens of seconds after the runtime settled.
- Cold key. t3ams reads a key that has never been written (
t3ams:session/identity). host-playground writes then reads. createLocalStorageRead returns Promise.resolve(undefined) on a miss (packages/ui/src/host-callbacks/LocalStorage.ts:5-18) — worth checking how undefined is serialized back through the runtime. Seeding all four keys with empty values in the host origin did not unblock it, so this is not the whole story.
- Concurrency. t3ams issues its reads back-to-back at boot.
Reproduction
# published product
open https://t3ams-spa-dev.paseo.fyi/
# → Debug → TrUAPI → four ◀ wire_12 frames, no ▶
# local product (minimal, same result)
git clone git@github.com:paritytech/t3ams-spa.git && cd t3ams-spa
VITE_NETWORK=paseo-next-v2 VITE_DOTNS_PRODUCT_DOMAIN=t3ams-spa.paseo npm run build:e2e
npx vite preview --mode host --port 5180 --strictPort
# Chromium needs --allow-running-insecure-content for the https→http iframe
open https://paseo.fyi/localhost:5180/
Control: https://host-playground.paseo.fyi/ → Storage → Bytes Write & Read.
Impact
t3ams cannot be used on paseo.fyi at all. Storage is its boot gate, so the product never reaches a signed-in state. Blocking for the upcoming internal test on the browser host.
t3ams is separately changing to stop using host KV where IndexedDB is available (paritytech/t3ams-spa#244), which will route around this. The host defect is still worth fixing: any product that reads host storage early in boot will hit it.
Summary
The browser host establishes a TrUAPI bridge with the t3ams product, answers its
account_get, and then never responds to itsLOCAL_STORAGE_READrequests. The product retries four times and gives up.host-playgroundperforms the same host-storage operation successfully in the same browser, host build and session, so the handler itself is reachable and working.Reproduced on live
paseo.fyi(2026-09-21) against both a published product and a local one.Evidence
t3ams — read never answered
https://t3ams-spa-dev.paseo.fyi/(published, resolves tobafybeihb6wcwndrcxk4yfahsmwveuylu3arzclrphr6mctwml5m5pevj6m). Debug → TrUAPI:wireId 12isLOCAL_STORAGE_READ.request; theredacted: trueshape matchesREDACTED_PREFIXEScontaininglocal_storageinpackages/ui/src/debug-wire-describe.ts:206. The ~10s spacing and exactly four attempts are the product's own read timeout and retry budget, so the product is behaving correctly and simply never hears back.No
dotli:truapi:product-storage:v1:21:t3ams-spa-dev.paseo:*key is ever created.Identical behaviour with a locally served build via the debug route
https://paseo.fyi/localhost:5180/(productId=localhost:5180), so it is not specific to the published artifact or to DotNS resolution.host-playground — same operation succeeds
https://host-playground.paseo.fyi/→ Storage → Bytes Write & Read (hostStorage().writeBytes/readBytes) completes, and the host origin gains:Not a version skew
Both products ship
@parity/product-sdk0.21.0 and@parity/truapi0.7.0. Diffing the 0.7 wire table against the vendored 0.14 one (vendor/truapi, 160 vs 178 entries) shows only four renamed ids —CHAT_CUSTOM_MESSAGE_RENDER_SUBSCRIBE.{start,stop,interrupt,receive}→CHAT_CUSTOM_MESSAGE_RENDER.*. Id 12 isLOCAL_STORAGE_READ.requestin both tables, and theaccount_getexchange on the same bridge round-trips fine.What appears to differ
Not established — needs host-side instrumentation. Candidates, in rough order of suspicion:
bridge.first_inbound, as part of boot, immediately afteraccount_get. host-playground's read is user-initiated, tens of seconds after the runtime settled.t3ams:session/identity). host-playground writes then reads.createLocalStorageReadreturnsPromise.resolve(undefined)on a miss (packages/ui/src/host-callbacks/LocalStorage.ts:5-18) — worth checking howundefinedis serialized back through the runtime. Seeding all four keys with empty values in the host origin did not unblock it, so this is not the whole story.Reproduction
Control:
https://host-playground.paseo.fyi/→ Storage → Bytes Write & Read.Impact
t3ams cannot be used on
paseo.fyiat all. Storage is its boot gate, so the product never reaches a signed-in state. Blocking for the upcoming internal test on the browser host.t3ams is separately changing to stop using host KV where IndexedDB is available (paritytech/t3ams-spa#244), which will route around this. The host defect is still worth fixing: any product that reads host storage early in boot will hit it.