docs(canon): accept ADR-012 and retract the parts it supersedes
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s

ADR-012 accepted 2026-08-25.

ADR-010 — partially superseded, notes added inline:
  decision 1: "a reading of the repositories" never said which copy, and the
    answer was neither the forge nor a working copy but whichever checkout last
    synced. The hub holds no repository files and never reads one.
  decision 5: "central derives, does not accept pushes" was policy while the
    workstation pushed everything.
  decision 6: "preliminary" was named but never built.

ADR-003 — partially superseded:
  decision 2: fingerprints composed from filesystem mtime are invalidated in
    part. mtime is a property of one workstation, differs across clones, and
    says nothing about content. Evidence: git_fingerprint for the-custodian
    held the initial commit while last_state_synced_at was minutes old.
  decision 5: the rebuild principle was correct but never exercised, and its
    "without data loss" claim holds only while nothing exists solely in the hub
    — which was false for 111 records on 2026-08-25.

ADR-001, ADR-005, ADR-007 and ADR-011 reviewed and unaffected; ADR-007 is
reinforced, since derived identifiers let an overlay and a forge-derived
projection compute the same identity.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
codex 2026-08-25 21:44:14 +02:00
parent 8c2825f4c3
commit c0cead2169
3 changed files with 59 additions and 5 deletions

View file

@ -16,7 +16,10 @@ tags: ["architecture", "state-hub", "caching", "read-model", "materialized-view"
## Status ## Status
Accepted. Accepted, and **partially superseded by `ADR-012`** (accepted 2026-08-25).
Decision 2's fingerprint composition is invalidated in part; decision 5's rebuild
principle is given a concrete source and a required operation. See the notes on
each.
## Context ## Context
@ -84,6 +87,19 @@ the stored value is updated.
computation (repo record, related domain, goals, snapshots). computation (repo record, related domain, goals, snapshots).
- Include the `mtime` (filesystem modification time) of every file that feeds - Include the `mtime` (filesystem modification time) of every file that feeds
the computation (`SCOPE.md`, `CLAUDE.md`, lockfiles, `tpsc.yaml`, etc.). the computation (`SCOPE.md`, `CLAUDE.md`, lockfiles, `tpsc.yaml`, etc.).
> **Invalidated in part 2026-08-25 by `ADR-012` decisions 1 and 2.** Filesystem
> `mtime` is not a property of the source. It differs between machines, changes
> on a fresh clone, and says nothing about content — so a fingerprint built from
> it describes one workstation's filesystem rather than the repository. Under
> `ADR-012` the projection derives from the forge, and the commit that produced
> a record is both the correct input and the auditable one.
>
> This was not merely theoretical drift. `git_fingerprint` for `the-custodian`
> held the repository's *initial* commit while `last_state_synced_at` was minutes
> old: the field meant to identify what a projection reflects was wrong by the
> entire history of the repository, and nothing noticed. Replace `mtime` inputs
> with the source commit.
- Join all components with `|` as a pipe-separated string — no hashing needed - Join all components with `|` as a pipe-separated string — no hashing needed
since the string is compared by equality, not transmitted to clients. since the string is compared by equality, not transmitted to clients.
- If a file is absent, encode `filename:absent` rather than omitting it, so - If a file is absent, encode `filename:absent` rather than omitting it, so
@ -110,6 +126,19 @@ table's `max(snapshot_at)` directly rather than relying on the repo record.
Per ADR-001, the state-hub must be rebuildable from scratch by re-ingesting Per ADR-001, the state-hub must be rebuildable from scratch by re-ingesting
all canonical sources. Materialised tables are **caches**, not records of all canonical sources. Materialised tables are **caches**, not records of
authority. They may be wiped and repopulated at any time without data loss. authority. They may be wiped and repopulated at any time without data loss.
> **Given concrete form 2026-08-25 by `ADR-012` decision 7.** This principle was
> correct and, until now, never exercised — an untested rebuild path is an
> assumption rather than a capability, and this one was believed for long enough
> that a divergence survived seven weeks behind it. `ADR-012` requires the
> reconstruction to exist as a routine operation, scoped per repository, sourced
> from the forge, and verifiable against it.
>
> The claim "without data loss" also needs its precondition stated: it holds only
> while the rule immediately below does. On 2026-08-25, 111 work records existed
> only in the hub, so a rebuild at that moment would have destroyed them.
> `ADR-012` therefore requires reset to refuse, per repository, when records have
> no counterpart in the forge.
This means: This means:
- No materialised table may be the only copy of any information. - No materialised table may be the only copy of any information.
- Schema migrations that wipe a materialised table are safe and expected. - Schema migrations that wipe a materialised table are safe and expected.

View file

@ -16,7 +16,9 @@ tags: ["architecture", "state-hub", "repo-manager", "hub-core", "authority", "ca
## Status ## Status
Proposed. Proposed, and **partially superseded by `ADR-012`** (accepted 2026-08-25).
Decisions 1, 5 and 6 are sharpened or given a mechanism there; see the notes on
each below. Everything else in this ADR remains in force.
## Context ## Context
@ -69,6 +71,12 @@ Hub — running on railiance — is authoritative. It is authoritative *as a rea
of the repositories*, not as a second place data lives. Repository files remain of the repositories*, not as a second place data lives. Repository files remain
the source of truth (`ADR-001`). the source of truth (`ADR-001`).
> **Sharpened 2026-08-25 by `ADR-012` decision 1.** "A reading of the
> repositories" never said *which* copy of them, and the honest answer was
> neither the forge nor any particular working copy: the projection derived from
> whichever checkout last ran the sync. The hub holds no repository files at all
> and never reads one. `ADR-012` names the forge as the projection source.
**2. A local hub is a cache, never a database.** Local instances hold a **2. A local hub is a cache, never a database.** Local instances hold a
rebuildable projection. A cache may be discarded and reconstructed from the rebuildable projection. A cache may be discarded and reconstructed from the
repositories at any time, and losing it must never lose work. repositories at any time, and losing it must never lose work.
@ -118,11 +126,23 @@ conflict and belongs to git.
"Authoritative" means authoritative *reading*, so nothing may inject derived "Authoritative" means authoritative *reading*, so nothing may inject derived
state directly. Hub-native records are the exception and keep a real write path. state directly. Hub-native records are the exception and keep a real write path.
> **Sharpened 2026-08-25 by `ADR-012` decision 6.** This was policy, not
> practice: nothing derived, and the workstation pushed everything. `ADR-012`
> retires push-based sync as the primary path so that "central derives" becomes
> true rather than aspirational.
**6. Preliminary until confirmed.** Locally registered data and uncommitted **6. Preliminary until confirmed.** Locally registered data and uncommitted
repository state are preliminary until the central service has seen them. repository state are preliminary until the central service has seen them.
Mitigation is by changing the repository files and the local cache — never by Mitigation is by changing the repository files and the local cache — never by
editing central to match a local view. editing central to match a local view.
> **Given a mechanism 2026-08-25 by `ADR-012` decisions 3 and 4.** "Preliminary"
> was named here but never built, so in practice locally registered data was
> indistinguishable from derived state once it arrived. It is now a labelled
> overlay within the same projection — explicitly not a second store — and it
> retires when the commit carrying it reaches the forge. The prohibition on
> editing central to match a local view is unchanged.
Combined with `ADR-007` decision 2 (identifiers derived from `PREFIX-WP-NNNN`), Combined with `ADR-007` decision 2 (identifiers derived from `PREFIX-WP-NNNN`),
"preliminary" largely stops mattering: a cache computes the same identifier "preliminary" largely stops mattering: a cache computes the same identifier
central will, so offline-registered data is already correct on arrival and needs central will, so offline-registered data is already correct on arrival and needs

View file

@ -2,9 +2,9 @@
id: CUST-ADR-012 id: CUST-ADR-012
type: architecture-decision-record type: architecture-decision-record
title: "What the Hub Projects: Forge as Projection Source, Working Copies as Preliminary Overlay" title: "What the Hub Projects: Forge as Projection Source, Working Copies as Preliminary Overlay"
status: proposed status: accepted
owner: the-custodian owner: the-custodian
revision: "draft-1" revision: "1.0"
last_reviewed: "2026-08-25" last_reviewed: "2026-08-25"
review_interval: 6m review_interval: 6m
decided_by: Bernd Worsch decided_by: Bernd Worsch
@ -16,7 +16,7 @@ tags: ["architecture", "state-hub", "forgejo", "projection", "provenance", "auth
## Status ## Status
Proposed. Supersedes `ADR-010` decision 1's phrase "authoritative as a reading of **Accepted 2026-08-25** by Bernd Worsch. Supersedes `ADR-010` decision 1's phrase "authoritative as a reading of
the repositories" by making the reading concrete, and implements decision 6's the repositories" by making the reading concrete, and implements decision 6's
unbuilt notion of "preliminary". unbuilt notion of "preliminary".
@ -227,6 +227,11 @@ built. Those belong to implementation.
- **`ADR-010`** — decisions 1 and 5 are sharpened, not reversed: central still - **`ADR-010`** — decisions 1 and 5 are sharpened, not reversed: central still
derives and still does not accept pushes of derived state. Decision 6's derives and still does not accept pushes of derived state. Decision 6's
"preliminary" gains a mechanism. The local-cache-versus-database framing stands. "preliminary" gains a mechanism. The local-cache-versus-database framing stands.
- **`ADR-003`** — partially superseded. Decision 2 composes fingerprints from
filesystem `mtime`, which is a property of one workstation rather than of the
source; under decision 1 here the input is the commit. Decision 5 already
stated the rebuild principle correctly but had never been exercised; decision 7
here makes it an operation with a source, a scope and a verification.
- **`ADR-007`** — derived identifiers become more valuable here: a forge-derived - **`ADR-007`** — derived identifiers become more valuable here: a forge-derived
projection and a preliminary overlay compute the same identifier for the same projection and a preliminary overlay compute the same identifier for the same
record, so absorbing an overlay entry needs no reconciliation. record, so absorbing an overlay entry needs no reconciliation.