CUST-ADR-010 proposed · draft-1 the-custodian reviewed 2026-08-17generated from canonical source — do not edit

Hub Authority, Local Cache, and the Two Kinds of Hub Data

Source: the-custodian · canon/architecture/adr-010-hub-authority-and-local-cache-model.md · 4039c9d1c08c92014ecc0a65dda63cc73ba187bb

Review due: 2027-02-17

Status

Proposed.

Context

Investigating a workplan-identifier flip-flop (ADR-007) revealed that two State Hub instances were operating as peer databases, not as a primary and a replica:

AddressInstanceWorkplans
127.0.0.1:8000 (IPv4)local uvicorn on docker postgres955
[::1]:8000 (IPv6)ssh tunnel state-hub-primary → railiance01649

Both listen on port 8000, separated only by IP family, so every tool defaulting to 127.0.0.1 reached the local instance while believing it was the primary.

Measured divergence — 320 records exist locally but not on the primary:

backed by a file that exists on disk    288    fully rebuildable
no backing file recorded                 28    not rebuildable as-is
same filename, different UUID             4    duplicate registration

No file was missing for any of the 288. The divergence is therefore almost entirely redundant: it can be discarded and rebuilt from repositories without losing anything.

ADR-001 already says work originates as repository files and the hub is a read model. The two-peer-database situation contradicts that in practice: a second database accumulated 306 net records of its own.

Decision

1. One authoritative hub, deriving from repository files. The central State Hub — running on railiance — is authoritative. It is authoritative as a reading of the repositories, not as a second place data lives. Repository files remain the source of truth (ADR-001).

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 repositories at any time, and losing it must never lose work.

This replaces the peer-database arrangement. It is also why the divergence is tractable: a divergent database is a merge problem, a stale cache is a refresh problem.

3. Local work requires no hub at all. Repository files are self-describing — identifier, status, tasks, all in frontmatter. Working in a repository requires reading files, not querying an index. A cache is an optimization for cross-repo questions, never a prerequisite for doing work.

4. Hub data is classified by origin, and the two kinds have opposite rules.

File-derivedHub-native
Examplesworkplans, tasks, statuses, dependenciesprogress events, decisions, inbox messages, token events
Source of truththe repository filethe hub
Offline behaviourwrite the file and commit — the commit is the writebuffer locally, replay when reachable
Conflict modelnone; conflicts are git conflicts, resolved in gitnone; append-only merges regardless of order
Central accepts pushes?no — it derivesyes

Neither kind needs a hub-side conflict model. That is the point of the split: if central derives file-backed state, it cannot hold a conflicting version of it — it re-derives whatever git settles on. Two people editing one workplan is a git conflict and belongs to git.

5. Central derives file-backed state; it does not accept pushes of it. "Authoritative" means authoritative reading, so nothing may inject derived state directly. Hub-native records are the exception and keep a real write path.

6. Preliminary until confirmed. Locally registered data and uncommitted repository state are preliminary until the central service has seen them. Mitigation is by changing the repository files and the local cache — never by editing central to match a local view.

Combined with ADR-007 decision 2 (identifiers derived from PREFIX-WP-NNNN), "preliminary" largely stops mattering: a cache computes the same identifier central will, so offline-registered data is already correct on arrival and needs confirmation rather than reconciliation.

7. Every record has exactly one authoritative hub. The State Hub retirement splits one hub into several. Multiple central hubs are permitted only under this rule: the owning hub is determined by the record's repository and domain. Without it, the same peer-database divergence recurs at larger scale.

8. Cache reads are advisory and must carry their age. Cross-repo answers from a cache are advisory and should be presented with staleness. For the repository an agent is working in, the file is truth and the cache is never consulted for correctness.

Orphan disposition

The 28 records with no backing file are the only ones a cache rebuild would drop. They fall into three classes, to be separated before any rebuild:

  1. Broken links — a file exists but backing_filename was never recorded. RMGR-WP-0004 is one: the workplan file exists and is committed. These are metadata repairs, not data loss, and are likely the largest class.
  2. Live hub-first recordsproposed, ready, or backlog with no file, in activity-core, core-hub, hub-core, issue-core, ops-hub, prj-forgejo-org-refactor, railiance-enablement, railiance-infra, reef-railiance. Each needs a repository file written or an explicit drop. These are ADR-001 violations and must not be preserved as hub-only records.
  3. Closed hub-first recordsfinished or archived with no file. Retain as historical provenance where cheap; do not reconstruct plans that are done.

A cache rebuild enforces ADR-001 retroactively: the only casualties are records that broke it.

Consequences

Positive. The divergence becomes discardable rather than mergeable. Offline work is fully supported without a write buffer for file-backed state — the git commit is the write. No hub-side conflict model is needed for either data kind. Authority stops being a policy claim and becomes a structural property.

Negative. The 28 orphans require case-by-case disposition before a rebuild. Any consumer that treats a local hub as authoritative must be corrected. The one-hub-per-record rule constrains the retirement's hub split.

Rescoping. STATE-WP-0068 (offline write buffer and edge relay) is scoped as a single mechanism. Under decision 4, most of what it buffers does not need buffering — only the append-only hub-native stream does. Its scope should be re-examined before more is built on it; this may reduce work rather than add it.

Correction to ADR-007. Decision 2 there calls the workstation instance a "development read replica". It was neither a replica nor smaller — it held 306 more workplans than the primary. Superseded by decisions 1–3 here.

Implementation

Owned by repo-manager for file-derived state (decision 747011c6; it already owns repository representation, file-backed record indexing, and reconciliation) and by hub-core for hub-native records. Tracked under RMGR-WP-0005.

References

  • ADR-001 — workplans originate as repo files; hub is a read model
  • ADR-007 — identifier uniqueness, derived identifiers, worker topology
  • Decision 747011c6 — repository standards belong to Repo Manager
  • RMGR-WP-0005 — registrar consolidation and deterministic identifiers
  • STATE-WP-0068 — offline write buffer and edge relay (rescope candidate)
  • Divergence measurement, 2026-08-17: 955 local / 649 primary / 320 local-only