Tier Transition Substrate Effects — Deferred Scope from ADR-033

Accepted

ontoref
ADR-033 (Tier Transition Mechanism) enumerated a six-effect catalog per

Context

ADR-033 (Tier Transition Mechanism) enumerated a six-effect catalog per transition direction. ADR-033 §FULL EFFECTS implemented exactly one of those effects: the atomic config file replace (the last step of every direction). The other fifteen effects — oplog bootstrap, commit_layer initialization, state_root computation, daemon registry mutation, Ed25519 keypair generation, catalog verification, daemon registry de-registration, and tier-descent witness emission — were deferred because they require coordinated implementation across the workspace substrate crates (`ontoref-oplog`, `ontoref-commit`, `ontoref-ops`), which were still being built out — not because of any external dependency. The oplog is redb-backed and lives entirely in the workspace; no stratumiops crate is required to persist the witness chain.

The Hard constraints `downgrade-preserves-substrate-immutable` and `tier-2-descent-emits-final-witness` from ADR-033 are documented as DEFERRED in the tier_transition module preamble. This ADR is that follow-up.

CURRENT STATE ENTERING THIS DECISION

Tier transition declaratively works via three reachability paths (CLI, ConfigWatcher, catalogued op) that all converge on `ontoref_ops::tier_transition::execute`. The execute function mutates ONLY the config.ncl file atomically. No substrate is bootstrapped on upgrade; no witness is emitted on descent; no oplog is created.

Tier-2 today is therefore declarative-only — projects can declare `ops.tier = 'Tier2` and the protocol honours the declaration, but the ADR-024 promises of cryptographic provenance and replay- deterministic operation logs remain unfulfilled at runtime.

Decision

ACCEPTED. The substrate effects are implemented behind a `substrate` feature flag on ontoref-ops (default: off), coordinated across ontoref-ops (effect handlers), ontoref-oplog (redb-backed oplog persistence), and ontoref-commit (commit_layer / state_root). The oplog persistence backend is redb, in-workspace — NOT stratumiops stratum-db. This ADR fixes the scope and the binding constraints; the implementation is tracked as backlog item bl-014.

SHAPE OF THE NEXT SCOPE

Substrate effects will be implemented behind a `substrate` feature flag on ontoref-ops (default: off). When enabled, execute runs the full effect catalog; when disabled, only the atomic config rewrite runs — preserving ADR-029 offline-first-default-stack for tier-0 consumers.

Per-actor Ed25519 keys: generated on first Tier1→Tier2 transition, stored at ~/.config/ontoref/keys/<actor>.key (mode 0600), public key published in .ontoref/actors.ncl.

Oplog: append-only via ontoref-oplog (redb-backed, in-workspace), mirrored as NCL render output for human inspection.

Tier-descent witness: payload_kind = 'tier_descent', written as the last signed entry of the project's oplog before the config rewrite to a lower tier.

Compensating rollback: each substrate effect registers its undo into the transaction scope established by tier_transition::execute. On any failure, compensations run in reverse order. Failures are recorded in .ontoref/artifacts/transition-log/<ts>-failed.ncl (already implemented in ADR-033 §FULL EFFECTS).

Constraints

  • Hard Substrate effects (oplog bootstrap, Ed25519 keypair, witness emission) MUST be gated behind a `substrate` feature flag on ontoref-ops. Builds without the feature MUST still produce a working `tier_transition::execute` that performs the atomic config rewrite. Preserves ADR-029 offline-first-default-stack.
  • Hard When substrate is enabled and `tier_transition::execute` is invoked with old_tier=Tier2 AND new_tier!=Tier2, the function MUST emit a witness with payload_kind='tier_descent' to the project oplog before applying the config rewrite. Closes the deferred half of ADR-033 `tier-2-descent-emits-final-witness`.

Alternatives considered

  • Leave the gap as implicit Rust source TODOsrejected: Implicit TODOs are not queryable. ADR-031 on+re duality requires protocol gaps to live on the ontology axis. Cost of this ADR is small; cost of every consumer rediscovering the gap grows linearly with the consumer count.
  • Implement substrate effects directly in ADR-033 §FULL EFFECTS instead of splittingrejected: ADR-033 §FULL EFFECTS was a self-contained PR-sized scope: tier_transition module + tests + CLI surface + watcher + holder + handler. Including substrate would have ballooned the scope across multiple substrate crates and pushed the ship date indefinitely. Splitting lets ADR-033 ship its value (working ontoref tier set + guard + tests) immediately.
  • Persist the oplog via stratumiops stratum-dbrejected: An earlier draft of this ADR assumed stratum-db for oplog persistence. The implemented `ontoref-oplog` is redb-backed and self-contained in the workspace, enforcing signature + parent-existence + monotonic-HLC checks on every append. Using stratum-db would reintroduce an external path dependency for tier-2, contradicting ADR-001's minimal-adoption posture and ADR-029's offline-first default. redb keeps the witness chain dependency-free.

Related ADRs

ADR-023 · ADR-024 · ADR-029 · ADR-031 · ADR-033

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.