Proposal: docs structure for the design phase¶
| Owner | Nacho (drafted by Claude, session 94119c0d) |
| Status | Ratified 2026-09-03 (Nacho; Benve's review, three flags, below). Landed: domain.md, scenarios/ (format; scenarios follow one PR each), this folder, writing-docs skill, CLAUDE.md read order, D28. Frozen |
| Created | 2026-09-03 |
| Updated | 2026-09-03 (ratified; review round 1 folded in) |
| Context | The writing-docs skill (.claude/skills/writing-docs/SKILL.md), architecture, PRD section 7 |
Summary¶
The documentation is the product until code exists, and it is starting to show the strain
of one folder holding three kinds of document. This proposal adds three document types
(domain, scenarios, proposals), moves the ratified reviews out of design/, and reorders
the read path. It does not rename any concept, split the decision log, or add folders that
would hold only headings. Migration is one session, almost all file moves, and the strict
docs build (make docs-build) catches every broken cross-reference.
The problem today¶
Three facts, all checkable on main:
- The vocabulary is buried. The Concepts and Invariants sections of architecture.md are the canonical definitions of Source, Event, Claim, Entity, and the nine invariants. They sit a third of the way into a 292-line document that the writing-docs skill says should have been split at 200. A reader asking "what exactly is an Event" has to know to look there.
- Proposals sit beside canonical docs. relationships.md
and v0-review.md are RFC-shaped: a status row, alternatives,
open questions, and a note saying where their content landed. Their content has landed
(architecture, interfaces, PRD, D16-D27). Yet they live in
design/next to the docs they fed, so nothing tells a reader which of the two is the current truth. This is the seed of the drift where a term ends up defined in an old review, a design doc, and a diagram with subtly different meanings. skeleton-proposal.md has the same shape and sits at the docs root. - No scenarios. Nothing in
docs/walks a concrete input through the system and states what must come out. The closest is a twelve-row table in relationships.md. The fixture corpus in PRD section 6 is scenarios in data form, but there is no prose spec for it to satisfy.
Proposed structure¶
docs/
├── index.md (the repo README, via symlink)
├── PRD.md what must exist and why
├── domain.md NEW: concepts and invariants, moved out of architecture.md
├── scenarios/ NEW: one file per scenario, prose specs the model must satisfy
│ ├── README.md index plus the format
│ └── <slug>.md
├── design/
│ ├── architecture.md pipeline, projections, reconciliation, modules, matching, stack
│ ├── interfaces.md the contracts
│ ├── data-model.md storage shape (arrives with feat/graph-data-model; proposed until ratified)
│ └── data-model/ its reference parts, per the 200-line split rule
├── decisions.md append-only, unchanged
├── proposals/ RENAMED ROLE: RFC-shaped docs, frozen once ratified
│ ├── docs-structure.md (this doc)
│ ├── skeleton-proposal.md
│ ├── relationships.md
│ └── v0-review.md
└── research/ unchanged
changelog/ stays at the repo root and enters the rendered site by symlink, as today.
The doc types, one question each¶
The writing-docs skill grows from six types to nine. New rows in bold.
| Doc | Question | Location |
|---|---|---|
| PRD | What must exist and why; requirements, milestones | docs/PRD.md |
| Domain | What the words mean and what must always hold | docs/domain.md |
| Scenarios | Given these inputs, what must the system conclude | docs/scenarios/ |
| Design docs | How: pipeline, storage shape, module decomposition, trade-offs | docs/design/ |
| Interface contracts | What modules promise each other | docs/design/interfaces.md |
| Decision log | What is settled, by whom, and why | docs/decisions.md |
| Proposals | What we are considering, and what we considered | docs/proposals/ |
| Research | What the evidence says before a decision | docs/research/ |
| Change log | What was executed, by whom, and how to verify it | changelog/ |
One rule ties them together: a definition lives in exactly one place. Domain owns concepts and invariants. Every other doc uses the term and links to domain.md; none redefines it. A glossary is deliberately absent because it would be a second place.
Domain¶
domain.md receives the Concepts and Invariants sections of architecture.md verbatim, then
gets a one-paragraph opener and a section listing the decisions each concept rests on. The
proposed tenth invariant from the 2026-09-03 discussion goes in on ratification: adding
new evidence never requires re-ingesting the original source. It is already implied by
invariant 1 and the changed-source reconciliation design, but nothing states it.
Scenarios¶
Each scenario is a short file with four parts: the concrete inputs (real-shaped data, not
placeholders), the composition and extraction the system must produce, the resolution
outcome, and the invariants and decisions it exercises. Variants of one setup stay in one
file. Scenarios are architecture tests in prose: when the model cannot explain what happens
in one, the design is not finished. Once the fixture corpus exists, each scenario becomes a
fixture plus a golden test under tests/contract/, and the scenario doc stays the spec the
test asserts.
The first eight, every one grounded in a decision already taken:
| Scenario | Exercises |
|---|---|
| Recording plus calendar event compose into one Event | Composition, B1 |
| Changed-source re-ingest reconciles claims and relation claims | I4, D11, D24 |
| Two John Smiths at Acme: alias is non-identifying, no merge | D4, invariant 3 |
| One email attached to two people: identifying-claim conflict, queued | D10, invariant 5 |
| Person leaves an organization: newer employment adds, nothing is superseded | D19, D21 |
| A wrong merge undone six months later by superseding links | Invariant 6, D1 |
| Same unknown person in two concurrent events | Invariant 7, D7 |
| Bootstrap import, organizations first | D26, B5 |
Proposals¶
A proposal is any RFC-shaped document: problem, motivation, examples, proposed model,
alternatives, consequences, open questions, and a Status row. Lifecycle:
- Proposed. Discussed in the doc, on the board, in review.
- Ratified (or rejected). The content moves into the canonical docs: decisions to
decisions.md, definitions todomain.md, mechanics todesign/, requirements to the PRD. The proposal's status row is updated to say where each piece landed, and the file is then frozen. - Canonical docs link to a proposal for history only, never for a definition.
Relationships and v0-review already follow steps 1 and 2 in substance; the move gives them
a home that says so. The data model doc is the other case: it is written as the future
canonical storage doc, not as a review, so it stays in design/ and its status row carries
"proposed" until ratified. The test is the shape of the document, not its status. Research stays separate: research can be wrong, a proposal can be
rejected, a decision explains history, canonical docs describe the current design.
Read order¶
For a fresh session, replacing the list in CLAUDE.md: README, PRD, domain, scenarios, architecture, interfaces. Then decisions as the reference for what is settled, and proposals and research as history and evidence when needed. The rendered site's nav mirrors this order.
Migration¶
One session, on one branch:
- Create
domain.mdfrom architecture.md's Concepts and Invariants; leave a two-line pointer at the top of architecture.md. Fix everyarchitecture.md#conceptsand#invariantsanchor (strict build reports them). git mvrelationships.md, v0-review.md, skeleton-proposal.md intoproposals/; fix links; add the "landed in" status wording where it is missing.- Write
scenarios/README.mdwith the format, then the eight scenarios above. This is the only step that is writing rather than moving; the rest of the migration does not wait on it. - Update the writing-docs skill (nine types, the one-place rule, the proposal lifecycle), CLAUDE.md's read order, and the site nav.
make docs-buildclean, one changelog entry, one decision entry (below).
Not doing, and why¶
- Splitting
decisions.md. Twenty-seven entries in one file is still greppable, which is the property that matters. Revisit past roughly fifty. - A
quality/folder. Observability, cost, backup, and security already exist as numbered PRD requirement rows with acceptance criteria. A folder would duplicate them. - Numbered folder prefixes (
01-vision/,02-domain/). They freeze an order that will change and add nothing the nav does not already do. - Renaming Event to Episode. Arguably better, since Event collides with queue vocabulary badly enough that the skeleton proposal had to legislate against it, and Graphiti's precedent is Episode. But it touches every doc and the board, so it is its own decision, not a side effect of a folder move. Raised as an open question below.
Review round 1 (Benve, 2026-09-03)¶
- Attribute schemas orphaned by the freeze. The four v1 relation attribute schemas (D19) were spelled out only in relationships.md. Resolved: moved into the registry section of interfaces.md before the freeze; no contract change, the schemas were already ratified.
- D27 cites v0-review section C for its table. History link, stays. Resolved: the proposals lifecycle now states that a deferred item worked later arrives as its own proposal, and v0-review's status row says so.
- Schedule Event vs Episode before milestone 1 closes. Deferred by Nacho, 2026-09-03: not a priority. Stays an open question below; the milestone-1 window Benve named is real and is recorded in D28.
Also from the review: scenario 4 (one email on two people) is uncovered design work in matching, not documentation. Written up as such in the scenarios PR, with the four other silences the scenarios surfaced collected at the end of scenario 8.
Agus's PR review (2026-09-03) surfaced five decisions (stage-contract version axes, prompt
storage, binary source bytes, D23 rejection scope, tenant-organization extraction); with
the deferred Event vs Episode rename they are GitHub issues labeled open-question
(#7, #9, #11, #13, #14, #15). An open-questions/ folder existed for a few hours and was
replaced by issues the same day: one place for a conversation, not two (Nacho,
2026-09-03).
Decision this proposal logs on ratification¶
D28: Nine doc types, one place per definition. The writing-docs layering gains domain,
scenarios, and proposals. Concepts and invariants are defined only in domain.md.
Proposals are frozen on ratification and are linked for history only.
Open questions¶
- Rename Event to Episode? Deferred (Nacho, 2026-09-03). Separate decision; cheapest before milestone 1 makes Event a pydantic class.
- Do scenarios cover ingestion adapters (per source type) or only the model? Proposed: model only until milestone 2 shows what the adapters actually see.
Alternatives considered¶
- Full arc42 or ten-folder layout. Rejected for now: with four people and about 1,800 lines of docs, most folders would hold one file or none, and the skill already forbids sections that exist because a template had a heading. arc42 itself recommends dropping unneeded sections (arc42).
- Keep everything in
design/with a status row. Cheaper, but a status row does not stop a reader from citing a frozen review as current truth. The folder boundary does. - A glossary file. Rejected: a second place for definitions, which is the drift this proposal exists to prevent.
References¶
- arc42 overview: separate goals, context, building blocks, cross-cutting concepts, decisions; drop what you do not need.
- C4 model: system context and container diagrams suffice for most teams; lower levels are expensive to maintain.
- Rust RFC template: motivation, guide-level and reference-level explanation, drawbacks, alternatives, unresolved questions.
- Documenting Architecture Decisions (Nygard): context, decision, consequences; accepted decisions preserved, never rewritten.