Recursive Level Chains and Domain Co-Tenancy — Relative Levels and Multi-Chain Hosting

Accepted

ontoref
ADR-012 introduced a domain extension system; ADR-018 formalized a three-level hierarchy (base, domain, instance) with an absolute level.index in {1,2,3} and a single-valued level.parent declared in ma

Context

ADR-012 introduced a domain extension system; ADR-018 formalized a three-level hierarchy (base, domain, instance) with an absolute level.index in {1,2,3} and a single-valued level.parent declared in manifest.ncl. ADR-020 plus the qa entry ontoref-three-layer-model describe three CONTENT layers (Layer 1 self-management, Layer 2 integration surface, Layer 3 caller-side wiring) and flag (bl-009) the unresolved interaction with ADR-018's levels as a '3-layer x 3-level matrix, likely orthogonal but unresolved until the ADR drafts'. A third field case forces resolution. Rustelo builds a domain over a Torred domain over ontoref-base, and Rustelo's implementation mode produces website instances; those website instances are then hosted inside a Provisioning workspace, itself the terminal instance of Provisioning's own provisioning-domain chain. Two facts break ADR-018's absolute triad. (1) DEPTH > 3: the specialization chain base -> Torred -> Rustelo -> website-mode -> website-instance is depth 4-5, but level.index is capped at 3 with fixed semantic names. (2) DOMAIN CO-TENANCY: a single hosting repo (Provisioning) participates in two distinct chains from two distinct projects at once, and one chain's terminal instance re-hosts another chain's instance (instance-as-host). ADR-018's level.parent is single-valued and manifest.ncl declares exactly one level — neither expresses depth > 3, co-residency of chains, nor instance-as-host. The genuinely hard part — cross-project reference — is already designed: ADR-018 makes level.parent a name reference (not a path), ADR-028 makes the ontology addressable independently of the project filesystem (verify by witness, not clone), and ADR-030 provides catalog discovery across projects. What is missing is the generalization of the level axis itself and an explicit declaration for hosting.

Decision

Generalize ADR-018's absolute triad into a relative parent chain and add a co-tenancy declaration, both opt-in and backward-compatible, via four mechanisms. (1) RELATIVE LEVEL CHAIN — level identity is the parent chain, not an absolute index. A manifest declares level.parent (a name reference, exactly as ADR-018) and an optional level.role label; level.index becomes a DERIVED depth (walk parents to a base) that is no longer capped at 3 and no longer authoritative. The names base/domain/instance are reinterpreted as ROLES in a sliding window of three relative to an observation point, not global coordinates. Existing index 1/2/3 declarations remain valid as the depth<=3 case; deeper chains simply keep walking. The terminal node of one chain may itself be the parent-root of another (instance-as-host is a well-formed shape, not an error). (2) DOMAIN CO-TENANCY — a repo may declare manifest.ncl::hosts, an array of { chain (name reference to a foreign domain artifact), mount (where in this repo the hosted chain's Layer-3 wiring lives), digest (optional witness pin) }. The foreign chain is resolved by name through catalog discovery (ADR-030) and verified by witness (ADR-028), NEVER cloned. The host carries only Layer-3 wiring for the hosted chain (ADR-020), tagged layer-3-boundary. (3) MUTATION SOVEREIGNTY UNDER CO-TENANCY — a host's runtime MUST NOT mutate the authoritative state of any hosted chain. Hosting is placement plus wiring; each chain's authoritative state mutates only through its own declared operations with its own witness (ADR-024). Co-tenancy is co-residency of wiring, not transfer of state ownership. (4) OBSERVABLE CROSS-CHAIN RESOLUTION — ontoref mode resolve extends to report the full traversal PATH (every level visited, not a single hop) and the CHAIN SCOPE (which chain answered) when multiple chains are co-resident; ontoref describe state disambiguates FSM dimensions by chain scope. No cross-chain resolution is silent.

Constraints

  • Hard Every manifest.ncl::hosts entry must name a foreign chain resolvable by catalog discovery (name, optional digest) — resolution is by witness, never by clone
  • Hard A host must not declare operations that mutate a hosted chain's authoritative state; hosted state mutates only through the hosted chain's own declared operations
  • Hard Every level.parent chain must terminate at a base (a node with no parent); an unresolvable or cyclic parent reference is an error
  • Soft Wiring under a hosts mount should be tagged layer-3-boundary; untagged hosted wiring is a Soft warning
  • Soft When level.index is declared explicitly it must equal the derived parent-walk depth; a mismatch is a Soft warning during the transition to derived indices

Alternatives considered

  • Keep ADR-018's absolute index and cap depth at 3rejected: The Rustelo chain is already depth 4-5. Capping forces artificial flattening that hides real specialization boundaries — the exact invisibility ADR-018 set out to eliminate. A depth cap turns a true parent/child relation into a lossy projection.
  • Allow depth > 3 but forbid co-tenancy (one chain per repo)rejected: Provisioning hosting a website inside a workspace is an actual deployment shape, not a hypothetical. Forbidding co-residency pushes the hosting wiring into untyped, untagged territory, producing exactly the Layer-3-in-Layer-1 contamination ADR-020 warns against. The relationship exists whether or not the model can name it; refusing to name it loses the boundary check.
  • Let the host own the hosted chain's state (single runtime per repo)rejected: Collapses ADR-024 internal-coherence-enforced. The hosted chain's validators and witness would be bypassed by the host runtime, making cross-domain mutation unverifiable and reintroducing the unwitnessed-mutation hazard the operations layer exists to close.
  • Model co-tenancy as ordinary Layer-3 with no manifest declarationrejected: Layer-3 wiring does live in the caller, but the hosting RELATIONSHIP (which foreign chain, pinned to which digest) is then implicit. The boundary cannot be validated, and the witness pin (ADR-028) has nowhere to live. An explicit hosts array is the minimal addition that makes the relationship checkable.

Anti-patterns

  • Host Owns Hosted State — A hosting repo's runtime mutates the authoritative state of a chain it merely hosts, treating co-residency as ownership. The hosted chain's validators and witness are bypassed; cross-domain mutation becomes unverifiable.
  • Absolute Level Flattening — Forcing a chain deeper than three into the absolute base/domain/instance triad by collapsing real specialization steps, so distinct boundaries become invisible.
  • Implicit Hosting — A repo hosts a foreign chain's Layer-3 wiring without declaring manifest.ncl::hosts, so the hosting relationship, the foreign chain identity, and the witness pin are invisible and unverifiable.

Related ADRs

ADR-012 · ADR-018 · ADR-020 · ADR-024 · ADR-028 · ADR-030

Was this useful? Rate it
Got something to add? Tell me what you think, what you'd suggest, or whether we should keep exploring this topic.
· reads

We use cookies to help this site function, understand service usage, and support marketing efforts. Cookie Policy for more info.