diff --git a/canon/architecture/adr-012-projection-source-and-preliminary-overlay.md b/canon/architecture/adr-012-projection-source-and-preliminary-overlay.md index fadc74f..00170a7 100644 --- a/canon/architecture/adr-012-projection-source-and-preliminary-overlay.md +++ b/canon/architecture/adr-012-projection-source-and-preliminary-overlay.md @@ -111,13 +111,51 @@ records under decision 3, but the baseline is derived, not received. This closes the gap where "central derives" was policy while "the laptop pushes" was practice. -**7. Formal git review stays optional.** Deriving from the default branch gives a +**7. The projection must be resettable from the forge, as a routine operation.** +There must be a supported way to discard the projection — for one repository or +for the whole fleet — and rebuild it from what Forgejo holds. + +This is the decision that makes the others checkable rather than merely stated. +A read model that cannot be rebuilt from its source is not a projection; it is a +database with a projection's reputation, and the difference only becomes visible +on the day someone needs to rebuild it. `ADR-010` decision 2 already asserts that +a cache "may be discarded and reconstructed from the repositories at any time" — +that claim has never been executed, and an untested rebuild path is an assumption, +not a capability. + +Three properties make it real rather than ceremonial: + +- **Routine, not emergency.** It should be run deliberately and often enough that + it is known to work, not discovered under pressure. A reset that has never been + performed is indistinguishable from one that does not work. +- **Scoped.** Per repository as well as fleet-wide. Rebuilding one repository's + records must not require discarding everything, or it will never be used. +- **Idempotent and verifiable.** A reset followed by a reset produces the same + projection, and the result can be compared against the forge to show it matches. + Derived identifiers (`ADR-007`) are what make this possible: the same commit + yields the same record identities every time. + +**Reset does not restore the preliminary overlay.** Overlay records exist +precisely because the forge does not hold them, so a rebuild from the forge +cannot reproduce them and must not pretend to. Reset therefore discards +preliminary state, and must say so plainly before it runs. + +**A reset must refuse when records exist only in the projection.** If the hub +holds records with no counterpart in the forge, rebuilding destroys them. That is +not hypothetical: as of 2026-08-25, 111 work records existed only in a retired +local database, and a rebuild at that moment would have erased them. The reset +path must detect that condition and stop, naming what would be lost, rather than +proceed and report success. + +**8. Formal git review stays optional.** Deriving from the default branch gives a shared baseline without requiring pull requests. Review can be adopted per repository where it earns its keep; this ADR neither mandates nor forbids it. ## Consequences -**Positive.** Truth becomes checkable by anyone, from anywhere, without a clone. +**Positive.** The hub becomes provably a projection: rebuildable on demand, and +therefore knowable to be one. Truth becomes checkable by anyone, from anywhere, +without a clone. Multiple contributors share one baseline instead of overwriting each other's views. Provenance becomes auditable — every record can name its commit. The "push then delete the working copy" case simply works. The distinction between @@ -140,7 +178,11 @@ direct forge fetch, not left dormant with an obsolete justification. **Unresolved.** This ADR does not settle the derive cadence, whether central clones or uses the Forgejo API, how preliminary records are surfaced in the dashboard and MCP, or what happens to a preliminary record whose commit never -arrives. Those belong to implementation. +arrives. Nor does it settle how hub-native records — progress events, decisions, +inbox messages, which `ADR-010` decision 4 classes as originating in the hub — +survive a reset. They are not forge-derived and must not be destroyed by a +rebuild of forge-derived state; the boundary needs drawing before reset is +built. Those belong to implementation. ## Relationship to prior decisions