15 KiB
| id | type | title | status | owner | revision | last_reviewed | review_interval | decided_by | date | accepted | tags | |||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| CUST-ADR-007 | architecture-decision-record | Workplan Identity Uniqueness, Single Registrar, and Repo Worker Topology | accepted | the-custodian | accepted-2 | 2026-08-31 | 6m | Bernd Worsch | 2026-08-16 | 2026-08-17 |
|
ADR-007: Workplan Identity Uniqueness, Single Registrar, and Repo Worker Topology
Status
Accepted 2026-08-17. Identifier uniqueness, the registrar model, lifecycle protection, and worker topology are settled.
Remediation of existing collisions (§ Migration) remains an open ruling. It
is disruptive, touches six repositories, and no active work depends on it — all
five duplicated identifiers are finished.
Context
On 2026-08-16, STATE-WP-0080 was found registered twice, in two different
databases, with two different workplan UUIDs and two disjoint sets of task
UUIDs:
| Registrar | Workplan UUID | Reachable at 127.0.0.1:8000 |
|---|---|---|
Workstation hub (make api, local postgres) |
03f38314 |
yes |
| A second instance, over a second database | bbfce36a |
404 |
The second instance is not identifiable from the commit author.
custodian-sync@railiance.local is a hardcoded default git identity in
scripts/consistency_check.py:1899 (GIT_SYNC_USER_NAME /
GIT_SYNC_USER_EMAIL), so every machine running fix-consistency commits under
that name. The discriminator is the timezone: sync commits appear under both
+0000 and +0200 (the workstation's offset), which is independent evidence of
two machines writing to one repository.
Both write their IDs into the same git-tracked workplan file, so each sync
overwrites the other's IDs and the file flip-flops on every round trip. The same
commit (ff909e1, "renormalize lifecycle state [auto]") also promoted the
workplan proposed → active without human review.
A fleet scan of 955 hub workplans (525 with parseable PREFIX-WP-NNNN
identifiers) found this is not an isolated incident. Two distinct identity
defects are live:
Prefix reuse across repositories:
CUST-WP- → state-hub, the-custodian
RAIL-BS-WP- → railiance-bootstrap, railiance-cluster
RAILIANCE-WP- → railiance-apps, railiance-forge, railiance-platform, railiance-telemetry
PRJ-WP- is a latent fourth: statehub register derives it from the prj-
flavor marker, so every project repository would collide (see RMGR-WP-0004).
Running-number reuse:
CUST-WP-0000 the-custodian ×2
CUST-WP-0010 the-custodian ×2
CUST-WP-0045 the-custodian ×2
RAILIANCE-WP-0015 railiance-platform, railiance-apps
RAILIANCE-WP-0016 railiance-platform ×2, railiance-apps
RAILIANCE-WP-0015 is actively cited in operational memory as the cnpg-backup
gate in railiance-apps; a second record of the same name in
railiance-platform makes that citation ambiguous.
The C-26 consistency check already flags prefix nonconformance within a repo
against a canonical prefix, but nothing enforces uniqueness across repos, and
nothing prevents number reuse.
Decision
1. A workplan identifier is globally unique. PREFIX-WP-NNNN names exactly
one workplan across the entire fleet, for all time.
Amended 2026-08-17 by
ADR-011decision 2. Uniqueness and forward-only allocation are namespace-scoped, not global; global identity is the pair(namespace, identifier), writtenPREFIX-WP-NNNN@namespacewhen foreign. Global sequential allocation would require a central coordinator — the exact dependency federation must survive. Everything below holds unchanged within a namespace, which is where all current work sits.
- A workplan prefix is owned by exactly one repository. No two repositories may use the same prefix.
- A running number is never reused within a prefix, including after a workplan is cancelled, archived, or deleted. Numbers are allocated forward only.
- Prefixes are derived from the project or repository identity, never from a
flavor marker or category (
PRJ-WP-is invalid by construction).
2. Hub identifiers stored in repository files must be derivable, not database-local. The defect is structural: a database-local key is stored in a shared artifact, so each database overwrites the other's value on every sync. It also inverts ADR-001 — a file carrying a hub's private key is the file holding hub state.
Target state (C2). state_hub_workstream_id and state_hub_task_id become
deterministic: UUIDv5 derived from the workplan identifier. Per ADR-011
decision 3 the derivation input is the pair (namespace, identifier), not the
identifier alone — deriving from the identifier alone would make two forks
holding unrelated work under the same number compute the same UUID. Every instance computes the same value independently, writeback
becomes idempotent, and any number of hub instances may coexist without
coordination. The field shape is unchanged, so consumers keep working; only the
provenance of the value changes.
This has a hard prerequisite: deterministic derivation from a non-unique
identifier would manufacture collisions rather than remove them. Two project
repos sharing PRJ-WP- would compute the same UUID for different workplans.
Decision 1 must therefore be enforced before derivation ships.
Interim state (A). Until derivation lands, exactly one instance writes hub identifiers into repository files. Other instances may read, project, and serve, but must not mint workplan or task UUIDs into git-tracked files.
Corrected 2026-08-17, superseded by
ADR-010decisions 1–3. This decision originally described workstation hubs as "development read replicas". That was wrong on both counts: the workstation instance was not a replica, and it was the larger of the two, holding 306 more workplans than the primary. The two instances were peer databases.ADR-010establishes the central hub as authoritative and local instances as rebuildable caches, which is what makes this interim rule coherent.
The interim is policy, enforced by discipline, and it has a real cost: registration requires connectivity to the registrar, so disconnected work cannot register. That cost is accepted only until C2 removes the need for it, at which point the number of hub instances becomes an availability choice rather than a correctness constraint.
Rejected. Collapsing to a single shared database (workstation hubs pointing at
the production database) would also make identifiers consistent by construction,
but it eliminates offline capability — cutting directly against STATE-WP-0068
(offline write buffer and edge relay) — and couples all local work to tunnel
availability.
Ownership. Both the interim guard and the derivation belong to repo-manager
under decision 747011c6, which already places file-backed record indexing and
reconciliation there. Building either in state-hub would invest in a component
being retired under STATE-WP-0079.
Migration scope for C2: 758 workplan files across the fleet currently carry these fields.
Amended 2026-08-21 — derivation scope for C2.
ADR-011decision 7 keys derivation on(namespace, identifier), which separates forks. It does not separate collisions inside one namespace, and the ecosystem's posture isN1— a single implied namespace. A fleet scan on 2026-08-21 found 20 reused identifiers across 48 files, all within that one namespace, so the prerequisite above is not satisfied byADR-011alone.Ruled: C2 derives only for live records; archived records keep their minted identifiers, frozen. This is what reconciles § Migration option 2 — under which historical files keep colliding identifiers — with the uniqueness derivation requires. Of the 20, only five collide among live files, so the remediation surface is 11 files rather than 48.
Two consequences follow, and both are load-bearing:
- Un-archiving a record with a frozen identifier is a collision hazard. A record returning to live status must be checked against the live namespace before it is re-derived, and renumbered if it clashes.
- Derivation is not retroactive. Existing live records keep their minted UUIDs until they are re-derived deliberately; C2 changes provenance for new and re-registered records, not the whole corpus at once.
Rejected: treating a repository as the namespace. That would make the collisions vanish by construction, but it redefines the term
ADR-011decision 1 fixes as "a fleet instance, a client deployment, an autonomous domain", andADR-011decision 9 warns specifically against reading N-plane movement into claims it does not support.
3. Lifecycle status is not automatically promoted. An automated
normalization pass may report drift; it may not move a workplan from proposed
to active. proposed means awaiting human review, and an automation that
promotes it destroys the meaning of the review gate.
4. Repository manipulation is performed by a worker agent in that repository. This is the default topology.
- A worker acting in repo X owns changes to repo X.
- Multiple independent top-level workers inside a single repository are an exception, requiring an explicit reason, not a routine mode of operation.
- Concurrent independent writers are what turned a two-registrar bug into repeated git divergence.
5. Project (prj-) repositories may act across their participating
repositories. When work is governed by a project repo, its tasks may direct
changes across every repository the project names, through the project's work
agent, where that is more efficient than delegating.
This is a deliberate, scoped exception to decision 4: the project repo already
owns cross-repo sequencing and its SCOPE.md names its participants, so its
authority is declared rather than ad hoc. It does not license a worker in an
arbitrary repository to reach into others.
Consequences
Positive. Workplan identifiers become citable without qualification.
Hub IDs stop flip-flopping in git. The proposed status regains meaning.
Cross-repo authority becomes something a repository declares rather than
something any session assumes.
Negative. Existing collisions must be remediated (see below), which is disruptive. Workstation sessions lose the ability to register workplans directly and must route through the registrar or a worker in the owning repo. Prefix allocation needs a fleet-level registry, which is new machinery.
Enforcement. Prefix ownership, uniqueness, and forward-only numbering are
repository standards, so they belong to Repo Manager under decision 747011c6
(RMGR-WP-0004), not to a hub. Canon defines the rule; Repo Manager checks it.
Migration — needs a separate ruling
Three prefixes and five identifiers are already colliding. Remediation options, in increasing cost:
- Freeze and forward-fix. Accept existing collisions as historical, enforce
uniqueness only for new workplans. Cheapest; leaves
RAILIANCE-WP-0015permanently ambiguous. - Renumber the live collisions only. Fix identifiers that are still cited or
active; leave
finished/archivedduplicates alone. - Full renaming. Give
railiance-apps,railiance-forge,railiance-platform,railiance-telemetrydistinct prefixes, likewiserailiance-bootstrap/railiance-clusterandstate-hub's legacyCUST-WP-files. Touches six repositories and every inbound reference.
Ruled 2026-08-17: option 2. Renumber live collisions; leave
finished/archived duplicates as historical record.
The live renumber list is empty
Verified against the fleet scan. All five duplicated identifiers are finished:
CUST-WP-0000 the-custodian ×2 finished
CUST-WP-0010 the-custodian ×2 finished
CUST-WP-0045 the-custodian ×2 finished
RAILIANCE-WP-0015 apps, platform finished
RAILIANCE-WP-0016 apps, platform ×2 finished
No workplan in a proposed, ready, active, blocked, or backlog state
shares an identifier with another. Option 2 therefore requires no renumbering
today. Historical duplicates stay, including the RAILIANCE-WP-0015 ambiguity
between railiance-apps and railiance-platform; citations of it must name the
repository.
The structural cause is not historical
Option 2 governs remediation. It does not exempt anything from decision 1, which is accepted canon: one prefix, one repository, forward-only numbering.
Three shared prefixes are still in use across seven repositories, and each is a single number line being allocated from concurrently:
RAIL-BS-WP- bootstrap 8, 9
cluster 7, 10, 11, 12, 13, 14
RAILIANCE-WP- platform 5, 8-17 (16 twice — an internal duplicate)
apps 15, 16 <- already collided with platform
forge 2
telemetry 1
CUST-WP- the-custodian 50 plans
state-hub 4 legacy plans (canonical prefix is STATE-WP)
RAIL-BS- and RAILIANCE- are actively growing — RAIL-BS-WP-0014 (ready),
RAILIANCE-WP-0002 (ready), RAILIANCE-WP-0001 (proposed), all created
2026-08-11 or later. The RAILIANCE-WP-0015/0016 collisions were not a
historical accident; they are what concurrent allocation from a shared sequence
produces, and it will recur at the next concurrent allocation.
CUST- is dormant on the state-hub side — four legacy plans, one in
backlog — and needs no split, only a prefix-ownership assertion.
Prefix assignments
RAIL-BS-WP- is retired (2026-08-17). Neither repository keeps it:
railiance-cluster adopts RCLUSTER-WP- for active and future plans;
railiance-bootstrap adopts RBS-WP- for future plans. Finished and archived
files keep RAIL-BS-WP- as historical record, consistent with option 2.
Migrating plans keep their running numbers — the prefix changes, the number does
not. This preserves traceability and cannot violate forward-only allocation,
because neither new prefix has prior history. railiance-bootstrap begins at
RBS-WP-0010, above its historical maximum, leaving the lower range free should
its finished plans ever be adopted into the new prefix.
RAILIANCE-WP- should follow the same pattern — retired rather than awarded to
one repository, since it names a family rather than a repository and so fails
decision 1 for the same reason PRJ-WP- does. Assignment of the four successor
prefixes is outstanding.
Execution of each rename belongs to a worker in the owning repository under
decision 4. RMGR-WP-0004-T09 records assignments and the numbering rule; it
does not perform renames.
Consequence. Prefix ownership must be assigned for all three shared prefixes
before the next workplan is created in the affected repositories. This is
forward conformance under decision 1, not migration, and is tracked as
RMGR-WP-0004-T09. Renaming the historical files is explicitly not required —
that would be option 3, which was rejected.
References
- Decision
747011c6— repository standards belong to Repo Manager - ADR-001 — workplans originate as repo files; hub is a read model
RMGR-WP-0004— repository standards conformance and governed scaffoldingSTATE-WP-0080— register scaffolding handoff- Fleet scan 2026-08-16: 955 hub workplans, 525 parseable identifiers, 3 reused prefixes, 5 reused identifiers