Discovered before implementation: discard-and-rebuild cannot exist. Progress
events, tasks, decisions and review contracts reference workplans with ON DELETE
RESTRICT, and 1067 of 1075 workplans carry such a reference. Deleting a workplan
would delete the hub-native records attached to it, which ADR-010 decision 4
forbids and the schema refuses.
The database is enforcing this ADR's own boundary one layer down. A progress
event is a fact that happened; destroying it to tidy a derived projection loses
hub-native truth to fix a derived-state problem.
Reset now reconciles: create what is missing, update what differs, retire what no
longer derives — and retirement must be visible rather than silent.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
ADR-012 accepted 2026-08-25.
ADR-010 — partially superseded, notes added inline:
decision 1: "a reading of the repositories" never said which copy, and the
answer was neither the forge nor a working copy but whichever checkout last
synced. The hub holds no repository files and never reads one.
decision 5: "central derives, does not accept pushes" was policy while the
workstation pushed everything.
decision 6: "preliminary" was named but never built.
ADR-003 — partially superseded:
decision 2: fingerprints composed from filesystem mtime are invalidated in
part. mtime is a property of one workstation, differs across clones, and
says nothing about content. Evidence: git_fingerprint for the-custodian
held the initial commit while last_state_synced_at was minutes old.
decision 5: the rebuild principle was correct but never exercised, and its
"without data loss" claim holds only while nothing exists solely in the hub
— which was false for 111 records on 2026-08-25.
ADR-001, ADR-005, ADR-007 and ADR-011 reviewed and unaffected; ADR-007 is
reinforced, since derived identifiers let an overlay and a forge-derived
projection compute the same identity.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Refines decision 7. Per-repository rebuild is not a convenience over a
fleet-wide operation: the repository is the unit, and the fleet-wide form is
defined as iteration over it.
It follows from the source — each forge repository has its own history and head,
so its projection is derivable and provable in isolation. It bounds blast radius,
which is what makes "routine" achievable: a rebuild that only runs fleet-wide is
one nobody runs casually and therefore nobody runs, which is how ADR-010's
never-executed reconstruction claim came to be believed.
It is also the only form that composes with the refusals. A repository holding
projection-only records can be held back while healthy ones rebuild; an
all-or-nothing reset is blocked permanently by a single bad repository. The
refusal is therefore evaluated per repository, and a fleet run skips and reports
rather than aborting.
The fleet-wide form must share the per-repository implementation, so the rare
dangerous path is exercised by the common safe one.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Adds decision 7: the projection must be discardable and rebuildable from what
Forgejo holds, per repository and fleet-wide.
This is what makes the other decisions checkable. A read model that cannot be
rebuilt from its source is a database with a projection's reputation, and the
difference only surfaces when someone needs to rebuild it. ADR-010 already
asserts a cache may be reconstructed at any time; that claim has never been
executed.
Three properties keep it real: routine rather than emergency, scoped per
repository, and idempotent enough to verify against the forge — which derived
identifiers make possible.
Two refusals are explicit. Reset cannot restore the preliminary overlay, since
the forge does not hold it. And reset must refuse when records exist only in
the projection: on 2026-08-25 that was 111 work records, which a rebuild would
have erased while reporting success.
Also flags an unresolved boundary: hub-native records are not forge-derived and
must survive a rebuild of forge-derived state.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
ADR-001 and ADR-010 both leave unanswered which repository files the hub reads.
Verified 2026-08-25: neither the forge nor a working copy — the projection
derives from whichever checkout most recently ran the sync, which is written
down nowhere.
Proposes the forge as projection source, unpushed local work as a labelled
preliminary overlay rather than a second store, and commit provenance on every
record. Implements ADR-010 decision 6's unbuilt notion of "preliminary" and
sharpens decision 1 rather than reversing it.
Status: proposed — needs review before anything is built on it.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Three dated corrections, following the blockquote convention ADR-007 uses:
- Decision 2's merge/refresh dichotomy is not exhaustive. Repository records
took a third shape — cache-only records whose source exists and is reachable
but was never introduced to central. Refreshing would have destroyed them.
- The Context recorded the shared port but not why it was silent: an unbound
ssh -L binds every loopback family, and ExitOnForwardFailure fires only when
every bind fails.
- A new Outcome section states that the ADR's own remediation never landed and
the condition was still live seven weeks later.
Refs CUST-WP-0067-T06
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
ADR-011 decision 7 keys derivation on (namespace, identifier), which
separates forks but not collisions inside one namespace. The ecosystem is at
N1, a single implied namespace, and a 2026-08-21 fleet scan finds 20 reused
identifiers across 48 files all inside it. So ADR-011 alone does not satisfy
decision 2's uniqueness prerequisite.
Ruled: C2 derives for live records only; archived records keep frozen minted
identifiers. This reconciles Migration option 2 with the uniqueness
derivation needs, and cuts the remediation surface from 48 files to 11.
Records the two consequences that follow -- un-archiving is a collision
hazard, and derivation is not retroactive -- and why treating a repository as
the namespace was rejected.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Reworks federation from binary rules into the plane/ladder/posture form from
ADR-008 (Four Planes), reusing its vocabulary rather than adding a second
maturity language to the canon.
Four planes: Namespace, Autonomy, Reconciliation, Substrate, each with a
ladder. Draft-1's 'records fork, effects do not' becomes the S ladder.
Posture is declared in the repo per ADR-010 decision 4; the ecosystem's own
posture is recorded honestly as N1 U1 R1 S1.
Key additions: conformance is accuracy not altitude; an anti-overclaim rule
stating that namespace qualification is N-plane movement only and does not
make anything federation-capable, with a commercial clause for
instance-per-client claims; the reconciliation tier is now DERIVED from
participants' postures (any S3 entails T3), so rejoining cost is computable
before a fork exists rather than discovered during reconciliation; evidence
definitions per level; and guard via rmgr conform.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Multi-tenancy is part of the IT-security framework NetKingdom provides, so it
belongs beside the IAM Profile and the tenant-engine boundary contract rather
than in the work-factory canon. Operator decision.
Relocation surfaced two things a review would have caught embarrassingly late.
NetKingdom's accepted platform-identity-security-architecture has used the word
plane since July for a trust and deployment layer - bootstrap, platform
control, tenant. This framework was using the same word for an independent
dimension of concern. Two senses of one word in one canon is precisely the
concept-ownership collision the estate is careful about, and the newcomer
yields: they are now axes. The rename is also just better, since a posture
vector is a point in five-dimensional space.
That same document also disproves the framework's opening line. It has
described the trust model, the tenant model and a capability progression since
2026-07-23, so the claim that the estate had never written down what it was
building was wrong. The accurate and narrower claim is that nothing said how
far a given service had got, or could hold several answers at once.
Stub left behind so the ADR-008 identifier resolves. The renderer moved to
policy-nexus, which owns publication.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The page and the ADR had already diverged once. They are now one source: the
markdown is authoritative and the page is generated, never hand-edited.
The renderer recognises conventions the document already uses rather than
requiring extra markup, so the source stays a readable document. A table whose
first column is **X0**/**X1** becomes a level ladder; a table headed Threat
becomes the threat matrix; a table with a Kind column gets mechanical and
adversarial chips; a table headed "E \ P" becomes the two-axis grid; ## N.
headings build the section rail.
Stdlib only, per the structure-not-tooling stance. A publishing step that needs
its own toolchain is a publishing step that stops being run - the same
reasoning tenant-engine used for its pin check.
One real consequence beyond deduplication: the E x P matrix had existed only on
the page, so the canonical document did not contain its own central diagram.
It is now a table in the markdown, which is where it should always have been.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
R4 now has a mechanism. It splits into horizon-elapsed (wait out a window
somebody else's retention set - available to all, proves little) and
key-destroyed (encrypt per entity, destroy the key, immediate). A service must
name which route it uses.
The regulatory position is stated rather than implied: DPAs have accepted key
destruction as erasure where physical deletion is disproportionate, under
conditions, and the EDPB has not formally endorsed it. Section 11.4 now says a
service may make that claim but not in language implying a regulator blessed
it. Overclaiming here would be worse than anywhere else in the document.
Third coupling recorded: shredding a single tenant's data needs the application
to encrypt under a per-tenant key before writing, so the top of the retention
ladder is an enforcement-plane capability. Reaching R4 is not a retention
project.
The noisy-neighbour artifact was replaced. It had required proof that a
saturating consumer does not breach another's allowance, which shared
infrastructure cannot provide - an artifact that can only fail, or passes by
being run gently, is an overclaim in the costume of evidence. It now measures:
baseline, saturation run, proof the controls bind, recorded degradation.
Generalised as decision 13.4.
The connection ceiling is reframed. Seven consumers each politely inside a
14-connection allowance still exhaust the instance, so the number is the
aggregate noisy-neighbour bound, and our per-consumer governance guards the
other shape entirely.
Also: quota transparency as a disclosure obligation (10.2) - a consumer
learning its statement timeout by hitting it in production is our failure, not
theirs; and two new open questions - crypto-shredding an audit trail destroys
what audit-core exists to hold, and we have no QoS vocabulary despite a
latency-critical consumer sharing an instance with a batch one.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Renamed to Tenancy Posture. Four Planes stopped being true and a name that
encodes a count breaks every time the framework grows; the posture vector is
the durable centre.
Corrections from the research digests:
- E3 no longer claims the application cannot route around it. Any session can
re-SET the GUC, so E3 is decisive against a forgotten predicate and useless
against SQL injection or a compromised process. Replaced the claim with a
threat-model table. Draft-2 was overclaiming in exactly the way section 6
prohibits, which is the correction I most wanted made before review.
- E3 layers on E2 rather than replacing it; claiming E3 now requires the E2
artifact too, because E3 alone fails open under injection.
- The GUC is set transaction-locally, not at pool checkout, and the scaling
section's pooling claim was backwards: SET LOCAL is what makes E3 safe under
a pooler; statement-level pooling is what leaks.
- Placement is a default plus per-tenant exceptions. One P level per service
could not express the isolation tiers section 11 already sells.
Added plane R for retention and erasure, implementing the rapp-postgres
ADR-0002 interface: N-day retention defaulting to 30, a published erasure
horizon, and dataset sweeps whose policy the consumer owns. R exists because
deleting a row does not remove it from yesterday's backup, and the estate had
never written that down.
Also: A4 for a standard PDP interface now that AuthZEN is Final; evidence split
into mechanical and adversarial, since a green CI run is not E2 evidence; the
tenant boundary named as OWASP API1; and section 14 recording the
structure-not-tooling stance.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
ADR-008 and ADR-009 were concurrently allocated by two authors on
2026-08-17. adr-008-multi-tenancy-model.md (Four Planes) has earlier
provenance and keeps 008; 009 is left free for that lane. Hub authority
becomes ADR-010, federated namespaces ADR-011. Cross-references in ADR-007
updated.
A live demonstration of ADR-007 decision 1's own subject: sequential
allocation with concurrent writers. ADR numbering is not covered by that
decision, which governs PREFIX-WP-NNNN only — gap to close.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Resolves a contradiction in accepted canon: ADR-007 decision 1's globally
unique forward-only running numbers require a central allocator, the exact
dependency federation must survive. Amended to namespace-scoped uniqueness
with PREFIX-WP-NNNN@namespace qualification; unqualified still means the
local namespace. C2's UUIDv5 derivation input becomes (namespace,
identifier) — free now, expensive after it ships.
States reconciliation limits rather than implying convergence. T0 fork, T1
sync and T2 reintegration are partly automatable; T3 amalgamation, where a
fork established distinct operational infrastructure, is an M&A-class
governed programme rather than a merge, and may legitimately end in
permanent coexistence or divestment. prj-state-hub-retirement is cited as
measured T3 cost under the most favourable possible conditions.
Coexistence, not merging, is the normal case: client instances per
CUST-WP-0058 are forks that never return. Records fork; effects do not.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Draft-1 proposed one model of multi-tenancy with fixed characteristics.
Rejected: the estate needs a framework that can hold several situations at
once, including repos that do not separate tenants rigorously today and must
be developed toward doing so.
What changed:
- Every plane now carries an ordered ladder (I0-I3, A0-A3, E0-E4, P0-P4),
not just placement. A service is a posture vector, not a verdict.
- D3 reversed. Draft-1 forbade RLS as a control that "looks like a database
guarantee without being one". The observation was right, the conclusion
wrong: RLS is E3, materially stronger than E2, and the actual error was
calling E3 by E4's name. Platform enforcement is now the direction of
travel and an obligation on the platform, not only on consumers.
- New governing rule: conformance is accuracy, not altitude. Declaring E0 is
conformant; concealing it is not. Overclaiming is the only violation.
- Fixed a flaw of draft-1's own making: R0 "shared tables, tenant column" was
an enforcement state mislabelled as placement. Removed; P ladder renumbered.
- Added methodology (analyze/establish/improve/guard) and per-level evidence
artifacts. Guarding checks a service against its own declaration, which is
what makes the verification problem tractable at all.
- D7 softened per operator: tiers carry minimum levels internally, marketing
language stays free, the constraint is on evidence not vocabulary. One hard
line kept: "another tenant cannot reach your data" requires E4.
Ratification now also tests the framework — each reviewing repo publishes its
posture vector, and if a repo cannot express itself in these ladders the
ladders are wrong, not the repo.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Central hub on railiance is authoritative as a reading of the repositories;
local instances become rebuildable caches, never peer databases. Local work
requires no hub at all — repo files are self-describing.
Classifies hub data by origin: file-derived (central derives, never accepts
pushes, conflicts are git conflicts) vs hub-native (central owns, needs a
write path and an append-only offline buffer). Neither kind needs a hub-side
conflict model.
Measured divergence: 955 local / 649 primary / 320 local-only, of which 288
are backed by files that all exist on disk. Only 28 orphans need
disposition, and they are the ADR-001 violations.
Corrects ADR-007's 'development read replica' wording — the workstation
instance was the larger of the two by 306 workplans.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The estate has built multi-tenancy across five documents that each cover a
slice and do not compose. This records the whole model and names what is
missing.
Core framing: multi-tenancy here is four orthogonal planes — identity,
authorization, data isolation, placement — not one property. Identity and
authorization are ratified and solid. Data isolation is stated but
unverified. Placement is owned by nobody and is precedent-by-accident.
Three findings that motivated the draft:
- R0 -> R1 -> R2 does not improve tenant isolation at all. Those rungs buy
consumer isolation and capacity. Only R3 makes the tenant boundary
structural. A plan tier selling R2 as isolation would be false.
- No fleet mechanism verifies that any consumer actually enforces the tenant
boundary it is obliged to enforce. A missing WHERE tenant_id would be a
cross-tenant breach that no probe fails and no log shows as an error.
Highest-severity gap; needs an appointed owner.
- platform-pg holds roughly six consumers (100 max_connections, 14 each) and
memory likely binds before connections do. Two are provisioned. The runway
is shorter than the ladder implies.
Also reconciles two already-ratified and contradictory defaults:
instance-per-client for business apps, pooled for platform services, with no
rule for telling a new service which it is.
Proposed, not ratified. Carries a ratification path so it does not join the
shared-platform-relational-storage draft in limbo.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Neither repo keeps the shared prefix. railiance-cluster switches active and
future plans (0007 backlog, 0014 ready) to RCLUSTER-WP- preserving running
numbers; railiance-bootstrap takes RBS-WP- starting at 0010, above its
historical maximum, so its finished plans could be adopted later without
collision. Finished files keep RAIL-BS-WP- per the option 2 ruling.
RAILIANCE-WP- should be retired the same way rather than awarded to one
repo; successor prefixes still outstanding.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Verified: all five duplicated identifiers are finished, and no workplan in a
live state shares an identifier. Option 2 therefore requires no renumbering
today; historical duplicates stay, RAILIANCE-WP-0015 ambiguity included.
Separates remediation from conformance: three shared prefixes remain in use
across seven repos as single concurrently-allocated number lines. RAIL-BS-
and RAILIANCE- are still growing, so the 0015/0016 collisions will recur at
the next concurrent allocation. Prefix ownership assignment tracked as
RMGR-WP-0004-T09 under decision 1, which option 2 does not exempt.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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>
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>
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>
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>
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>
Proposes three federated canons (Custodian, InfoTech, Commerce) with
declared concept ownership. Renames identity-canon to commerce-canon in
place; identity content emigrates to a new InfoTechCanon model.
Assigns all ~60 identity-canon glossary concepts to exactly one owner and
lists six unresolved collisions as open questions rather than deciding
them silently.
Status is proposed — canon changes are review-gated.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Publish project-repository-flavor_v0.1 with naming, GOAL.md (not durable
INTENT.md), authority boundary, lifecycle, residuals, and archive rules.
Close ADR-005 deferred naming and CUST-WP-0050 D1a; cross-link from the
repo classification standard.
Canon work-record-types: residuals use intake/workplan/decision with
origin residual|handoff and origin_ref parent WP. Schema origin_ref;
agent close protocol aligned.
Standalone-app shape, instance-per-client tenancy with consolidation-ready
data model (DR-1 C), app-local identity with bounded auth module (DR-3 A),
build/release evidence, ops-hub and fin-hub obligations, data-protection
baseline. Applies to client apps and Binky Hedgehog's own apps alike
(DR-2 B client-#1 model). Awaits canon review.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Mark T16/T17 done with cutover evidence and decision coupling doc
- Add business-model-canvas and bootstrap-protocol canon (T20/T21)
- Record Core Hub readiness-summary evidence stubs
- Refresh fos-hub-bootstrap-sequence-status and core-hub-replacement-evidence
Documents the three-machine role model, fleet mesh topology, coulombcore
freeze policy, and ordered drain sequence. Adds railiance01 systemd tunnel
install assets and refreshes ops service inventory to reflect 2026-07-03
production placement (cluster State Hub, fleet mesh, draining coulombcore).
Add human-review script for 13 high-blast-radius repos, bulk-push helper,
and SSH-based Gitea inventory probe. Update exclusion list with SSH-verified
absent slugs; marki-docx now classified and registered.
Add exclusion list and batch classification author for post-cutover inventory.
Mark workplan finished after registering 7 new repos and reclassifying 43
migration rows via state-hub register-from-classification tooling.
Insert a 'tooling' category between project and product (reusable internal
tooling/infrastructure: libraries, CLIs, services, ops components used across
the ecosystem rather than offered to external customers). Update §5 definition,
§11 decision procedure, §16 agent prompt, the machine-readable allowed-values,
and the CUST-WP-0050 T02 progress note. Nine custodian tooling repos
reclassified to it; the-custodian and inter-hub remain research.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>