RMGR-WP-0004-T03: project repos get GOAL.md and a required prefix. RMGR-WP-0005-T06 implemented in state-hub consistency.
279 lines
10 KiB
Markdown
279 lines
10 KiB
Markdown
---
|
||
id: RMGR-WP-0005
|
||
type: workplan
|
||
title: "Registrar consolidation and deterministic hub identifiers"
|
||
domain: infotech
|
||
repo: repo-manager
|
||
status: active
|
||
owner: codex
|
||
topic_slug: infotech
|
||
created: "2026-08-17"
|
||
updated: "2026-08-18"
|
||
parent_project: prj-state-hub-retirement
|
||
parent_workplan: SHR-WP-0001
|
||
related:
|
||
- RMGR-WP-0004
|
||
- STATE-WP-0080
|
||
- STATE-WP-0068
|
||
- CFED-WP-0001
|
||
state_hub_workstream_id: "7ddb5421-d960-4a3c-94b1-40b6c96abfab"
|
||
---
|
||
|
||
# Registrar consolidation and deterministic hub identifiers
|
||
|
||
## Goal
|
||
|
||
Make hub identifiers stored in repository files **derivable rather than
|
||
database-local**, so that any number of hub instances can reconcile the same
|
||
repository without overwriting each other.
|
||
|
||
Implements `ADR-007` decision 2: interim single-writer (A), target deterministic
|
||
derivation (C2).
|
||
|
||
## The defect
|
||
|
||
`state_hub_workstream_id` and `state_hub_task_id` are database-local primary
|
||
keys stored in a shared git artifact. Two hub instances over two databases each
|
||
mint their own value for the same workplan, and every sync overwrites the other.
|
||
|
||
Observed 2026-08-16 on `STATE-WP-0080`: workplan UUID `03f38314` from the
|
||
workstation hub, `bbfce36a` from a second instance (404 against the workstation
|
||
database), plus two disjoint sets of task UUIDs. Sync commits appear under both
|
||
`+0000` and `+0200` timezones, confirming two machines write to one repository.
|
||
|
||
It also inverts `ADR-001`. Files are meant to originate work with the hub as read
|
||
model; a file carrying a hub's private key is the file holding hub state.
|
||
|
||
**Scope: 758 workplan files** across the fleet currently carry these fields.
|
||
|
||
## Apply the interim single-writer rule
|
||
|
||
```task
|
||
id: RMGR-WP-0005-T01
|
||
status: todo
|
||
priority: high
|
||
state_hub_task_id: "b57a6882-280d-4f0a-9c73-899843dfc3d3"
|
||
```
|
||
|
||
Until derivation ships, exactly one instance may write hub identifiers into
|
||
repository files. The interim registrar is the automated production instance;
|
||
workstation hubs are rebuildable caches (`ADR-010` decision 2).
|
||
|
||
- Make the writeback path refuse to mint identifiers when the instance is not
|
||
the registrar, rather than relying on operator discipline.
|
||
- Provide the configuration that designates the registrar, and make a
|
||
non-registrar instance's read/project behaviour unchanged.
|
||
- Document the accepted cost: registration requires connectivity to the
|
||
registrar, so disconnected work cannot register until T03 lands.
|
||
|
||
Interim, and deliberately so — it trades availability for correctness, and T03
|
||
removes the need for the trade.
|
||
|
||
## Re-register identifiers minted outside the registrar
|
||
|
||
```task
|
||
id: RMGR-WP-0005-T02
|
||
status: wait
|
||
priority: medium
|
||
state_hub_task_id: "8e679ddb-9845-457f-8672-1fd4b7455e7b"
|
||
```
|
||
|
||
Records minted by non-registrar instances before T01 need reconciliation. Known
|
||
cases, all created 2026-08-16/17 from the workstation hub:
|
||
|
||
- `RMGR-WP-0004` (`b8b3f1e0`) and its seven tasks;
|
||
- `CFED-WP-0001` (`7a96da54`) and its thirteen tasks, plus the
|
||
`prj-canon-federation` repo record (`3809b0ff`);
|
||
- `STATE-WP-0080` — already reconciled by hand to the second instance's IDs
|
||
(`bbfce36a`), retained here as the worked example.
|
||
|
||
Prefer waiting for T03 where possible: once identifiers are derived, these
|
||
converge without manual intervention. Re-register by hand only what blocks work
|
||
before then.
|
||
|
||
## Derive identifiers deterministically
|
||
|
||
```task
|
||
id: RMGR-WP-0005-T03
|
||
status: wait
|
||
priority: high
|
||
state_hub_task_id: "28067729-498d-4f47-89bd-5b9718e999c7"
|
||
```
|
||
|
||
Replace minted UUIDs with UUIDv5 derived from the globally unique
|
||
`PREFIX-WP-NNNN` identifier (and `PREFIX-WP-NNNN-TNN` for tasks).
|
||
|
||
- Fix the namespace UUID and derivation input as a published contract — the
|
||
value must be reproducible by any implementation, not just this one.
|
||
- Field shape is unchanged, so consumers reading `state_hub_workstream_id`
|
||
keep working; only the provenance of the value changes.
|
||
- Writeback becomes idempotent: two instances write identical bytes, so the
|
||
flip-flop cannot recur regardless of how many hubs run.
|
||
|
||
**Blocked on `RMGR-WP-0004-T08`.** Deriving from a non-unique identifier
|
||
manufactures collisions: two repositories sharing `PRJ-WP-` would compute the
|
||
same UUID for different workplans. Uniqueness must be enforced first.
|
||
|
||
## Migrate the fleet
|
||
|
||
```task
|
||
id: RMGR-WP-0005-T04
|
||
status: wait
|
||
priority: high
|
||
state_hub_task_id: "503a23a9-ede1-4cf1-bd32-e9669b84ce58"
|
||
```
|
||
|
||
One-time pass over the 758 files carrying hub identifiers: compute the derived
|
||
value, update the database to match, and write the file.
|
||
|
||
- Must be all-or-nothing per repository — a half-migrated repo has some derived
|
||
and some minted identifiers and reconciles unpredictably.
|
||
- Records whose current identifier is already referenced externally (dashboards,
|
||
saved queries, progress events) need a mapping table from old to derived, kept
|
||
as provenance rather than discarded.
|
||
- Repositories with unresolved identifier collisions cannot migrate until
|
||
`ADR-007` § Migration is ruled on; skip and report them rather than guessing.
|
||
|
||
## Retire the interim rule
|
||
|
||
```task
|
||
id: RMGR-WP-0005-T05
|
||
status: wait
|
||
priority: low
|
||
state_hub_task_id: "3946d1fc-2137-4d7b-a400-29b447ca83de"
|
||
```
|
||
|
||
Once derivation is live fleet-wide, remove the single-writer restriction from
|
||
T01. Multiple hub instances become an availability choice rather than a
|
||
correctness constraint, and disconnected registration works again.
|
||
|
||
Confirm before removal: two instances reconciling the same repository produce
|
||
byte-identical writeback, and neither creates a duplicate record.
|
||
|
||
## Rebuild local instances as caches
|
||
|
||
```task
|
||
id: RMGR-WP-0005-T07
|
||
status: wait
|
||
priority: high
|
||
state_hub_task_id: "70f83359-0b61-4dc0-83b0-33f289b64e83"
|
||
```
|
||
|
||
Implement `ADR-010` decisions 1–3: the central hub on railiance is authoritative
|
||
as a *reading* of the repositories; local instances become rebuildable caches.
|
||
|
||
- A cache must be discardable and reconstructable from repository files alone,
|
||
with no work lost.
|
||
- Local work must not require a hub — repository files are self-describing, so
|
||
reading them is sufficient for working inside a repo.
|
||
- Cache reads are advisory and must carry their staleness (`ADR-010` decision 8).
|
||
|
||
Measured 2026-08-17: 955 workplans locally against 649 on the primary, 320
|
||
local-only, of which **288 are backed by files that all exist on disk**. That
|
||
portion of the divergence is redundant and needs no merge — only a rebuild.
|
||
|
||
## Separate file-derived from hub-native data
|
||
|
||
```task
|
||
id: RMGR-WP-0005-T08
|
||
status: wait
|
||
priority: high
|
||
state_hub_task_id: "241cf058-2f3e-4d49-8cc9-5c714be4a1cf"
|
||
```
|
||
|
||
Implement `ADR-010` decision 4. The two kinds need opposite handling:
|
||
|
||
- **File-derived** (workplans, tasks, statuses, dependencies) — central derives
|
||
it and must not accept pushes of it (decision 5). Offline, the git commit *is*
|
||
the write. No conflict model: conflicts are git conflicts.
|
||
- **Hub-native** (progress events, decisions, inbox messages, token events) —
|
||
central owns it, needs a real write path and a local append-only buffer for
|
||
replay. No conflict model either: append-only merges regardless of order.
|
||
|
||
Deliverable is an explicit classification of every record type the hub holds,
|
||
with its truth source and offline behaviour, so neither kind is handled by the
|
||
other's rules.
|
||
|
||
Feeds a rescope of `STATE-WP-0068` (offline write buffer and edge relay): under
|
||
this split most of what it buffers does not need buffering, and only the
|
||
append-only stream does. Re-examine before building further on it — this likely
|
||
reduces its scope.
|
||
|
||
## Disposition the orphaned hub-first records
|
||
|
||
```task
|
||
id: RMGR-WP-0005-T09
|
||
status: wait
|
||
priority: high
|
||
state_hub_task_id: "d40cc4a8-4280-4940-ac1d-dc1049f1b678"
|
||
```
|
||
|
||
28 records exist in the local instance with no backing file. They are the only
|
||
records a cache rebuild would drop, so they must be classified first
|
||
(`ADR-010` § Orphan disposition):
|
||
|
||
1. **Broken links** — a file exists but `backing_filename` was never recorded.
|
||
`RMGR-WP-0004` is a confirmed instance. Repair the link; no data at risk.
|
||
Likely the largest class, so classify before estimating the rest.
|
||
2. **Live hub-first records** — `proposed`/`ready`/`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`. Write a repository file or drop explicitly. These are
|
||
`ADR-001` violations and must not survive as hub-only records.
|
||
3. **Closed hub-first records** — `finished`/`archived` with no file. Retain as
|
||
provenance where cheap; do not reconstruct completed plans.
|
||
|
||
**Blocks T07** — rebuilding the cache before this classification would discard
|
||
class 2.
|
||
|
||
Note: one of these records is already labelled `SPURIOUS bootstrap (statehub
|
||
register collision)` in `repo-manager`, independent corroboration of the
|
||
`STATE-WP-0080` defect.
|
||
|
||
## Assign one authoritative hub per record
|
||
|
||
```task
|
||
id: RMGR-WP-0005-T10
|
||
status: wait
|
||
priority: medium
|
||
state_hub_task_id: "15f0f167-a8d0-4d5c-8576-3e93b1e8792f"
|
||
```
|
||
|
||
Implement `ADR-010` decision 7. The retirement splits one hub into several, which
|
||
is permitted only if every record has exactly one authoritative hub, determined
|
||
by its repository and domain.
|
||
|
||
Define and enforce that mapping before the split lands. Without it the
|
||
peer-database divergence this workplan exists to remove recurs at larger scale.
|
||
|
||
Coordinate with the hub-extension architecture in
|
||
`prj-state-hub-retirement/architecture/`; `hub-core` owns the hub-native side.
|
||
|
||
## Protect lifecycle status from automation
|
||
|
||
```task
|
||
id: RMGR-WP-0005-T06
|
||
status: done
|
||
priority: medium
|
||
state_hub_task_id: "d440d59c-f78e-4752-84c7-f3d5fdf7d3c3"
|
||
```
|
||
|
||
Implement `ADR-007` decision 3: an automated normalization pass may report
|
||
lifecycle drift but may not promote a workplan from `proposed` to `active`.
|
||
`proposed` means awaiting human review; automated promotion destroys the gate.
|
||
|
||
Observed: commit `ff909e1` ("renormalize lifecycle state [auto]") promoted
|
||
`STATE-WP-0080` to `active` hours after it was drafted for review.
|
||
|
||
Extend the same protection to task status, where the symptom is currently
|
||
sharper: `C-15` forces `CFED-WP-0001-T02` back to `wait` on every sync
|
||
regardless of file content — reproduced three times, via file edit and via
|
||
`update_task_status`, with the task never holding `todo`. Establish which
|
||
direction wins for task status and make it consistent with `ADR-001`, where the
|
||
file originates work.
|
||
|
||
**Result (2026-08-18):** In `state-hub` consistency: C-23 does not
|
||
auto-promote `proposed` → `active` (report only). C-15 no longer
|
||
writebacks wait over progress/todo; file wins via C-10 (ADR-001).
|
||
C-15 remains a non-fixable warning when the DB is terminal and the file
|
||
is not.
|