Repository navigation
Closed as not planned
Description
Ruling: D5, second part (b), ruled 2 October 2026 (docs/signing-rulings-2026-10-d5-d9.md, "D5 … Second part: is the authority log itself signed?"; recorded in docs/signing-rulings-2026-10.md, "D5 to D9"). Size: M. Depends on: PR #80 merged; #70 (signing: sidecars, ssh, L011, the signed-bytes function, under from D9). Must land: before any real namespace has a second grant, and before R1.5.
Why
D5 (a) makes verify evaluate the role as of the act (A006), reading the grants in the log. Until grants and grant acceptances are signed, a forged grant file naming the genesis holder as granted_by satisfies that check. The only defence meanwhile is that grants are few and visible in review.
What to build
- Grants signed by the grantor, who must pass the same
authorizecheck forgrant-roleover the grant's scope, on the grant the act names (D9). The chain ends at the genesis grant, anchored by itsexternal_refand the genesis holder's self-bound key. - Grant acceptances signed by the holder.
- Grant revocations signed by the revoker (added 4 October 2026, PR ledger: Session B step 1 — signed acceptances, revocations, key bindings and policy changes (#70) #89 review). A
rev:revocation whoserevokesis a grant is signed underledger.revocation.v1, the payload I9: Signed acceptances and revocations #70 already defines for revocations, by itsactor, on the grant it names inunder. I9: Signed acceptances and revocations #70 signs only revocations of acceptances; a grant's revocation is left unsigned there, because signing it without signing the grant it ends would be the only signed record in that chain. In I9: Signed acceptances and revocations #70ledger-core/src/signing/subject.rssubjectsfilters it out (revocation(…)returnsNoneforRevocable::Grant), and thegrant revokeverb (Author::revoke_grant,ledger-core/src/author/authority_ops.rs) files no sidecar. - Unavailability (added 5 October 2026, PR ledger: an old-style revocation is valid only as a pre-policy act (A006) #93 audit): a closed payload, a signature by its declarer (
by), and a role check atverifyfordeclare-unavailabilityon the basis it claims. Today onlyverifychecks it, throughauthority/references.rsbasis_holds, and that checks the declarer's claimed relation to the grant (aSCHEMArule). It has no payload, no sidecar and noA006.- A forged one today: hand-written with the grantor named as
byand basisgrantor, it passesverifyand makes the grant unavailable fromfrom. The holder's acts in that window then failA006, and a lower-ranked grant of the same role covers them instead.
- A forged one today: hand-written with the grantor named as
- Availability (added 5 October 2026): a closed payload and a signature by the holder (
by). Its role check atverifyis thatbyholds the unavailable grant, whichreferences.rschecks today as aSCHEMArule on the claimedbyonly.- A forged one today: hand-written naming the holder as
by, it passesverifyand ends an unavailability early, so the grant is usable again fromavailable_at.
- A forged one today: hand-written naming the holder as
- Role declarations (added 5 October 2026): a closed payload for a role file, a signature by its declarer, and a role check at
verifythat the declarer heldgrant-roleover*(Act::DeclareRole). Today the declarer is checked only by therole declareverb.verifychecks onlyauthority/structure.rsrole_faults(format, id, filename, duplicates) and write-once (verify/history.rs,L007). A role file names no declarer, so the payload has to add one.- A forged one today: a well-formed hand-written file in
.decisions/roles/passesverify, and any capability set it lists exists for a grant to name.
- A forged one today: a well-formed hand-written file in
atin the grant payload.ledger.authority-grant.v1(ledger-core/src/authority/payload.rs,grant_map) carries noattoday. Add it: hashed when present, omitted when absent, required in files of the format this issue introduces. No existing digest moves.- A payload for the grant acceptance — accepted as proposed (2 October 2026).
GrantAcceptance(ledger-core/src/authority/grant.rs) gets a closed payload under its own prefix,ledger.grant-acceptance.v1, over{grant, signs, actor, at}.- It carries no
under. Accepting a grant is the holder's own act, so there is no authorising grant to name.
- It carries no
underon grants (D9 (a)), if I9: Signed acceptances and revocations #70 has not already added it to the grant payload. (I9: Signed acceptances and revocations #70, PR ledger: Session B step 1 — signed acceptances, revocations, key bindings and policy changes (#70) #89, adds it.)- The grant does not bind its role's content. Session A close-out §3 question 8 is ruled write-once and held by
verify(that check lands in I9: Signed acceptances and revocations #70), so a grant's role id names fixed content. The grant payload keeps naming its role by id only.
Tests
- A forged grant (hand-written, valid shape, unsigned, or signed by a key that is not the grantor's) fails the gate, and an acceptance made under it fails
A006. - A grant acceptance not signed by the holder fails.
- A grant revocation that is unsigned, or signed by a key that is not the revoker's, fails
L011where policy requires a signature. - An unavailability, an availability or a role file that is unsigned, or signed by a key not the declarer's, fails
L011where policy requires a signature. One whose declarer could not make it, as of the act, failsA006. - Every stored digest unchanged (Session A's
ledger-cli/tests/digests.rs).
Constraints
- Format document (§3.9) and migration note in the same PR.
verify --exportpasses; regenerate exports. - No format change outside this list.
Metadata
Metadata
Assignees
Labels
No labels
Type
Fields
Priority
None yet
Effort
None yet
Progress
None yet
Activity
Hafeok commentedon Nov 3, 2026
Closed as not carried under D1.24`` and the definition's chapter 8:``` the Rust tool is frozen at
rust-finaland its tree left `main` in #166 (`53bd547`). This concerns the Rust ledger (its keys, namespaces or authority), which is Writ's authority graph now. The rewrite holds no key and no grant, and `writ import` reads `.decisions/` once, at the tag. Disposition approved on #165.Generated by Claude Code