Skip to content

Store-stamping drift: most page records lack , so reconcileSeed can never retire them and deleted seeds leave permanent orphans #4207

Description

@kevinthelago

Found while verifying #4183. The issue there assumed the 8 graph-Settings records would "clear themselves
on next hydrate" once their seeds were deleted. On this machine they will not — and the cause is not
specific to Settings.

The mechanism

reconcileSeed's first branch is:

if (!rec.builtin) { records.push(rec); continue; }   // user-authored — never touched

A record without the builtin flag is treated as hand-authored and is therefore never re-seeded,
re-hashed, or retired. That is correct behaviour for a record a user really did author. The problem is how
many records are missing the flag that should have it.

Scale

Of the 22 role: page records in the base-studio-code kit, at least 17 carry no builtin and no
seedHash
— including settingspage, automationspage, securitypage, skillspage, githubpage,
teamspage, relationshipspage, accessibilitypage and the whole Pages-tier set (tablepage,
dashboardpage, collectionpage, recordpage, pipelinepage, …).

(At least — a few records could not be read cleanly in the sweep, so the true number may be higher.)

settingspage's own history shows rev 3 on 2026-07-24 changing builtin, and the field has been absent
ever since — so the flag was actively lost at some point, not merely never set.

Why it matters

  1. Deleted seeds leave permanent orphans. Delete the dormant graph Settings path (the fuller revert #3758 left open) #4183 deleted the 8 Settings seed JSONs; the store copies
    remain and bsc ui doctor now reports SettingsWorkspace as a dangling root pulling in 17
    dependencies, plus 6 reimplemented-component findings for the graph GeneralPage/SecurityPage/…
    copies. As the Epic: load the app's UI from the graph at runtime #3604 migration deletes more seeds, this accrues.
  2. Seed updates silently do not reach the store. A builtin whose seed we edit should re-seed; an
    unstamped one keeps a stale copy forever. That is the same class as
    "Page Records Render From Store Not Seed" — the store copy is what mounts, so a seed fix that never
    lands is invisible until someone diffs them.
  3. It makes "is this record ours or the user's?" unanswerable, which every reconcile decision rests on.

What to work out

  • When and how the flag is lost. Candidates: a write path that drops unsupplied fields (see bsc ui set has the #4154 defect: a partial write silently drops every field it omits #4197
    bsc ui set is a whole-record replace, which would strip builtin/seedHash from any record it
    rewrites), a designer promotion, or a snapshot re-seed. bsc ui set has the #4154 defect: a partial write silently drops every field it omits #4197 is the strongest suspect and may be the
    whole cause — check that first, and if so this is largely a data-repair job after that lands.
  • A repair pass that re-stamps records which match a packaged seed by id, so the fleet of unstamped
    builtins rejoins the reconcile path. It must not stamp a record the user genuinely authored.
  • A guard so the flag cannot be dropped again by an ordinary write.
  • Only then, retire the genuinely-orphaned Settings records (a destructive act — see below).

Not to be done as a side effect

Removing the 8 orphaned Settings records is bsc ui remove, which for an unstamped record is
permanent (no re-seed to restore it). That wants an explicit decision, not a cleanup pass. Also
adjacent: accessibilitypage is store-only with no seed and no catalogue entry — likely a designer
harvest from #3804 — so a blanket "delete anything without a seed" rule would eat it.

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Next milestonebugSomething isn't working

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions