Goldie Blocks

One Domain Rulebook, Concept-Sliced Convex, Standard FSD

Why the codebase uses one runtime-free canonical domain package shared by frontend and Convex, concept-sliced Convex adapters, and standard Feature-Sliced Design for the frontend — and which structural rules each brand promise obliges

Decision

Goldie Blocks uses one runtime-free canonical domain model (packages/domain) shared by the frontend and Convex, concept-sliced Convex adapters for persistence and authority, and standard Feature-Sliced Design (FSD) for the frontend, with Atomic Design retained only for domain-neutral Shared UI.

In plain terms: one official rulebook states what Documents, Modules, Blocks and Fields are; the Convex vault stores and guards them using that rulebook; and the frontend workbench follows a documented industry filing system rather than a homemade one.

Settled 2026-08-09 by the owner-led architecture grill recorded in the archived plan 2026-08-09-codebase-architecture, after independent reviews and a merged tracer (R3) proved the package, the boundaries, and every enforcement gate — each observed failing before being trusted green.

The brand pillars are the rationale

Every structural rule in this record exists to make one of three product promises dependable. An abstraction that serves none of them and removes no demonstrated safety risk is ceremony, not architecture.

Brand pillarProduct mechanismsArchitectural obligation
A Block for every story — and a story for every BlockLibrary discovery, classification, signals, readable/About facesOne discovery contract and one two-face domain projection
Many views, but only one truth@ mentions, stable identity, surfaces, agents and outputsOne canonical model; every other representation is a projection or adapter
Build on your best workWorking → library, versions and lineageOne reuse lifecycle with immutable pinned versions and no silent source mutation

Test any proposed structure with four questions: does it make the right Folio easier to find; understandable from both faces; one truth across every reference and view; safer to save, improve and reuse?

The three responsibility areas

packages/domain/       canonical types, rules and projections
        ↑
        ├──────── convex/     storage, authority and transactions
        └──────── src/        FSD frontend application

The domain owns runtime-free, deterministic business meaning: canonical types, parsing and validation, Proposed Change lifecycle, naming and mention projections, transitions, numbering, and agent/interview contracts. Purity is the entry requirement, not the definition of membership — deployment configuration is not domain meaning and lives in convex/convex.config.ts (or convex-dev/ for dev-only fixtures and switches).

Convex owns the assembled schema, registered functions, auth and permission prologues, AuthorityContext construction and enforcement, transactions, storage, and runtime-only configuration. It is organised by business concept (convex/folio/, convex/goldie/, convex/library/), never by global technical buckets. The concepts are the ones the schema has — this record originally illustrated the rule with convex/blocks/, convex/documents/ and convex/modules/, three drawers the Folio unification abolishes by making a document, a module and a block three kinds of one record. The rule is unchanged; only the example was tier-shaped. The current concept list lives in Convex rules (owner ruling, 2026-09-01).

Every content-mutating capability receives an explicit AuthorityContext; a content write without one is not representable.

The frontend follows standard FSD layers — shared, entities, features, widgets, pages, app — with their documented meanings unchanged. "Use FSD sparingly" means do not create empty or shallow slices; it never means altering layer meanings. Atomic Design survives only inside shared/ui (atoms and molecules); the global organisms/ and templates/ levels are retired because their size-based admission test made them junk drawers.

Humans and agents are peer operators: different public wrappers where trust or approval differs, but one canonical operation underneath. Agent scope narrows structural reach; it never grants a capability the principal lacks.

Frontend operation placement (owner ruling, 2026-08-27). A Feature and a dispatcher answer different questions and are not competing architectures. A Feature is the reusable frontend home for a user intention used by two or more Pages; its implementation binds the canonical domain operation, policy, persistence, optimistic state and failure handling. Rename, duplicate and delete Document already meet that threshold because Document Home and Document Work both offer them, and a future Project surface must call the same implementation rather than depend on the drafting editor. An intention used only within the drafting editor stays behind a local dispatcher until another consumer exists; speculative reuse does not earn a Feature.

The reusable vocabulary is Folio operation and Folio arrangement, not "Stack operation". Stack is neutral visual furniture and never owns a business write; a Substack names only a Stack in a nested relationship. A menu, drag gesture, keyboard command, Goldie tool or non-Stack surface adapts its input onto the same operation. Operations on a Folio change that Folio; insert, move, reorder and remove change its parent's Folio arrangement, while duplication combines a source-owned copy with placement in that arrangement. Fields remain ordered parts of a data Block rather than Folios, so Field authoring is reused through the Block operation boundary instead of inventing a Field Stack. The domain operation catalogue remains the authority for vocabulary, availability, capability and destructive posture; frontend placement must not restage those rules. The glossary's Folio-operation and Folio-arrangement entries remain the definitions rather than this placement ruling becoming a second operation catalogue.

Shared plain-text editing

useEditableValue owns draft, cancellation, blur commit and the optimistic hold for plain-text editors. Only the latest write may settle the hold; an older refusal cannot replace a newer draft. Callers retain validation, normalisation and the policy for a refused write. A callback returning a promise reports settlement; a void callback acknowledges through updated value props. Presentation never enters the hook.

EditableText is the shared atom for single-line inputs and growing multiline textareas. Length and appearance are independent: multiline chooses the native element; variant chooses bare, line or pill. Typography comes from the surrounding surface. EditableName adds derived-name and click-to-edit behaviour with header, plain and pill treatments. Field keys and values keep their domain adapters; About notes keep their resting presentation. Existing activation is preserved. Rich block content remains a separate editor so its move to Tiptap does not reshape plain-text controls. Each family has one variants gallery; behavioural stories remain separate where they prove distinct interactions (GB-296).

Domain concept chapters

The accepted chapters, each earned by surveyed real code (created only when its code moves in — no empty symmetry):

agent/ · block/ · document/ · field/ · flow/ · folio/ · interview/ · mention/ · naming/ · numbering/ · proposed-change/

Two rulings shape the list. interview/ stays separate from agent/: the interview is the questionnaire — which Fields, what order, what counts as done — and exists whether a person on the Form surface or Goldie conducts it; agent/ holds only Goldie's turn machinery. mention/ replaces reference/ (owner ruling 2026-08-09: "reference" is too general): a mention is authored in text, binds to stable identity, and survives renames — one product word from rulebook to screen, matching the at-mention frontend capability. packages/domain/src/reference/ was renamed to mention/ 2026-08-11, closing the gap between this ruling and the code. document/ and flow/ are reserved names, not yet created — no code has moved into them.

Rules that prevent drift

  1. One concept, one canonical declaration — adapters translate, never mirror.
  2. One folder owns one responsibility; no concept has two plausible homes.
  3. Meaning decides ownership, not technical purity or visual size.
  4. Shared UI is domain-neutral — product nouns are banned from its public identifiers and CVA keys.
  5. FSD imports travel downward through slice public APIs; sidesteps are violations. Cross-Entity presentation uses FSD's documented @x convention (Steiger must be observed enforcing it before the first cross-Entity module lands).
  6. Frontend runtime code uses the generated Convex API, never private backend implementation modules.
  7. Authority is explicit — AuthorityContext is a required value, not a convention.
  8. No empty symmetry; no accidental renames; no long-lived shims; no big-bang migration.
  9. A test not observed failing is not evidence.

Enforcement: Steiger (FSD layers, slice isolation, public APIs), Biome (domain/Convex/legacy import bans, Shared UI product-noun ban), TypeScript across every consumer, Vitest domain tests, the generated Convex API as the runtime boundary, and a function-path test for string-based Convex references. Every gate was deliberately broken and observed red before being trusted (R3, 2026-08-09). The one-declaration rule remains partly a review rule — structurally identical types compile.

Where the three areas stand

In plain terms: this section says what is done and what is not. It does not list the folders — the tree does that, and a list in prose drifts the moment someone adds a slice.

packages/domain is populated. Every chapter is under a settled name, and ls packages/domain/src is the list. field/ owns the canonical stored Field declaration, the canvas snapshot contract, and the type-to-initial-name projection; Convex and the frontend consume those declarations rather than mirroring them.

The frontend's structural move to FSD is complete. Every layer is populated, the legacy src/components tree went on 2026-08-11, and src/routes, src/hooks and src/styles do not exist — routes are thin shells over their Pages. src/lib was removed on 2026-08-14, emptying Steiger's ignore list so every file under src/ is linted. There are no Atomic-Design leftovers: the one exception this record permitted, the module card, was discharged when it became entities/module.

src/features holds a slice only where cross-Page reuse earns it — the two-Page bar this record's placement ruling sets. duplicate-folio (2026-09-07, GB-151) met it because Document Home and Document Work both duplicated a document, each with its own catch block and alert and, on Work, no pending guard. review-folio-proposal (2026-09-15, GB-201) is the one review controller for every kind's card: it binds Accept and Reject and holds the pending and refusal state, the Page subscribes to the open proposal, and the canvas places the drawn halves on the anchor card. Rename and Delete stay bound at Document Work until a second surface offers them.

The one open gap is convex/. Concept slicing has begun — folio/, goldie/ and library/ — and the root still carries the modules nothing has earned a home for yet. Slicing continues as work earns each move, carrying its generated and string paths; the move discipline is in Convex rules. Opportunistic moves alone will not empty a flat root, so this closes when someone decides it is worth its own work, not on a schedule.

Both migration plans are archived and this record is authoritative.

Settled vocabulary

  • Folio — a Document, Module or Block: stable identity, immutable authored versions, reuse posture, lineage. Field is deliberately excluded — a Field freezes with its Data Block version.
  • Mention — authored in text with @; binds to stable identity; survives renames. Retires "@ reference" in prose.
  • Proposed Change — the canonical propose → tracked differences → revise → accept/reject → apply lifecycle. One baseline, one diff, one acceptance state, projected on both faces. "Tracked changes" is its visual projection, not a second stored change.
  • Canvas — the editable rendering surface where a Document is composed.
  • Library — reserved for the product's reusable precedent bank; never a code-file name for anything else.
  • Goldie — the agent persona and its agent-specific surfaces; not a prefix for general UI. Shared UI names stay neutral (CardFrame, WorkBar, ViewTabs, PromptComposer).

Product documentation does not mirror code folders: docs describe product truth by concept; the repository map lives in CLAUDE.md.

Open and deferred

About-source lexical fidelity is explicitly deferred (owner, 2026-08-09): whether comments, whitespace and untouched spans of human-authored About source must survive edits byte-for-byte, or semantic round-trip suffices. Standing constraint: no parser or source-editor library may be chosen for the About face until this is ruled — the two behaviours need different machinery. (Tiptap's decided role is the Content facet's editing adapter only; it must not be quietly reused for the About face.)

Proof obligations carried forward: Steiger @x enforcement (before the first cross-Entity module), and a Document–Module–Block search tracer proving the discovery folder and query shape before either enters the target tree.

Revisit when

  • A Field earns independent lifecycle (own audit trail, routine concurrent editing, cross-library Field queries, or independent reuse) — the Folio boundary then re-opens.
  • Durable cross-device queues, concurrent Proposed Changes, or shared review arrive — the evidence for independent Proposed Change persistence.
  • The deferred fidelity ruling lands — it constrains the About-face editor choice.

On this page