diff --git a/canon/architecture/adr-011-federated-namespaces-and-reconciliation-limits.md b/canon/architecture/adr-011-federated-namespaces-and-reconciliation-limits.md index 907f8aa..1b9643a 100644 --- a/canon/architecture/adr-011-federated-namespaces-and-reconciliation-limits.md +++ b/canon/architecture/adr-011-federated-namespaces-and-reconciliation-limits.md @@ -1,59 +1,134 @@ --- id: ADR-011 type: architecture-decision-record -title: "Federated Namespaces, Qualified Identifiers, and the Limits of Reconciliation" +title: "Federated Namespaces: Four Planes, Declared Posture, and the Limits of Reconciliation" status: proposed decided_by: Bernd Worsch date: "2026-08-17" -tags: ["architecture", "federation", "namespace", "identity", "reconciliation", "fos", "adr-007", "adr-008"] +revision: "draft-2" +tags: ["architecture", "federation", "namespace", "identity", "reconciliation", "posture", "fos", "adr-007", "adr-008", "adr-010"] --- -# ADR-011: Federated Namespaces, Qualified Identifiers, and the Limits of Reconciliation +# ADR-011: Federated Namespaces — Four Planes, Declared Posture, and the Limits of Reconciliation ## Status -Proposed. Amends `ADR-007` decision 1 and extends `ADR-010` decision 4. +Proposed, draft-2. Amends `ADR-007` decisions 1 and 2; extends `ADR-010` +decision 4; adopts the plane/ladder/posture form and the accuracy-not-altitude +conformance rule from `ADR-008` (Multi-Tenancy Framework). ## Context The ecosystem must be **federation-capable** — able to work without a live link -to central services — and **chain-of-command efficient**. These read as opposing -requirements, but `federated-organization-standard_v1.0` already resolves the -organizational half: +to central services — and **chain-of-command efficient**. +`federated-organization-standard_v1.0` already resolves the organizational half: > global coherence is achieved through policy, escalation, and shared protocols > rather than through monolithic control (`:51`) > > bounded autonomy plus disciplined coordination (`:86`) -Authority is a **policy** layer; availability is a **mechanism**. Nothing -requires the mechanism to depend on reaching the authority — the same separation -distributed version control makes, where an integration branch is privileged by -agreement rather than by any technical property. +Authority is a **policy** layer; availability is a **mechanism**. Distributed +version control makes the same separation: an integration branch is privileged by +agreement, never by a technical property. -**One accepted decision does violate this.** `ADR-007` decision 1 requires -running numbers that are *globally* unique and allocated forward only. Global -sequential allocation requires a coordinator — precisely the central dependency -federation must survive. Two disconnected forks each allocating -`RCLUSTER-WP-0015` is not an edge case but a certainty. +**One accepted decision violates this.** `ADR-007` decision 1 requires running +numbers that are *globally* unique and allocated forward only. Global sequential +allocation requires a coordinator — precisely the central dependency federation +must survive. Two disconnected forks each allocating `RCLUSTER-WP-0015` is a +certainty, not an edge case. This is not hypothetical. Instance-per-client tenancy (`CUST-WP-0058`) already -means each client deployment is a fork of the stack; the business model committed +makes every client deployment a fork of the stack; the business model committed to forking before the identifier scheme could express it. +### Why this draft changed form + +Draft-1 stated federation as a set of binary rules — notably "records fork, +effects do not". That is a single verdict where a graduated declaration belongs, +and it is the same conflation `ADR-008` §03 diagnoses for multi-tenancy: +*"'Is this multi-tenant?' is treated as one question. It is four, and they are +independent."* + +"Is this federation-capable?" is likewise not one question. A namespace can be +strong on identity and incapable of disconnected operation; it can operate +disconnected and have no way to reconcile afterwards. Draft-1 could not say so. + +This draft reuses `ADR-008`'s vocabulary rather than inventing a parallel one. +Two competing maturity vocabularies in one canon would be its own collision. + ## Decision **1. Records live in a namespace.** A namespace is a federated branch of the ecosystem — a fleet instance, a client deployment, an autonomous domain that may -operate disconnected. It is the unit of sovereignty in FOS terms, and the unit of +operate disconnected. It is the unit of sovereignty in FOS terms and the unit of divergence here. -**2. Identifiers are unique within a namespace, qualified across namespaces.** -`ADR-007` decision 1 is amended: uniqueness and forward-only allocation are -**namespace-scoped**, not global. Global identity is the pair -`(namespace, identifier)`. +**2. Federation is four orthogonal planes.** -Notation is a suffix: +| Plane | Question | Vocabulary owner | +|---|---|---| +| Namespace **N** | How are records named and disambiguated across branches? | this ADR | +| Autonomy **U** | Can work proceed with no link to central services? | repo-manager | +| Reconciliation **R** | What happens when branches meet again? | repo-manager | +| Substrate **S** | Does this namespace hold independently diverging operational state? | railiance-platform | + +**3. Each plane carries a ladder.** Higher is stronger, not better. The right +level is the one a namespace can evidence and its risk warrants. + +```text +N0 no namespace concept; identifiers assume one global space +N1 namespace implied by deployment, never recorded +N2 namespace declared; identifiers namespace-scoped; qualification available +N3 N2 + lineage recorded, and derived identifiers keyed on (namespace, identifier) + +U0 routine work requires the central service +U1 degraded read-only; writes blocked while disconnected +U2 work proceeds locally: file-derived state written to files, hub-native buffered +U3 U2 + exercised — a dated disconnection drill with evidence + +R0 no defined path; divergence is unrecoverable +R1 manual, per-record comparison and hand resolution +R2 append-only events plus derived state: union and re-derive, deterministic +R3 R2 + lineage-aware; distinguishes divergence from collision automatically + +S0 shares operational substrate with another namespace — cannot fork safely +S1 shared substrate, namespace-keyed +S2 dedicated substrate, no independent state divergence yet +S3 independent operational substrate with diverged state — the fork is real +``` + +**4. A namespace declares a posture vector**, in the repository rather than the +hub, consistent with `ADR-010` decision 4 (file-derived state) and `ADR-008` +decision 5.1. + +```yaml +federation: + current: { N: 1, U: 1, R: 1, S: 1 } + target: { N: 3, U: 2, R: 2, S: 1 } + reviewed: "2026-08-18" + gap: + U: "Registration requires the registrar under ADR-007 decision 2 interim. + Lifts when derived identifiers land (RMGR-WP-0005-T03)." +``` + +**The ecosystem's own posture today is `N1 U1 R1 S1`** — one implied namespace, +disconnected registration blocked, reconciliation manual, substrate shared. +Declaring that is conformant. Claiming better is not. + +**5. Conformance is accuracy, not altitude.** Adopted verbatim in force from +`ADR-008` §06: a namespace is conformant when its declared posture is accurate, +its target recorded, and it claims no level it cannot evidence. It is +non-conformant when it overclaims, at any altitude. + +Declaring `S0` is conformant. Concealing `S0` is not. A repository may join at +any posture; it may not join silently. This matters more here than it does for +tenancy: the cost of discovering a true posture during reconciliation is the +whole difference between T2 and T3. + +**6. Identifiers are unique within a namespace, qualified across.** `ADR-007` +decision 1 is amended: uniqueness and forward-only allocation are +**namespace-scoped**. Global identity is the pair `(namespace, identifier)`. ```text RCLUSTER-WP-0015 this namespace — the common case, unchanged @@ -61,40 +136,77 @@ RCLUSTER-WP-0015@railiance01 a foreign namespace, explicitly qualified ``` Unqualified always means "in my own namespace", exactly as `main` does against -`origin/main`. A suffix keeps existing sorting, grep, and tooling working; a -prefix would break them. +`origin/main`. A suffix preserves existing sorting, grep, and tooling; a prefix +would break them. -**3. Deterministic identifiers derive from the pair.** `ADR-007` decision 2 (C2) -derives UUIDv5 from `PREFIX-WP-NNNN`. Under federation the derivation input must -be `(namespace, identifier)`. Deriving from the identifier alone would make two -forks holding unrelated work under the same number compute the *same* UUID — -a collision manufactured by the fix. C2 is not yet built, so this is free now and +**7. Derived identifiers key on the pair.** `ADR-007` decision 2 (C2) derives +UUIDv5 from the identifier. Under federation the input must be +`(namespace, identifier)`. Deriving from the identifier alone would make two +forks holding unrelated work under the same number compute the *same* UUID — a +collision manufactured by the fix. C2 is not yet built, so this is free now and expensive later. -**4. Records carry lineage.** A namespace records what it forked from and at what -point; a record forked from another namespace records its origin. Without -lineage, a shared identifier is ambiguous between *the same work, diverged* and -*different work, colliding* — a distinction that cannot be reconstructed after -the fact. +**8. The planes couple at their upper levels. State the coupling; do not use it +to argue the planes are one.** -**5. Mutable state is derived from an append-only log.** Extending `ADR-010` -decision 4: status and other mutable fields are a fold over append-only events -rather than fields to be reconciled. Reconciliation then becomes union-of-events -plus re-derivation — deterministic, order-independent, and requiring no -conflict model. This collapses the hardest part of reconciliation into the part -that was already free. +- `R3` requires `N3` — distinguishing divergence from collision requires lineage. +- A namespace may not sustain `U2` or above while below `R2`. Operating + disconnected without deterministic reconciliation accumulates divergence that + cannot later be merged. Autonomy without reconciliation is not federation; it + is an unplanned fork. +- `T3` is entailed by `S3` in any participant (decision 10). -**6. Coexistence is the normal case; merging is the exception.** The qualifier is -primarily a **coexistence** mechanism, not merge preparation. Most forks — -client instances above all — are never intended to return. The architecture must -support permanent parallel operation as a first-class outcome, not as a failure -to reconcile. +**9. Anti-overclaim.** This is the most misusable fact in the framework, and it +is the direct analogue of `ADR-008`'s `P0 → P1 → P2` warning. -**7. What may fork.** Canon, plans, knowledge, and records fork freely. **Effects -do not.** Two namespaces may hold divergent plans about one production database; -they cannot hold divergent production databases. Work that acts on shared -operational infrastructure is not fork-safe and must be coordinated through the -owning namespace. +> Adopting namespace-qualified identifiers is movement on the **N plane only**. +> It buys disambiguation, citability, and coordinator-free allocation. It does +> **not** raise autonomy, reconciliation, or substrate independence by one step. +> A system at `N3 U0 R0 S0` cannot operate disconnected and cannot reconcile. + +No namespace may be described as "federation-capable", "independently operable", +or "able to run disconnected" on N-plane evidence alone. Such a claim requires +declared `U` and `R` levels with evidence behind them. + +**Commercially**, client-facing claims about instance independence must cite the +`S` and `U` levels, never the identifier scheme. Instance-per-client tenancy is +sold on substrate independence; the qualifier does not supply it. + +**10. The reconciliation tier is derived from participants' postures, not judged +after the fact.** + +```text +any participant at S3 -> T3 (regardless of other planes) +all participants S<=S2 and R>=R2 -> T2 feasible +any participant below R2 -> T1 at best; manual thereafter +``` + +This is the practical payoff of declaring postures: the cost of rejoining is +**computable before a fork is created**, rather than discovered when +reconciliation is attempted. + +**11. Coexistence is the normal case; merging is the exception.** The qualifier +is primarily a coexistence mechanism, not merge preparation. Most forks — client +instances above all — are never intended to return. Permanent parallel operation +is a first-class outcome, not a failure to reconcile. + +**12. Evidence.** A claimed level requires evidence, per `ADR-008` §13. + +| Level | Evidence | +|---|---| +| `N2` | namespace declared in the repo; qualified references resolve | +| `N3` | lineage fields present; a derived identifier reproduced by an independent implementation | +| `U2` | work completed with central unreachable, committed, later accepted without rework | +| `U3` | dated disconnection drill record | +| `R2` | replaying the union of events reproduces identical derived state | +| `R3` | a collision and a divergence, correctly distinguished, in test | +| `S2` / `S3` | substrate inventory naming the stateful systems and whether their state has diverged | + +**13. Guard.** Declared postures regress silently. Posture is checked by the same +consistency machinery that checks repository standards (`RMGR-WP-0004-T02`, +`rmgr conform`), so a namespace that drops below its declared level is a +reported defect rather than a discovery. A regression found by guarding is a +defect; a regression declared in advance is a decision. ## Reconciliation tiers, and where automation stops @@ -102,11 +214,8 @@ owning namespace. |---|---|---|---| | **T0 Fork** | namespace created, lineage recorded | metadata | yes | | **T1 Sync** | pull canon, plans, or knowledge from another namespace | append events, re-derive | largely | -| **T2 Reintegration** | fork returns; records diverged, **no independent operational infrastructure** | union events, re-derive, human-resolve genuine contradictions | partly | -| **T3 Amalgamation** | **distinct operational infrastructure**, identity, credentials, data stores, possibly distinct canon | governed programme — see below | **no** | - -**The T2/T3 test is whether the fork established its own operational -infrastructure** — stateful systems with independently diverged state. +| **T2 Reintegration** | records diverged, no participant above `S2` | union events, re-derive, human-resolve genuine contradictions | partly | +| **T3 Amalgamation** | any participant at `S3` | governed programme — see below | **no** | **T3 is not a merge.** It resembles the merger or acquisition of distinct companies far more than a version-control merge, and must be planned as such: @@ -120,46 +229,49 @@ companies far more than a version-control merge, and must be planned as such: **T3 may legitimately end without integration.** Permanent coexistence, or divestment, are valid outcomes. Real mergers most often fail at systems -integration; an architecture that assumes eventual convergence is lying about -its own limits. +integration; an architecture that assumes eventual convergence is lying about its +own limits. ### Known cost `prj-state-hub-retirement` is a T3 reconciliation inside a *single* -organization — two hub implementations with distinct infrastructure. It required -a dedicated project repository, a 425-item disposition inventory (`SHR-INV-0001`), +organization — two hub implementations, distinct infrastructure. It required a +dedicated project repository, a 425-item disposition inventory (`SHR-INV-0001`), staged migration with strangler adapters, and explicit retirement gates. That is -the realistic cost of T3 under the most favourable possible conditions: one +the realistic cost of T3 under the most favourable conditions possible: one owner, one canon, one credential authority. -Nothing in this ADR reduces that cost. It ensures the cost is **visible before** -a fork is created rather than discovered when reconciliation is attempted. +Nothing here reduces that cost. Declared postures make it **visible before** a +fork is created rather than discovered when reconciliation is attempted. ## Consequences **Positive.** Disconnected operation stops requiring a coordinator for identity. -`ADR-007` decision 1's contradiction is resolved rather than tolerated. Client -instances become expressible. Reconciliation limits are stated rather than -implied. +`ADR-007` decision 1's contradiction is resolved rather than tolerated. A +namespace mid-journey can describe itself honestly instead of being +non-conformant. Reconciliation cost becomes computable in advance. Client +instances become expressible. -**Negative.** Every record gains a namespace and lineage, and tooling must learn -qualified references. The fork-boundary rule (decision 7) constrains what -disconnected work may legitimately do — deliberately. +**Negative.** Every namespace gains a posture to declare and keep accurate, and +tooling must learn qualified references. Decision 8's coupling rule constrains +disconnected operation to namespaces that can reconcile — deliberately. **Deferred.** Merge machinery for T2 is **not** specified here and should not be -built until a real fork exists and needs it. T3 needs no machinery by definition; -it needs a project repository and human judgement. +built until a real fork needs it. T3 needs no machinery by definition; it needs a +project repository and human judgement. -**Amended.** `ADR-007` decision 1 — uniqueness is namespace-scoped, not global. +**Amended.** `ADR-007` decision 1 — uniqueness is namespace-scoped. `ADR-007` decision 2 — derivation input becomes `(namespace, identifier)`. ## Open question **What is the namespace boundary in practice?** Candidates: a fleet instance (`railiance01`), a client deployment, or an FOS autonomous domain. FOS's -recursion ("from projects to companies to foundation-like umbrella structures") -suggests namespaces nest, which would make qualification relative rather than -absolute. Settle before implementation; the notation works either way. +recursion — "from projects to companies to foundation-like umbrella structures" — +suggests namespaces **nest**, which would make qualification relative rather than +absolute, closer to DNS than to a flat handle. The notation survives either +answer, so implementation is not blocked, but the data model is unfinished until +it is settled. ## References @@ -167,6 +279,9 @@ absolute. Settle before implementation; the notation works either way. escalation, sovereignty by default, rebuildability - ADR-001 — workplans originate as repo files - ADR-007 — identifier uniqueness and derived identifiers (amended here) +- ADR-008 — Multi-Tenancy Framework; source of the plane/ladder/posture form and + the accuracy-not-altitude conformance rule - ADR-010 — hub authority, local cache, and the two kinds of hub data - `CUST-WP-0058` — instance-per-client tenancy - `SHR-INV-0001` — 425-item disposition inventory, T3 cost evidence +- `RMGR-WP-0004-T02` — `rmgr conform`, the guard machinery