Repository navigation
Keys per namespace: key close, D7, first policy; remove carried_over; the two notices (issue 6) - #160
Open
Hafeok wants to merge 2 commits into
Conversation
This was referenced Oct 9, 2026
Collaborator
Author
|
CI, standing down on one step. The The remedy the gate names is Generated by Claude Code |
Hafeok
force-pushed
the
claude/great-feynman-zcdsdd-step-05-authority
branch
from
October 11, 2026 06:17
4ebe365 to
73f98fb
Compare
Hafeok
force-pushed
the
claude/great-feynman-zcdsdd-step-06-keys
branch
from
October 11, 2026 06:18
406b17d to
792983a
Compare
Hafeok
added a commit
that referenced
this pull request
Oct 11, 2026
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
Hafeok
force-pushed
the
claude/great-feynman-zcdsdd-step-05-authority
branch
from
October 11, 2026 06:22
73f98fb to
4ee026b
Compare
Hafeok
force-pushed
the
claude/great-feynman-zcdsdd-step-06-keys
branch
from
October 11, 2026 06:22
792983a to
53becab
Compare
Hafeok
added a commit
that referenced
this pull request
Oct 11, 2026
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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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