Compare commits

...

5 commits

Author SHA1 Message Date
codex
77e0ac2bca docs(canon): correct ADR-007 second-instance attribution
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
custodian-sync@railiance.local is a hardcoded default git identity in
consistency_check.py, not proof of which machine synced. The real evidence
is the timezone split (+0000 and +0200) across sync commits.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-17 10:19:03 +02:00
codex
dd65c91b4f docs(canon): ADR-007 accepted — deterministic hub IDs (C2) with single-writer interim
Decision 2 reframed: the defect is a database-local key stored in a shared
artifact, which also inverts ADR-001. Target is UUIDv5 derived from the
globally unique PREFIX-WP-NNNN, making writeback idempotent across any
number of hub instances. Prerequisite: decision 1 uniqueness must be
enforced first, or derivation from PRJ-WP- style collisions manufactures
duplicate UUIDs.

Interim: one writer only, the automated production instance. Rejected:
collapsing to a shared database, which kills offline capability against
STATE-WP-0068. Both land in repo-manager per 747011c6.

Migration scope: 758 workplan files carry these fields. Remediation of the
3 shared prefixes and 5 duplicated identifiers stays an open ruling.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-17 10:17:58 +02:00
codex
4565bef819 docs(canon): ADR-006 accepted — R7 places evidence pair in dedicated itc-evid
Evidence, Evidence Source, Adjudication Outcome and the general
evidence-strength dimension get a dedicated InfoTechCanon model, imported by
itc-gov, itc-ident and commerce-canon. Three named consumers predate the
model, which is the required demand signal.

itc-gov stops owning Evidence and becomes an importer; it retains
AssuranceCase, AssuranceConclusion, Audit and the Policy-Control-Evidence
pattern expressed over imported concepts.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-17 10:03:15 +02:00
codex
183dd35467 docs(canon): resolve ADR-006 ownership questions R1-R6
R1 Scope -> itc-ident (itc-access keeps narrower ResourceScope).
R2 Assurance Level -> itc-ident, distinct from governance AssuranceCase.
R3 Evidence + Evidence Source are a general pair (container vs extracted
   assertion), owned together, not by commerce; itc-gov no longer owns
   Evidence.
R4 Relationship Tuple -> itc-access (already modelled there).
R5 Adjudication Outcome follows R3; general, not commerce-owned.
   assurance_tier splits: general strength dimension vs commerce's named
   Counterparty Assurance Gradient.
R6 Community + Household extend itc-org CollectiveActor; Family rejected as
   a collective actor and given its own seeded concept area.

One open question remains: the home for the evidence pair (dedicated
itc-evid model vs itc-gov incumbency). Recommendation: dedicated model.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-17 09:46:19 +02:00
codex
81cdce4173 docs(canon): ADR-007 workplan identity, single registrar, worker topology (proposed)
Globally unique PREFIX-WP-NNNN; one prefix per repo; forward-only running
numbers; prefixes never derived from flavor markers. Exactly one registrar
mints hub IDs into git-tracked files. Automated normalization may not
promote proposed to active. Repo manipulation defaults to a worker agent in
that repo; prj- repos may act across their declared participants.

Fleet scan of 955 workplans found 3 shared prefixes and 5 duplicated
identifiers. Migration of existing collisions deliberately left for a
separate ruling.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-16 18:54:39 +02:00
2 changed files with 318 additions and 22 deletions

View file

@ -2,9 +2,10 @@
id: ADR-006
type: architecture-decision-record
title: "Canon Federation and Concept Ownership Across InfoTech and Commerce"
status: proposed
status: accepted
decided_by: Bernd Worsch
date: "2026-08-16"
accepted: "2026-08-17"
tags: ["architecture", "canon", "concept-ownership", "info-tech-canon", "commerce-canon", "identity", "orthogonality"]
---
@ -12,8 +13,8 @@ tags: ["architecture", "canon", "concept-ownership", "info-tech-canon", "commerc
## Status
Proposed. Canon changes are review-gated; this ADR is the review artifact for
the identity/commerce split and must be accepted before content moves.
Accepted 2026-08-17. All seven ownership questions are resolved (see
Resolutions); content may now move under `CFED-WP-0001`.
## Context
@ -114,10 +115,13 @@ than identity-owned definitions.
`Customer` · `Vendor` · `Commercial Relationship` · `Commercial Commitment` ·
`Payment Instrument Reference` · `Payment Mandate` · `Pipeline Pursuit` ·
`Commercial Record` · `Counterparty Assurance Gradient` · `Reputation Signal` ·
`Performance Evidence` · `Adjudication Outcome` · `Registry Identifier` ·
`Performance Evidence` · `Registry Identifier` ·
`Proxy Commercial Identifier` · convenience terms `Reputation`,
`Customer Account`
*Owned by `itc-evid`, the evidence model (see R3, R5, R7):*
`Evidence` · `Evidence Source` · `Adjudication Outcome`
Identifier subtypes demonstrate the intended pattern: `itc-ident` owns
`Identifier`; `commerce-canon` owns `Registry Identifier` and `Proxy Commercial
Identifier` as specializations of it.
@ -133,26 +137,112 @@ the canon does not push.
organizational architecture, human-gated — not commercial vocabulary. If it ever
moves, it becomes an InfoTechCanon organization standard, not a CommerceCanon one.
## Open questions
## Resolutions
These are unresolved collisions that must be settled before the affected
concepts move. They are deliberately listed rather than silently decided.
The six collisions listed at draft time, resolved 2026-08-17. Two were settled
by evidence already present in the models rather than by argument.
1. **`Scope`.** identity-canon P3 makes it first-class; `itc-access` uses "access
scope" throughout. Does `itc-ident` own `Scope` with `itc-access` importing,
or the reverse?
2. **`Assurance Level` vs `itc-gov` `Assurance`.** Specialization or distinct
concept? `Counterparty Assurance Gradient` builds on whichever wins.
3. **`Evidence Source` vs `itc-gov` `Evidence`.** Likely an `itc-gov`
specialization rather than an identity-owned concept.
4. **`Relationship Tuple`.** A Zanzibar/OpenFGA-style authorization primitive —
plausibly `itc-access`, not `itc-ident`.
5. **`Adjudication Outcome` vs `itc-access` `AuthorizationDecision` and `itc-gov`
`Decision`.** Three candidate owners.
6. **`Community`, `Family Or Household`.** Social collectives absent from
`itc-org`, which covers enterprise structures (`Team`, `Group`,
`OrganizationalUnit`). Recommend extending `itc-org` rather than placing them
in `itc-ident`.
**R1 — `Scope`: owned by `itc-ident`.** There is no head-on collision:
`itc-access` owns `ResourceScope` (`:717`, "the boundary within which access
applies"), a narrower concept, not a general `Scope`. `itc-ident` owns the
general concept, keeping it with `Tenant` and `Realm` — `Tenant` is defined as
"an administrative or isolation scope", so separating it from its genus would
split a definition from the concept it depends on. `itc-access` keeps
`ResourceScope` as a refinement.
If `landscape` or `information-space` later need general scoping, promote
`Scope` to the kernel **on that demand signal**, not pre-emptively.
**R2 — `Assurance Level`: owned by `itc-ident`, distinct from governance
assurance.** A false collision. `itc-gov` owns `AssuranceCase` (`:1178`, a
structured argument that a claim is justified) and `AssuranceConclusion`
(`:1184`). identity's `Assurance Level` is NIST SP 800-63-4 IAL/AAL/FAL —
graded confidence metadata on credentials, bindings, and federation assertions.
They share an English word and nothing else. Both models carry a disambiguation
note, because the word will keep causing this.
Design principle P12 ("Distinguish Assurance Dimensions") carries over: IAL,
AAL, and FAL must not be collapsed into a single "trust level" on an account.
**R3 — `Evidence` and `Evidence Source` are a general pair, owned together, and
not by commerce.** They are not competing definitions of one concept:
- **Evidence Source** — an addressable information container: a document, file,
or other artifact identifiable by URI.
- **Evidence** — a distinct information item, textual or descriptive, drawn from
a source: a quotation, an extracted value, a specific assertion.
Both may carry commentary. Which evidence is captured from a source depends on
the interest being served.
Worked example: an invoice PDF is an Evidence Source; the amount, the issuer,
and the due date are separate Evidence items within it. The common electronic-
invoicing pattern of an XML embedding inside a signed PDF is exactly this
structure — evidence pre-extracted and bound to its source so the extraction is
itself tamper-evident.
The pair is domain-neutral (it extends to criminal, regulatory, and scientific
evidence). Commerce, identity, and governance all **use** it; none owns it.
Consequently `itc-gov` no longer owns `Evidence`; it imports it.
**R4 — `Relationship Tuple`: owned by `itc-access`.** Already modelled there
(`:549`, under `PolicyEvaluationEntity` beside `AuthorizationRequest`,
`AuthorizationDecision`, `DecisionReason`, `EvaluationContext`). identity-canon's
own entry agrees: "Relationship tuples are not canonical identity roots. They
project from actors, accounts, memberships, and delegations into authorization
domains." `itc-ident` must not define it.
**R5 — `Adjudication Outcome`: follows R3, owned with the evidence pair.** Not
`itc-access` `AuthorizationDecision` (a PDP allow/deny, `:907`) and not `itc-gov`
`Decision` (a governance choice point). The concept is general rather than
commercial: an arbitration award, court judgment, or regulatory consent order is
evidence in employment, licensing, or compliance disputes as much as in
commercial ones. Commerce is a consumer, not the owner.
Structurally it is **Evidence** — the outcome asserted — sourced from an
Evidence Source such as the judgment document.
The `assurance_tier` dimension splits accordingly: the evidence model owns a
general evidence-strength dimension; `commerce-canon` owns the
`Counterparty Assurance Gradient` as its named four-tier application of it.
**R6 — `Community` and `Household` extend `itc-org`; `Family` is a separate
concept area.** identity-canon defines "Family Or Household" as one entry. That
conflation is rejected.
`Community` and `Household` are collective actors and slot under `itc-org`'s
existing `CollectiveActor` (`:363`, beside `Person`, `HumanActor`,
`NonHumanActor`), honouring P4 ("Model Collective Actors Without Collapsing
Them").
`Family` does not. Family carries substantial structure — kinship, guardianship,
dependency, care, and legal, biological, and social parenthood — which changes
over time and is subject to interpretation. Modelling it as one more collective
actor is the specific mistake most family-oriented software makes, and it is why
such software generally models families badly. It gets its own concept area.
Scope discipline applies: the family area is **seeded, not authored**. Record the
concept, the privacy sensitivity already flagged in identity-canon ("may have
legal implications outside the canon's scope"), and the open modelling
questions. Do not build it out inside `CFED-WP-0001`; it grows on demand signal
like any other canon content.
**R7 — the evidence pair lives in a dedicated model, `itc-evid`.** A new
InfoTechCanon model at `infospace/models/evidence/` owns `Evidence`,
`Evidence Source`, `Adjudication Outcome`, and the general evidence-strength
dimension.
`itc-gov`, `itc-ident`, and `commerce-canon` import it. Three named consumers
existed before the model did, which is the demand signal the canon requires.
Rejected alternative: leaving both with `itc-gov` as incumbent owner of
`Evidence`. That is cheaper and preserves the locality of the
Policy-Control-Evidence chain pattern (`:1391`), but it would force identity and
commerce to import "governance" in order to describe an invoice line item —
mis-signalling evidence as a governance sub-topic when it is domain-neutral.
`itc-gov` retains `AssuranceCase`, `AssuranceConclusion`, `Audit`, and the
Policy-Control-Evidence pattern, now expressed over imported evidence concepts.
## Consequences

View file

@ -0,0 +1,206 @@
---
id: ADR-007
type: architecture-decision-record
title: "Workplan Identity Uniqueness, Single Registrar, and Repo Worker Topology"
status: accepted
decided_by: Bernd Worsch
date: "2026-08-16"
accepted: "2026-08-17"
tags: ["architecture", "workplans", "identity", "state-hub", "repo-manager", "agents", "registrar"]
---
# 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:**
```text
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:**
```text
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.
- 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 globally unique `PREFIX-WP-NNNN`
identifier. 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. The interim
registrar is the automated production instance; workstation hubs are development
read replicas.
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.
**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:
1. **Freeze and forward-fix.** Accept existing collisions as historical, enforce
uniqueness only for new workplans. Cheapest; leaves `RAILIANCE-WP-0015`
permanently ambiguous.
2. **Renumber the live collisions only.** Fix identifiers that are still cited or
active; leave `finished`/`archived` duplicates alone.
3. **Full renaming.** Give `railiance-apps`, `railiance-forge`,
`railiance-platform`, `railiance-telemetry` distinct prefixes, likewise
`railiance-bootstrap`/`railiance-cluster` and `state-hub`'s legacy `CUST-WP-`
files. Touches six repositories and every inbound reference.
Recommendation: **option 2**, with option 3's prefix split applied only to repos
that are still creating new workplans under a shared prefix — a shared prefix
that is still growing keeps generating new collisions, while a dormant one does
not.
All five duplicated identifiers are currently `finished`, so no active work is
blocked by deferring this.
## 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 scaffolding
- `STATE-WP-0080` — register scaffolding handoff
- Fleet scan 2026-08-16: 955 hub workplans, 525 parseable identifiers,
3 reused prefixes, 5 reused identifiers