Repository navigation
Keys per namespace: key close, D7, first policy; remove carried_over; the two notices (issue 6) - #160
Conversation
|
CI, standing down on one step. The The remedy the gate names is Generated by Claude Code |
4ebe365 to
73f98fb
Compare
406b17d to
792983a
Compare
Issue #150 (PRD issue 7, §3.4; ruling 47). Each namespace's `ns/<ns>/allowed_signers` is derived from that namespace's trusted bindings alone — a line ended by a close in that namespace only, as issue 6 made the derivation read — and a namespace that binds nothing has no file. `signers::write` now removes a file committed in a namespace none of whose bindings is trusted (inventory item N10) and reports what it wrote and removed per namespace (`Synced`); `ledger identity sync`, the identity verbs and `init --namespace` print those lines, and `sync` says when no namespace binds a key. `[SIGNERS]` already compared each namespace's file with its own derivation (issue 1); its protocol line now says so. Tests (each failing before the change where the behaviour is new): `ledger-cli/tests/signers_per_namespace.rs` — each namespace has its own file holding its own `ledger-accept@<ns>` lines; a close in A leaves B's file byte-identical; a file hand-written in a namespace that binds nothing fails `[SIGNERS]` naming the namespace, and `identity sync` removes it, prints the removal, and the store verifies again; a namespace whose only binding is untrusted has no file after `sync`. Protocol: LP-4.10 loses its note and gains the removal; LP-4.33 names the namespace; Appendix B row; Appendix C note "A stale `allowed_signers` is removed". No class added; no digest moves. Stacked on #160 (issue 6). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GgRcHXmnAu43hChNxhnqxU
…two notices Issue #149 (PRD issue 6, §3.3; rulings 47 and 69; AC-47 second bullet). A key is bound, closed and trusted in one namespace. `Authority::of` and `as_of` now filter key bindings by namespace like every other record; `key_close::same_key` compares the namespace, so a close ends the key in its own namespace only and `refusal`'s three rules (another principal's, closed, already open) look at the binding's namespace; D7 (`filing`) drops the store-wide branch — the genesis holder's first key in a namespace is that namespace's self-bound binding, once per namespace, under its own mandate; the signing check drops `carried_over`, judges a first policy by a key trusted in its own namespace, and the re-acceptance deadline runs from the key's earliest close there; `allowed_signers` ends a line at a close in its own namespace. The writer binds the configured key self-bound at every `init --namespace` (`carry_genesis_key` and `no_live_key` go; `--without-key` stays until issue 13), `identity add`'s self-bound test is per namespace, and signing refuses a key not live in the namespace (`ToSign.any_namespace` goes). Two repository notices, never findings (`verify::key_notices`, in the text and JSON report): a key closed in one namespace and open in another; one key bound to two principals in two namespaces. Tests (each failing before the change): `key_across_namespaces.rs`, rewritten as §3.11 says — bound in A then B, or B then A, a close in A leaves B open: the key still signs there, A's `allowed_signers` line ends and B's does not, the split is a notice, the key signs nothing in A, and a third namespace opens with the same key self-bound; a rotate in A leaves B's acceptances, review items and `allowed_signers` byte-identical (AC-47, second bullet); the within-namespace rules of 2026-10-06 stand (four tests kept); and the carried test, that no agent identity and no non-interactive session produces a key close. The writer's close in every namespace held is issue 8's and is not claimed. `genesis_key.rs`: `init` in a later namespace self-binds the holder's key there under the namespace's own mandate and signs the first policy with it; with every key closed elsewhere `init` binds the key again and `verify` notices the split (JSON `key_split`); with no usable key, `--without-key` initialises unbound and the unbound-genesis notice names the namespace. The prompt assigned these rewrites to issue 8; they could not wait, since the cross-namespace lean they asserted is what this step removes. `key_close_tests.rs`: three tests now assert the namespace reading. The pre-policy cases now bind the holder's first key in the second namespace self-bound: `pre_policy_binding.rs` (`unsigned_before` is self-bound under `hand::found`'s mandate; the signed case signs the first policy with the key bound before it, as LP-4.31 now requires; opening a namespace over a binding filed in it before any policy is refused again, since the holder's own self-bound binding would no longer be the first there — `…_and_init_is_refused_over_it`); `binding_accounting.rs` (`self_bound_by_hand`, one namespace per first binding). `trust.rs`: `init` self-binds in the second namespace and a further key there is the holder's own add (renamed from "once per store"); a hand-written self-bound binding beside `init`'s fails, "first in the namespace". `genesis_key.rs`'s forged-binding test reads the same wording. `key_across_namespaces.rs` keeps its four within-namespace tests. Protocol: LP-4.12, LP-4.13, LP-4.31, LP-4.32, LP-4.37, LP-4.38, LP-4.39 (ruling 101's wording), LP-6.31 (keys note dropped), LP-6.32 (loses its mark; the writer's close-everywhere noted for issue 8), LP-8.31 (two notices, report shape); Appendix B row; Appendix C note "Keys are per namespace". CLAUDE.md updated. No class added; no digest moves (a binding's hashed fields are unchanged and `namespace` was among them). Stacked on #159 (issue 5). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GgRcHXmnAu43hChNxhnqxU
Files the signed bindings the contract-surface gate demands for this step's 14 exposed Rust surface changes over 3 files (13 bindings: the two `key` fields of key_notices.rs share one): a new declaration for verify/key_notices.rs with its verdict_knowledge written, verify/mod.rs amended with bindings, and author/genesis_key.rs amended with its verdict rewritten now that init binds the key in every namespace it opens. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GgRcHXmnAu43hChNxhnqxU
73f98fb to
4ee026b
Compare
792983a to
53becab
Compare
Issue #150 (PRD issue 7, §3.4; ruling 47). Each namespace's `ns/<ns>/allowed_signers` is derived from that namespace's trusted bindings alone — a line ended by a close in that namespace only, as issue 6 made the derivation read — and a namespace that binds nothing has no file. `signers::write` now removes a file committed in a namespace none of whose bindings is trusted (inventory item N10) and reports what it wrote and removed per namespace (`Synced`); `ledger identity sync`, the identity verbs and `init --namespace` print those lines, and `sync` says when no namespace binds a key. `[SIGNERS]` already compared each namespace's file with its own derivation (issue 1); its protocol line now says so. Tests (each failing before the change where the behaviour is new): `ledger-cli/tests/signers_per_namespace.rs` — each namespace has its own file holding its own `ledger-accept@<ns>` lines; a close in A leaves B's file byte-identical; a file hand-written in a namespace that binds nothing fails `[SIGNERS]` naming the namespace, and `identity sync` removes it, prints the removal, and the store verifies again; a namespace whose only binding is untrusted has no file after `sync`. Protocol: LP-4.10 loses its note and gains the removal; LP-4.33 names the namespace; Appendix B row; Appendix C note "A stale `allowed_signers` is removed". No class added; no digest moves. Stacked on #160 (issue 6). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GgRcHXmnAu43hChNxhnqxU
|
Closed unmerged under D1.24:`` the Rust tree left Generated by Claude Code |
Closes #149 — PRD
ledger/prd/namespace-independence-prd.md§6 issue 6 (§3.3; rulings 47 and 69; AC-47 second bullet).Stacked on #159 (issue 5). Review the last commit alone,
406b17db.What lands
A key is bound, closed and trusted in one namespace.
Authority::of/as_offilter key bindings by namespace like every other record (the step 5 note on keys goes).key_close::same_keycompares the namespace: a close ends the key in its own namespace only (LP-6.32), andrefusal's three rules — another principal's key, a closed key, a key already open — look at the binding's namespace (LP-4.37).authority::filing) drops the store-wide branch: the genesis holder's first key in a namespace is that namespace's self-bound binding, once per namespace, under its own mandate (LP-4.12).carried_over; a first policy is judged by a key trusted in its own namespace (LP-4.31); the re-acceptance deadline runs from the key's earliest close there (LP-4.13);allowed_signersends a line at a close in its own namespace (LP-4.32).init --namespacebinds the configured key self-bound in every namespace it opens (carry_genesis_keyandno_live_keygo;--without-keystays until issue 13);identity add's self-bound test is per namespace; signing refuses a key not live in the namespace (ToSign.any_namespacegoes).verify::key_notices, in the text and the JSON report askey_splitandkey_shared): a key closed in one namespace and open in another; one key bound to two principals in two namespaces (ruling 69).The writer's close in every namespace it holds is issue 8's and is not claimed here.
Tests
ledger-cli/tests/key_across_namespaces.rs, rewritten as §3.11 says (each failing before): bound in A then B, or B then A, a close in A leaves B open — the key still signs there, A'sallowed_signersline ends and B's does not, the split is a notice, the key signs nothing in A, and a third namespace opens with the same key self-bound; a rotate in A leaves B's acceptances, review items andallowed_signersbyte-identical (AC-47, second bullet); the four within-namespace tests of 2026-10-06 stand; and the carried test — no agent identity and no non-interactive session produces a key close.Rewritten, and why:
genesis_key.rs:initin a later namespace self-binds the holder's key there under the namespace's own mandate and signs the first policy with it; with every key closed elsewhereinitbinds the key again andverifynotices the split; with no usable key,--without-keyinitialises unbound and the unbound-genesis notice names the namespace. The prompt assigned these rewrites to issue 8; they could not wait, since the cross-namespace lean they asserted is what this step removes.pre_policy_binding.rsandbinding_accounting.rs: the holder's first key in the second namespace is now self-bound (underhand::found's mandate); the signed case signs the first policy with the key bound before it, as LP-4.31 now requires; opening a namespace over a binding filed in it before any policy is refused again, since the holder's own self-bound binding would no longer be the first there.trust.rs:initself-binds in the second namespace and a further key there is the holder's own add (was "once per store"); a hand-written self-bound binding besideinit's fails, "first in the namespace".genesis_key.rs's forged-binding test reads the same wording.key_close_tests.rs: three unit tests assert the namespace reading.Protocol
LP-4.12, LP-4.13, LP-4.31, LP-4.32, LP-4.37, LP-4.38 (the later-namespace paragraph goes), LP-4.39 (ruling 101's wording), LP-6.31 (keys note dropped), LP-6.32 (loses its mark), LP-8.31 (two notices, report shape); Appendix B row; Appendix C note "Keys are per namespace". CLAUDE.md updated. No class added; no digest moves (a binding's hashed fields are unchanged and
namespacewas among them); no committed store in this repository binds a key.Checks
cargo build,cargo t,cargo clippy --workspace -- -D warnings -D clippy::unwrap_used, the quality scripts, andledger verify --exporton this repository (same output as onmain).🤖 Generated with Claude Code
https://claude.ai/code/session_01GgRcHXmnAu43hChNxhnqxU
Generated by Claude Code