Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions .s5d/aliases.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -534,3 +534,21 @@ packages:
package_id: feat.s5d.self-update
owning_package: null
deprecated: false
- uuid: ec8a5081-8f37-48ac-a69a-4ea1aa36a53e
artifact_id: cap.ownership-derivation
artifact_type: Capability
package_id: feat.s5d.ownership-derivation
owning_package: null
deprecated: false
- uuid: 7982d3b1-4774-4128-ba80-65dbb00652e7
artifact_id: feat.s5d.ownership-derivation
artifact_type: Feature
package_id: feat.s5d.ownership-derivation
owning_package: null
deprecated: false
- uuid: cf86a094-f413-4eb0-9ede-46ad61623707
artifact_id: comp.ownership-derivation
artifact_type: Component
package_id: feat.s5d.ownership-derivation
owning_package: null
deprecated: false
1 change: 1 addition & 0 deletions .s5d/evidence/feat.s5d.ownership-derivation/graph_1.log
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
graph check passed (built-in)
1 change: 1 addition & 0 deletions .s5d/evidence/feat.s5d.ownership-derivation/schema_1.log
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
schema validation passed (built-in)
66 changes: 66 additions & 0 deletions .s5d/evidence/feat.s5d.ownership-derivation/tribunal-round1.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# Tribunal round 1 — Codex adversarial review (2026-06-12)

Scope: PR #13 diff (branch voroninr/ran-491-ownership-derivation vs main).
Reviewer ran: `git diff --check`, `cargo fmt --check`, `cargo clippy -D warnings`, `cargo test --all` — all passed.

## VERDICT: REJECT (both blockers confirmed by maintainer review and fixed in round 2)

### Blocking 1 — derivation not anchored to imported content
`derive_global_owners` applied CURRENT package files to HISTORICAL ledger entries,
ignoring `LedgerEntry.spec_sha256`. A backdated package edit could fabricate a
false owner mismatch and veto a legitimate rollback.

**Fix:** per-entry sha gating. An import/reconcile entry contributes claims only
when the current file's sha256 matches the entry. A mismatching/missing file
poisons every key unowned at that replay point (→ `Unverifiable`), cleared only
by that package's own rollback entry. Unverifiable never routes to the
destructive fallback — a two-file tamper (alias field + any package file) must
not be able to downgrade the veto into a tombstone. Pinned by
`rollback_skips_tombstoning_when_ownership_unverifiable`.

### Blocking 2 — rollback epochs ignored
`AliasTable::resolve` is first-creator-wins **within the active epoch** (rollback
tombstones the entry; the next import creates a fresh one with a new owner). The
original replay derived "first ever importer" and would false-flag the legitimate
second-epoch owner on an untampered repo (A imports X → A rolled back → B imports
X → B rollback vetoed).

**Fix:** the replay releases a package's ownerships (and its poison entries) when
its ledger `rollback` entry is seen. Pinned by
`rollback_after_reimport_does_not_false_flag_new_owner`.

### Non-blocking notes (accepted)
- Fingerprint untouched — confirmed.
- Tombstoning still gated by stored claim — derivation never expands destruction.
- CLI/MCP mutation order centralized, matches old shape.
- Remaining test-gap notes (MCP warning parity, reconcile-derived ownership)
acknowledged; MCP shares the lib function and report serialization verbatim.

---

# Tribunal round 2 — Codex (2026-06-12)

## VERDICT: REJECT (both lifecycle blockers confirmed and fixed in round 3)

### Blocking 1 — self-poisoning on normal re-import
Edit → re-approve → re-import leaves the FIRST ledger entry with a stale sha;
that self-stale entry poisoned the package's own keys and degraded its own
rollback to "unverifiable" skip.

**Fix:** self-poison is harmless by construction — whichever of a package's
imports was first, the owner is the same package. Read-rule: a verified
Owner stands unless the poison set contains a FOREIGN package. Pinned by
`rollback_after_edit_and_reimport_tombstones_own_globals`.

### Blocking 2 — rolled-back spec file pins globals via referenced-guard
`referenced_globals` walked all package files regardless of record status, so
a rolled-back spec left on disk kept its globals alive forever (pre-existing
behavior, now inconsistent with epoch semantics).

**Fix:** specs whose record status is Deprecated no longer count as
referencing. Pinned by
`rollback_epoch_transition_works_with_old_spec_file_left_on_disk`.

Also introduced `DerivedOwnership::UnverifiedCandidate` — a key whose only
ledger candidate is unverified maps to fallback-tombstone when consistent
with the stored field, and to non-destructive skip otherwise.
10 changes: 10 additions & 0 deletions .s5d/index.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -109,3 +109,13 @@ features:
status: applied
product: s5d
version: 1.0.0
- id: decision.s5d.ownership-derivation
spec_path: packages/decision.s5d.ownership-derivation__20260612.s5d.yaml
status: applied
product: s5d
version: 1.0.0
- id: feat.s5d.ownership-derivation
spec_path: packages/feat.s5d.ownership-derivation__20260612.s5d.yaml
status: applied
product: s5d
version: 1.0.0
14 changes: 14 additions & 0 deletions .s5d/ledger.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -147,3 +147,17 @@ entries:
status: success
timestamp: 2026-06-11T13:18:34.283184+00:00
record_ref: records/feat.s5d.self-update__20260611.record.yaml
- spec_sha256: sha256:25f8d74f16b8fcc0548f7a8a821f7a5b479a470abd599eb7684b63fe19f06de0
state_fingerprint: sha256:f3661f6500d4713210d6e64133caec154bd03f0a9e623e3b633c0b3dd358b251
package_id: decision.s5d.ownership-derivation
action: import
status: success
timestamp: 2026-06-12T07:00:58.037320+00:00
record_ref: records/decision.s5d.ownership-derivation__20260612.record.yaml
- spec_sha256: sha256:164fbe42e314dab04baa9f2d61dd8395ab644ab62198967f358ba3620bbacb9c
state_fingerprint: sha256:748cc41bf3906aae6b9a9ac23e1f7c25e4d2b31a3ae81c7dd8c8d9832f2378fa
package_id: feat.s5d.ownership-derivation
action: import
status: success
timestamp: 2026-06-12T07:11:04.200544+00:00
record_ref: records/feat.s5d.ownership-derivation__20260612.record.yaml
130 changes: 130 additions & 0 deletions .s5d/packages/decision.s5d.ownership-derivation__20260612.s5d.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
s5d: '1.0'
id: decision.s5d.ownership-derivation
version: 1.0.0
product: s5d
tier: decision
allow_update: true
meta:
title: ownership-derivation
authors: []
date: 2026-06-12
tickets: []
adrs: []
renames: []
context: null
workflow: null
artifacts: null
links: null
contracts: []
gates:
- kind: review
roc: null
problem:
signal: How should S5D protect rollback ownership (owning_package) integrity without invalidating existing fingerprint baselines? (RAN-491 — owning_package sits outside compute_state_fingerprint, so corrupting it is invisible to drift-check while rollback tombstoning depends on it; pinned by test owning_package_corruption_is_invisible_to_drift_check)
constraints:
- Changing the fingerprint formula invalidates every imported baseline in every repo — mass false drift after upgrade is unacceptable as a silent default
- Rollback must never become destructive on derivation errors — when in doubt, keep data and report loudly
- Legacy repos (aliases created before ledger discipline, manual aliases.yaml edits) must keep working — degrade to warning, not hard failure
targets: []
indicators: []
goodhart_guard: null
acceptance: (1) Tampering owning_package cannot silently change rollback outcomes when ledger and packages are available; (2) zero false drift on existing baselines after upgrade — fingerprint formula untouched; (3) non-destructive degradation — underivable ownership falls back to stored field with at most a warning; (4) no migration day and no new persistent artifact required of users
blast_radius: .s5d state machine core — rollback path (CLI + MCP), alias table semantics; no user-facing schema change
reversibility: High — derivation is additive cross-check logic; reverting restores prior tombstoning behavior without data migration
status: backlog
hypotheses:
- id: versioned-fingerprint
title: Versioned fingerprint
content: Introduce fingerprint v2 that includes owning_package. New imports/reconciles stamp v2; existing entries stay valid under v1 until the next lifecycle event re-stamps them. No migration day; convergence by natural lifecycle.
scope: compute_state_fingerprint, drift-check, reconcile
kind: system
layer: L0
r_eff: null
evidence:
- id: 20260612-internal-versioned-fingerprint
type: internal
content: 'Analysis: avoids baseline invalidation (old entries valid under v1) but leaves a blind window — ownership corruption stays invisible between upgrade and the next lifecycle re-stamp, and dual-version fingerprint code persists indefinitely.'
verdict: refine
valid_until: 2026-09-10T06:55:25.115942+00:00
carrier_ref: null
formality: 2
claim_scope:
- compatibility
- detection-latency
congruence_level: null
reliability: 0.7
refine_kind: specialise
depends_on: []
rationale: null
spec_ref: null
prompt: null
next_move: null
- id: separate-ownership-checksum
title: Separate ownership checksum
content: Keep the import fingerprint untouched; add a second checksum covering only ownership data, stored alongside. Drift-check compares each hash against its own baseline; missing ownership baseline is informational until first stamped.
scope: ledger entries, drift-check
kind: system
layer: L0
r_eff: null
evidence:
- id: 20260612-internal-separate-ownership-checksum
type: internal
content: 'Analysis: detects corruption without touching the import fingerprint, but adds a second permanent artifact to compute, store, and migrate; detects the symptom rather than removing the load-bearing role of the mutable field. Lower ideality than derivation.'
verdict: refine
valid_until: 2026-09-10T06:55:25.121203+00:00
carrier_ref: null
formality: 2
claim_scope:
- complexity
- detection
congruence_level: null
reliability: 0.7
refine_kind: specialise
depends_on: []
rationale: null
spec_ref: null
prompt: null
next_move: null
- id: derive-ownership-from-ledger
title: Derive ownership from ledger
content: 'Rollback derives the owner of each global alias from the append-only ledger plus stored packages at the point of use, instead of trusting the mutable owning_package field. The field degrades to a verified cache: mismatch with the derivation is a loud error (or self-heal). Fingerprint formula unchanged; the corruption class stops being load-bearing.'
scope: rollback, alias table, ledger
kind: system
layer: L2
r_eff: null
evidence:
- id: 20260612-internal-derive-ownership-from-ledger
type: internal
content: 'Falsification probe on the s5d repo itself (2026-06-12): all 17 global aliases have owning_package present in the ledger as a successful import (17/17). Prerequisite for ledger derivation holds on real data. Caveat: probe checked owner-presence, not full derived-owner==stored-owner equality; implementation must add the full derivation test.'
verdict: pass
valid_until: 2026-09-10T06:55:25.110345+00:00
carrier_ref: null
formality: 3
claim_scope:
- derivability
- real-repo
congruence_level: null
reliability: 0.85
refine_kind: null
- id: 20260612-gate-review-derive-ownership-from-ledger
type: gate:review
content: 'Adversarial review, 5 probes: (1) ownership-transfer counter-argument REFUTED by identity.rs — resolve() is first-creator-wins, apply_renames preserves owning_package, no transfer API, so first-import derivation is correct by construction; (2) tail failure (edited+re-imported packages diverge current file from historical import) bounded by conservative semantics — derivation only vetoes/confirms tombstoning, never expands it, disagreement = skip + loud warning; (3) probe weakness (presence-only, not full equality) acknowledged, full derivation tests required in implementation; (4) weakest link — derivation sources are sha256-bound (packages) and append-only (ledger), strictly stronger than the unanchored alias field; (5) alternatives D1/D2 recorded as hypotheses with refine verdicts, merkle-izing aliases recreates the baseline-invalidation contradiction. No fatal flaw.'
verdict: pass
valid_until: 2026-09-10T07:00:05.862753+00:00
carrier_ref: null
formality: 3
claim_scope:
- adversarial-review
- decision-tier
congruence_level: null
reliability: 0.85
refine_kind: null
depends_on: []
rationale: null
spec_ref: feat.s5d.ownership-derivation__20260612.s5d.yaml
prompt: null
next_move: null
decision: null
note_rationale: null
expires_at: null
auto_noted: false
Loading