fdr seeded beside adr #
radial space create now seeds an eighth built-in artifact type: fdr — a feature design
record, project-scoped and append-only, the same register as adr one altitude down. An ADR
settles why the system is shaped as it is; an FDR settles what one feature does and why it is
designed that way. They are separate chains rather than one because they are superseded by different
things: a structural decision outlives the feature that provoked it, and a feature's design is
replaced by the next design of that feature, not by the next decision about the system.
Nothing about the fold, the lexicons, or the turn model changed — artifact types are per-space
registry data (design §4), so this is one more seeded record and the comment above builtinTypes
saying why it is there.
Branch and commit #
- Branch:
radial/impl-6c790516c837(new, frommain@5988cd7) - Commit:
ef76919f9e1cb912516c79903bca1f204569d953— "seed an fdr artifact type beside adr" - Pushed to
git@tangled.org:disnetdev.com/radial; no pull request opened from here (Radial opens it).
What changed #
The seed
packages/sidecar/src/commands.ts—fdrappended tobuiltinTypes(scope: project,durability: 'append-only'), with a brief that asks for the design-record register — problem, the behaviour committed to, the design, the alternatives weighed — and explicitly hands a decision about the shape of the system back toadr. The doc comment above the list is updated (five project-scoped types → six) and gains a paragraph on whyadrandfdrare two chains.packages/lexicons/fixtures/builtins.json— the matching shipped seed record (createdAt…00:00:08Z).space-create.test.mjsasserts the writer and this fixture say the same thing word for word, so the two cannot drift.
Operator defaults
packages/daemon/src/config.ts— the scaffoldedplannerprofile carriesfdrbeside the other system types, so a freshradiald config initcovers everything a fresh space seeds and no seeded type lands as a ⊕ entry with an empty assignee list.packages/daemon/src/cli.ts— theuncoveredadvisory's doc comment names the current seed list.
UI
packages/ui/src/lib/units.ts—typeLabelcapitalisesfdr→FDR. It was a singleadrcomparison; it is now a small set of spoken acronyms, still typography only (§3.3) and still passing anything unknown through unchanged.packages/ui/src/lib/components/Glyph.svelte— a glyph of its own, deliberately unlike theadrbook: the two sit side by side in the System section, and rows that draw alike have to be read to be told apart. Unknown types keep the generic fallback.
Docs — docs/design.md §8 (both the prose list of system artifacts and the "decision records"
durability bullet), docs/radial-json.md (seeds seven → eight, the sample config, the init
output), docs/running-an-agent.md (same three places), packages/sidecar/README.md.
Checks #
Run from the repo root after pnpm install (the offline install failed — typescript-5.9.3.tgz was
missing from the store — so a plain pnpm install was used):
pnpm build— cleanpnpm lint— clean across all 9 projects, includinggenerate.mjs --check(no lexicon changed; the generated file is untouched and current) andcheck-no-nulpnpm test— clean across all 9 packages, including@radial/ui'snode --testand both vitest projects (862 tests)
Three test expectations were counts of the seed list and were updated with it:
core/test/validation.test.mjs, sidecar/test/space-create.test.mjs,
daemon/test/config.test.mjs, plus ui/src/lib/write.test.ts (a browser-side space create seeds
8 types and the registry rows now include fdr). Added typeLabel coverage in
ui/src/lib/units.test.ts — it had none, and the capitalisation rule now has more than one member.
Risks and things left out #
- Existing spaces do not gain the type. Seeds are written at
space create, so a space created before this change has nofdruntil an admin adds the registry record (the registry form in the UI, or a hand-writtenartifactType). That is how registry data works here; there is no migration path and this change does not invent one. - An agent has to publish it. A space that seeds
fdrwith no profile listing it gets a request that sits open. New operators are covered by the scaffold above; an existingradial.jsonneeds the name added andradiald init planner --update— which is exactly whatradiald run'suncoveredadvisory will say at startup. - The brief is the one judgement call with no test behind it: it leans on "keep it to this feature" to hold the ADR/FDR line, and only real turns will show whether that is enough separation.