Found while cutting the first leaf app (Lelañea) from daybreak-v0.2.0.
What bit
.context/framework/building-on-daybreak.md → "Two tests you are expected to adjust" gives this rule:
tests/unit/lib/app/defaults.test.ts — asserts every lib/app/* seam ships empty. When you fill one, pin the new value in its SEAM_DEFAULTS row rather than removing the row.
The rule is keyed on "when you fill one". But filling a leaf-* seam also breaks the row for the bridge above it — a seam the leaf never touched. The bridge reads the leaf seam, so the leaf changes its resolved value without editing its file.
Two instances, both confirmed by running them:
1. lib/app/brand.ts — hit for real on the first leaf.
FAIL tests/unit/lib/app/defaults.test.ts > 'lib/app/brand.ts' registers nothing by default
AssertionError: expected 'Lelañea' to be 'Daybreak'
lib/app/brand.ts:33 resolves leafBrandName ?? 'Daybreak', so a leaf that sets its name correctly makes this row report the leaf's name. The row (defaults.test.ts:418) pins the literal 'Daybreak'.
The part worth noting: the row's own comment two lines above anticipates the override and pins the literal anyway —
// PINNED (Daybreak fills this bridge): the framework's own identity, which a
// leaf fork overrides from the reserved-empty `leaf-brand.ts` (row below).
expect(seam.appBrandName).toBe('Daybreak');
2. lib/app/admin-nav.ts — verified with a throwaway probe (one registerNavSection in leaf-admin-nav.ts, then reverted):
FAIL 'lib/app/admin-nav.ts' registers nothing by default
AssertionError: expected [ { title: 'Framework' }, …(1) ] to have a length of 1 but got 2
The leaf-admin-nav.ts row failed in the same run, which is correct and covered by the guide. The admin-nav.ts row is the one the rule does not reach.
3. lib/app/data-export.ts — probable, NOT verified. Its row asserts expect(accounted).toEqual(frameworkModels) where frameworkModels comes from framework-*.prisma only. A leaf declaring its app_* models through initLeafSubjectSources() looks like it would add entries frameworkModels cannot contain. Lelañea has no app.prisma models yet, so this is a read of the code rather than an observation — flagging it as the likely third rather than claiming it.
lib/app/bootstrap.ts is safe: await expect(initApp()).resolves.toBeUndefined() stays true however much a leaf registers.
Why it matters more than the fix cost
Every one of these fails at exactly the moment a leaf does the right thing — fills its reserved seam, as the guide instructs. The failure names a Daybreak-owned file the leaf never edited, so the natural reading is "I broke the framework" and the natural repair is to go and edit brand.ts or admin-nav.ts — the bridges the same guide says never to touch, and the exact edit that collides on the next sync. In the data-export.ts case, resolving that the obvious way silently drops the framework's tables from every GDPR subject-access export, which is the failure mode building-on-daybreak.md already warns about in bold.
So the cost is not the two-minute fix; it is that the guidance points a leaf toward the one repair the framework most needs it not to make.
Suggested shape
Either would do; the second is cheaper and probably better:
- Make the bridge rows resolve rather than pin — assert against what the tier below actually supplies, so the row keeps its meaning at both tiers.
- Extend the rule in
building-on-daybreak.md to say that filling a leaf-* seam also moves its bridge's row, and list the pairs (leaf-brand.ts → brand.ts, leaf-admin-nav.ts → admin-nav.ts, leaf-data-export.ts → data-export.ts), with the explicit instruction to pin the bridge row too, not edit the bridge.
Either way the guide's "Two tests you are expected to adjust" undercounts — within defaults.test.ts a leaf adjusts a row per seam it fills plus a row per bridge above those.
What Lelañea did
Pinned all three affected rows to the resolved values rather than deleting them, so the seams still empty keep their protection, with the reasoning recorded in place so nobody restores them on a sync.
Filed from the first leaf cut on daybreak-v0.2.0 (Sunrise 0.11.2).
🤖 Generated with Claude Code
https://claude.ai/code/session_01CneMwAfmx471CoA4sepW8q
Found while cutting the first leaf app (Lelañea) from
daybreak-v0.2.0.What bit
.context/framework/building-on-daybreak.md→ "Two tests you are expected to adjust" gives this rule:The rule is keyed on "when you fill one". But filling a
leaf-*seam also breaks the row for the bridge above it — a seam the leaf never touched. The bridge reads the leaf seam, so the leaf changes its resolved value without editing its file.Two instances, both confirmed by running them:
1.
lib/app/brand.ts— hit for real on the first leaf.lib/app/brand.ts:33resolvesleafBrandName ?? 'Daybreak', so a leaf that sets its name correctly makes this row report the leaf's name. The row (defaults.test.ts:418) pins the literal'Daybreak'.The part worth noting: the row's own comment two lines above anticipates the override and pins the literal anyway —
2.
lib/app/admin-nav.ts— verified with a throwaway probe (oneregisterNavSectioninleaf-admin-nav.ts, then reverted):The
leaf-admin-nav.tsrow failed in the same run, which is correct and covered by the guide. Theadmin-nav.tsrow is the one the rule does not reach.3.
lib/app/data-export.ts— probable, NOT verified. Its row assertsexpect(accounted).toEqual(frameworkModels)whereframeworkModelscomes fromframework-*.prismaonly. A leaf declaring itsapp_*models throughinitLeafSubjectSources()looks like it would add entriesframeworkModelscannot contain. Lelañea has noapp.prismamodels yet, so this is a read of the code rather than an observation — flagging it as the likely third rather than claiming it.lib/app/bootstrap.tsis safe:await expect(initApp()).resolves.toBeUndefined()stays true however much a leaf registers.Why it matters more than the fix cost
Every one of these fails at exactly the moment a leaf does the right thing — fills its reserved seam, as the guide instructs. The failure names a Daybreak-owned file the leaf never edited, so the natural reading is "I broke the framework" and the natural repair is to go and edit
brand.tsoradmin-nav.ts— the bridges the same guide says never to touch, and the exact edit that collides on the next sync. In thedata-export.tscase, resolving that the obvious way silently drops the framework's tables from every GDPR subject-access export, which is the failure modebuilding-on-daybreak.mdalready warns about in bold.So the cost is not the two-minute fix; it is that the guidance points a leaf toward the one repair the framework most needs it not to make.
Suggested shape
Either would do; the second is cheaper and probably better:
building-on-daybreak.mdto say that filling aleaf-*seam also moves its bridge's row, and list the pairs (leaf-brand.ts→brand.ts,leaf-admin-nav.ts→admin-nav.ts,leaf-data-export.ts→data-export.ts), with the explicit instruction to pin the bridge row too, not edit the bridge.Either way the guide's "Two tests you are expected to adjust" undercounts — within
defaults.test.tsa leaf adjusts a row per seam it fills plus a row per bridge above those.What Lelañea did
Pinned all three affected rows to the resolved values rather than deleting them, so the seams still empty keep their protection, with the reasoning recorded in place so nobody restores them on a sync.
Filed from the first leaf cut on
daybreak-v0.2.0(Sunrise 0.11.2).🤖 Generated with Claude Code
https://claude.ai/code/session_01CneMwAfmx471CoA4sepW8q