You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The frame contract is in sync. src/lib/tunnel/tunnelProtocol.fixtures.json is content-identical
to base-studio-code develops src/features/tunnel/lib/tunnelProtocol.fixtures.json, and tunnelProtocol.fixtures.test.ts decodes every fixture into our typed models and deep-equals back,
so any frame-level drift fails in both directions.
The payloads are not. store_state is {domain, rev, json} where json is an opaque serialized
string, so every per-domain payload shape inside it is completely unguarded. Drift has accumulated
silently: all 351 tests pass while several pages render blank or stubbed.
Confirmed examples:
Desktop split glances ProjectLite.status into health + activity (#2541). We still read p.status (src/lib/pages/glancePage.ts:85), so every project node falls back to idle and the
fault/health colouring is dead.
Desktop audit rows are {ts: ISO-8601 string, pane, toolName, target}
(src/features/security/lib/auditLog.ts:22). We parse {at: number, action, detail, actor}
(src/lib/mirror/securityView.ts:64). Only pane→actor resolves; every row renders as —.
Target: develop, not main
base-studio-code main is at #2435 (2026-07-06). develop is at #3440 (current). Every contract
reference our code cites — #2497, #2498, #2511, #2530 — exists only on develop. Syncing against main would move us backwards. All investigation and all fixture copies must use ?ref=develop.
Approach
One issue per domain. Each is investigated against the real desktop surfaces on develop before any
code is written — resolving every referenced type to its actual definition rather than trusting the
payload interface alone, and checking TYPES not just field names (the security bug is a
string-vs-number, not a rename).
glance, security, alerts, org, themes, skills, automations and mcp have Layer A decoders + Layer B smoke tests. Only two domains remain in PENDING_DOMAINS, each citing its issue — moving a domain from PENDING_DOMAINS into DECODERS is the definition of done for its issue.
Known harness limit (found in #241): the fixture cannot catch pass-through bloat, because a minimal PROJECTION_INPUTS entry satisfies a type whose heavy fields are optional. Needs a sibling invariant desktop-side — fixture inputs must exercise optional fields the builder passes through.
The structural fix
Per-domain fixes are mechanical and will rot again the moment either side ships a rename. The durable
fix is a payload-level parity harness with the same "cannot land on one side without failing the
other" property the frame fixtures already have. Tracked as its own child.
Related: the mobile copy of the frame fixtures differs from the desktops by line endings only
(CRLF vs LF), which already technically violates the BYTE-IDENTICAL claim in the files own $comment. A .gitattributes pin folds into the harness work.
@
The problem
The frame contract is in sync.
src/lib/tunnel/tunnelProtocol.fixtures.jsonis content-identicalto base-studio-code
developssrc/features/tunnel/lib/tunnelProtocol.fixtures.json, andtunnelProtocol.fixtures.test.tsdecodes every fixture into our typed models and deep-equals back,so any frame-level drift fails in both directions.
The payloads are not.
store_stateis{domain, rev, json}wherejsonis an opaque serializedstring, so every per-domain payload shape inside it is completely unguarded. Drift has accumulated
silently: all 351 tests pass while several pages render blank or stubbed.
Confirmed examples:
ProjectLite.statusintohealth+activity(#2541). We still readp.status(src/lib/pages/glancePage.ts:85), so every project node falls back toidleand thefault/health colouring is dead.
{ts: ISO-8601 string, pane, toolName, target}(
src/features/security/lib/auditLog.ts:22). We parse{at: number, action, detail, actor}(
src/lib/mirror/securityView.ts:64). Onlypane→actorresolves; every row renders as—.Target:
develop, notmainbase-studio-code
mainis at #2435 (2026-07-06).developis at #3440 (current). Every contractreference our code cites — #2497, #2498, #2511, #2530 — exists only on
develop. Syncing againstmainwould move us backwards. All investigation and all fixture copies must use?ref=develop.Approach
One issue per domain. Each is investigated against the real desktop surfaces on
developbefore anycode is written — resolving every referenced type to its actual definition rather than trusting the
payload interface alone, and checking TYPES not just field names (the security bug is a
string-vs-number, not a rename).
Children
Linked as they are filed.
glance— glance domain: status split into health+activity (#2541) — every node renders idle; fleets/personaRoles unread #238 ✅ merged (status → health+activity; fleets/personaRoles adopted)security— security domain: consumer written against an invented shape — every section renders blank #237 ✅ merged (re-modelled on the real shape; decoder green)org— org domain: consume orgs (the whole team library) + persona detail + the missing iterates archetype #235 ✅ merged (feat(org,#235): consume the team library, persona detail, and the iterates archetype #257: team library + persona detail consumed,iteratesarchetype added, decoder green)blueprints— blueprints domain: soundKit/h/origin/updatedAt unread; only the ACTIVE team crosses the wire #236components— components domain: unpared kits (~10-25KB/push), global composes scoping bug, libraryRefs not projected #241 (C5 scoping ✅ merged; C1/C3/C4 desktop-side. store_state_chunk: reassemble fragmented store domains (mobile half of base-studio-code#3757) #255 ✅ merged, so the domain is mirrored again via chunk reassembly)themes— themes domain: base (light/dark surface) and tech (design group) already on the wire, never read #242 ✅ merged (fix(themes,#242): read base + tech — group the page, preview on the theme's own surface #258:base+techread in BOTH consumers, grouped page, decoder green)automations— automations domain: system hook floor never projected; two dead reads on withheld fields #239 (mobile half ✅ merged fix(automations,#239): delete reads on fields the desktop rules out; guard the domain #263: dead reads deleted, decoder green;systemHooksdesktop-side)mcp— mcp domain: built-in servers invisible; version read is unfixable and should be deleted #240 (mobile half ✅ merged fix(mcp,#240): delete the unfixable version read; guard the domain #264: unfixableversionread deleted, decoder green;withBuiltinsdesktop-side)skills/plan/alerts— verification pass done.alertsdrift confirmed and fixed (alerts: store domain is in sync, but three live FCM push types are unroutable (incl. the security quarantine push) #244 ✅ merged, decoder green);skills/planfiled as skills + plan domains: in sync; lesson timestamps dropped, StageStatus 'ahead' has no colour #245.gitattributesline-ending pin — Payload parity harness: guard store_state payloads the way the frame fixtures guard frames #246, Phase 0 + M4 ✅ merged (ci(tunnel,#246): run the tests in CI, pin line endings, share the decode helpers #249, test(tunnel,#246): payload parity harness — Layer A re-encode + Layer B smoke #251). M5 (contract-sync job) still open.store_state_chunktransport — store_state_chunk: reassemble fragmented store domains (mobile half of base-studio-code#3757) #255 ✅ merged (feat(tunnel): reassemble store_state_chunk fragments (base-studio-code#3757) #256: reassembler + 9 tests;componentsis ~63.5 KB, over the Noise cap)Harness status
glance,security,alerts,org,themes,skills,automationsandmcphave Layer A decoders + Layer B smoke tests. Only two domains remain inPENDING_DOMAINS, each citing its issue — moving a domain fromPENDING_DOMAINSintoDECODERSis the definition of done for its issue.Known harness limit (found in #241): the fixture cannot catch pass-through bloat, because a minimal
PROJECTION_INPUTSentry satisfies a type whose heavy fields are optional. Needs a sibling invariant desktop-side — fixture inputs must exercise optional fields the builder passes through.The structural fix
Per-domain fixes are mechanical and will rot again the moment either side ships a rename. The durable
fix is a payload-level parity harness with the same "cannot land on one side without failing the
other" property the frame fixtures already have. Tracked as its own child.
Related: the mobile copy of the frame fixtures differs from the desktops by line endings only
(CRLF vs LF), which already technically violates the BYTE-IDENTICAL claim in the files own
$comment. A.gitattributespin folds into the harness work.Related
components,blueprints/org, and the not-yet-existingalgorithms/soundsdomains are shared surface between these two umbrellas.@