Phase 2b+3 of the step-3 rehearsal, under the four operator decisions of
2026-08-06: deterministic signing, separate slh_dsa block, additive posture,
keygen executed same day (key in provider state, 0600, git-ignored — verified
before generation, not after).
src/pacta/slhdsa.py — the module that did not exist (register:
pq-slot-names-unproven-algorithm). Parameter set LOCKED to SLH-DSA-SHA2-128s:
every entry point asserts the key's reported algorithm and refuses anything
else, because any other set sits outside all eleven certificates while looking
like dogfood. Deterministic via -pkeyopt deterministic:1, so the byte-level
reproducibility check that caught a real defect on the Ed25519 side survives
here. Verification runs two ways: OpenSSL, and pacta-verify-slhdsa built from
the pinned proven source — the one signature check in the estate performed by
code whose verify path the certificates cover. The proven-verifier path is
package-anchored, not cwd-relative: the lesson of signer-backend-depends-on-cwd
applied on day one, not retrofitted.
make_signed_tree_head grows optional slhdsa key parameters. With them, the head
carries a signed slh_dsa block; without, an honest not-configured slot exactly
as ml_dsa always has. ml_dsa itself is untouched. Signatures stay outside the
signed payload for both algorithms — tested by asserting the payload is
byte-identical with and without the slh_dsa key.
Honesty carried in the artifact: signing_backend says "openssl" because no
proven signer exists for any algorithm; the module docstring states that
nothing here is Lean-proven and that the certificates cover the verify path of
the extracted model only.
Tests: 7 new, suite 152 passed, 0 failed, 0 skipped — including determinism
(two signings, identical bytes), the foreign-key refusal (Ed25519 key raises),
corruption rejected by both verifiers, and the proven/OpenSSL agreement.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The deployed consistency verifier implemented the RFC 9162 2.1.4.2
bit-navigation loop but its final return checked only the two
reconstructed roots, omitting the terminal condition that the new-size
navigation counter reach zero. That condition couples the consumed proof
length to the claimed tree sizes; without it, a valid proof for one
transition verifies under a lied (power-of-two) old size. Flagship: a
valid 2->3 proof is accepted under the false claim 1->3 with the size-2
root.
Fix: add `and sn == 0` to the final return.
This is the corpus's Known Gap 14 (3,867 deployed-accepts-only cases in a
pinned 73,573-case family, recorded in public log entry 13). It was
found by the project's own differential harness; a post-appeal review
round added a faithful RFC oracle as a third comparison, which showed
the deployed verifier — not the mechanized model — was the one deviating
from RFC 9162, and traced it to the missing terminal check.
Scope: verify_consistency's only production caller is the consumer-side
pin store, reached only behind a verified head signature. Generation is
RFC-correct and unaffected; the live provider service does not run this
verifier; the published standalone verify.py has no consistency verifier.
An empirical search found 0 realizable pin-advance poisons against an
honestly pinned consumer, consistent with Known Gap 14's non-claim.
Verification:
- New fail-first three-way regression test
test_consistency_lied_size_three_way_agreement (deployed / recursive
ConsRec model / independent faithful RFC 9162 transliteration) over the
honest AND lied-size families; fails pre-fix, passes post-fix.
- Historical differential tests (164,479 inclusion; 164,224 consistency)
unchanged — the fix rejects nothing honest.
- Full suite: 145 passed, 0 failed.
Public log entry 13, the attested accumulator commit, and the IACR
submission PDF are all unchanged. Vulnerable state tagged
vulnerable/sn0-consistency-fd2f6ba. See
docs/security-2026-07-23-consistency-terminal-check.md.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Two repos joined the estate on 2026-07-22; both renderings (ESTATE.md +
cockpit /estate) gain their cards, with every fact recomputed from the
repos themselves:
- fips205-source (upstream lane): verbatim snapshot of
integritychain/fips205 (pure-Rust FIPS 205 / SLH-DSA), upstream pin
30bac08, snapshot head 5dca0db — single deviation: upstream CI
workflows stripped, documented in-commit. Aeneas-compat patches land
there as transparent, individually-justified commits; nothing is
proposed upstream.
- fips205-slhdsa-verified (subject lane): SLH-DSA-SHA2-128s verify-path
campaign, marked exactly as its own check.sh says — CAMPAIGN IN
PROGRESS, zero certificates, non-green by design. NOT attested; the
map does not imply otherwise.
Also:
- liveness board now probes fips205-slhdsa-verified (a sibling under
the default repos root). fips205-source is deliberately NOT probed:
the upstream-source shelf lives outside that root, like the five
existing source clones (comment documents the decision).
- drift tripwire (test_estate_view_and_estate_md_do_not_drift) extended
with both new sentinel names.
- stale fact chip refreshed in both renderings: pacta suite 135 → 144
green (the suite grew during the cockpit era; chip was never bumped).
- estateview's pasta dossier no longer calls the curve layer "the one
open verification task in the estate" — the campaign is a second.
Suite 144 green.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Audit question: is the documentation coherent, and is the app portable
to a fresh machine (macOS) with proper isolation? Findings and fixes:
- README never mentioned the cockpit/deck/lab manual (three rounds of UI
evolution invisible at the front door). Added: human-surface section
with the one command, expanded Install (editable-from-clone is the
supported mode — repo files are part of the product; zero-install
PYTHONPATH=src alternative; fresh-machine skip behavior), macOS
openssl/LibreSSL Ed25519 prerequisite with a one-line self-check,
wallet commands in the command list.
- The lab manual violated the repo's own macOS law (AGENTS.md): GNU
sha256sum -> shasum -a 256; GNU sed -i -> portable python3 -c
one-liner (executed and output-matched before shipping: entry 0 hash
mismatch, BROKEN, exit 1).
- Fresh-clone bootstrap was actually tested end to end in a scratch
clone: zero-install suite 130 passed / 0 failed / 14 skipped after
fixing the one unguarded test (test_ledger_is_hash_chained now skips
like its siblings when the dogfood binary is absent - capability gap,
not failure); venv + pip install -e . -> pacta console script serves
bridge/deck/manual/sample-prefill/drift-tripwire with no PYTHONPATH.
- PYTHONPATH incantations simplified: cockpit needs src only (provider
never imported by src/pacta); manual + cockpit.md updated.
- threat-model.md: cockpit attack-surface note (no mutating routes,
no auth because nothing to operate, localhost-only disclosure risk,
probe-only network I/O, fake-cockpit = host-compromise boundary).
- products.md: cockpit named as the shared human surface of all four
profiles. AGENTS.md: doc-portability law + the cockpit's three laws
added to the standing guidance.
Suite 144 green here; 130/0/14 on a bare clone.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Operator asked for a real big fat user manual: read on one monitor with
the deck on the other, worked like a lab from beginning to end, with
highest didactical skill — the goal being to educate ONE person in ALL
roles, as if to BECOME each role. Shipped as a full course:
- docs/warden-lab-manual.md (canonical, ~7100 words): 8 sessions +
capstone. Fixed didactic ritual per role-session: why the role exists
-> the mind of the role -> concepts -> LAB (numbered machine exercises
with checkpoint rails) -> never-list with whys + thought experiment ->
handoff artifact -> self-test -> recap card. Notation: do / checkpoint
/ write / optional. Capstone 'incident day': one incident walked
through all six chairs producing seven written artifacts; graduation
session maps the path to a real wallet; Appendix A command reference
by chair, Appendix B full self-test answers.
- Session 4's tamper drill: copy the demo wallet, flip one character of
ledger history, watch verify-ledger AND a second cockpit catch it.
Every checkpoint in the manual was executed by the author before
commit: status fields, intact-chain exit 0, tampered-chain 'entry 0:
hash mismatch / BROKEN' exit 1, CUSTODY EVIDENCE BROKEN banner.
- src/pacta/mdlite.py: deliberately small stdlib Markdown renderer
(headings/anchors+TOC, bold/italic/code with placeholder stashing,
fences, lists, quotes, tables, links); tested against the real manual
for zero artifact leaks.
- /manual route with syllabus TOC; manual typography (checkpoint boxes,
session borders); nav tab, deck wizard cross-link, cli hint.
Suite 142 -> 144 green; read-only sweep covers /manual.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Operator asked for a tmux-type panes grid in the browser (one pane per
role, all acting in parallel, like real life) with a wizard on the right
that takes a newcomer by the hand through every role's actions, each
instruction camouflaged in that role's color.
- /deck: CSS-grid of six live panes (2-col, 3-col on wide screens),
one per station, each an iframe onto /station/<id>?pane=1. tmux
controls per pane: reload, single-pane zoom, open-full. Narrow
screens: wizard first, panes stacked.
- pane mode (?pane=1): chrome-stripped shell (no h1/banner/nav), same
station content, READ-ONLY label kept; an 8-line shim re-carries
pane=1 on every same-origin link and form submit, so probes, incident
browsing, and inspect verdicts all happen inside the pane.
- the wizard: a 10-step guided first watch across all six roles on the
live demo wallet. Each step card wears the role's hue with a 'YOU ARE
THE <ROLE>' chip, the matching pane glows, and every step states what
success looks like + what was just learned. Step remembered per
session (sessionStorage).
- /inspect?sample=1 pre-fills examples/wallet-evidence so the
cryptographer step verifies (then deliberately breaks) real evidence.
- verified in a real browser: step navigation moves the glow, panes
load their stations, Probe-now inside the pane probed live inside the
pane (log head tree_size 13), sample flow prefilled the key in-pane.
Suite 139 -> 142 green. Read-only guarantee unchanged; byte sweep
covers /deck and pane routes.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Operator verdict on round two: better, but 'still no coherent
application'. The cockpit must provide everything a human crew would
need if no AI were around — as distinct roles that cooperate through
handoffs and never melt into each other. This rebuilds the IA as a
bridge with six stations over shared instruments, in the control-room
tradition (overview -> station -> instrument -> raw files/CLI), with
maker-checker separation of duties encoded in the UI itself.
- / is now the Bridge: whole-system verdict strip, six crew cards with
live data, and the dispatch (andon) board 'if this happens, who acts'
- /station/{proposer,quorum,operator,cryptographer,architect,newcomer}:
each console has a fixed anatomy: Mission -> Duties (every duty a
runnable, verified-real CLI command - the no-AI drill) -> embedded
live instruments -> 'This station never...' (separation of duties) ->
Handoffs (receives/delivers)
- Operator gets a real liveness board: on-demand parallel probes (HTTP
GET on log head/paper/blog/mirror with observed facts + latency; git
HEAD/cleanliness on all 9 local repos). Never probes on ordinary page
loads. Verified live: caught this very repo as 'alive, dirty' while
building it, and confirmed log 13/3488a2d0 + paper 7f140356
- Architect gets the live drift tripwire (ESTATE.md vs estate view)
- modularized per the standing separation-of-concerns order:
uikit.py (primitives+style), stations.py (role model, pure),
liveness.py (probes), walletui.py (collectors, instruments, routes)
- crew law test-enforced: bridge crew+dispatch, per-station role
contract, station distinctness (signature phrases must not bleed
across roles), explicit-probe semantics; read-only byte sweep now
covers all 13 routes incl. the probe route
- narrow-viewport fix: breakany for unbreakable paths in headings
Suite 135 -> 139 green. Read-only guarantee unchanged: no mutating
routes; every custody act is a printed command, never a button.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Operator verdict on the first cockpit: unusable, jargon-walled. The
evidence layer was honest but the presentation assumed the reader
already lived inside warden's head. This rebuilds the presentation
layer around a testable UX contract, additive to the design law:
- every page: verdict IN WORDS first (CUSTODY HEALTHY / CUSTODY FROZEN
(LATCHED) / CUSTODY EVIDENCE BROKEN), then evidence, then provenance
- every page: plain-language lead saying what the page answers
- every panel: 'How to read this panel' expander interpreting every
column and pill; jargon carries a ? linking to the glossary
- new /guide view: what warden is, how to read any page, color code,
five-minute tour, 12-term glossary, honest 'what this cockpit cannot
tell you'
- navigation: two-line tabs stating the question each view answers,
present on every page; /estate gets a back-to-cockpit chip
- explained empty states (incidents: 'empty is the good state')
- narrow-viewport fix: tables/pre scroll in their own containers
- estate fact chip updated 130->135 green (both renderings)
UX contract is test-enforced (guide terms, lead+nav+explainers on every
view, empty states); read-only byte-guarantee sweep now covers /guide.
Verified by looking: served --demo, walked all six views in a browser.
Suite 131 -> 135 green.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The operator ran the documented command and hit the fail-fast (no
wallet exists on a fresh machine) — correct behavior, useless
instruction. seal_demo_wallet() now seals a throwaway DEMO wallet
(fake shell-stub members, DEMO-labeled fields, temp dir named
warden-DEMO-*, sample incident/refusal/airgap so every view has
content); 'pacta wallet cockpit --demo' serves it. Exactly one of
--wallet/--demo required. Verified by running the literal command:
all five views 200, demo quorum renders. Suite 130 -> 131.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Operator questions answered in code: (1) the estate map now lives IN the
cockpit too — /estate serves the interactive map (lanes, typed edges,
loops, clickable dossiers) to the same human audience the cockpit
serves; ESTATE.md remains the canonical committed version (renders on
GitHub, reachable by agents via llms.txt, needs no running process), and
a name-level sync test guards drift between the two renderings — the
published_assets lesson applied preemptively. (2) 'What is RUNNING?' is
now answered everywhere: an operations strip on the map (ALWAYS ON:
caddy + the LTL read-only container + Forgejo with its single 03:00
mirror cron, all droplet; ON-DEMAND: append/publish/sign ceremonies,
cockpit, MCP, operator machine only; NOT RUNNING: warden — prototype,
no deployed instance, no funds watched; everything else: static files
or external parties), a per-entity Runtime line in every dossier, and a
verified What-is-running table in ESTATE.md (container commands, :ro
mounts and read_only:true on the LTL service, and the crontab checked
on the droplet 2026-07-20, not recalled).
Suite 128 -> 130 (estate route + drift guard). Local-only as before:
nothing deployed, live estate untouched.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Operator-ordered milestone, built under an explicit no-risk constraint
while the paper application is in flight: strictly ADDITIVE (one new
module + one CLI subcommand; zero changes to wallet semantics, the
public site, or anything the paper describes), LOCAL-ONLY (never
deployed; binds 127.0.0.1), and READ-ONLY in v1 (human approve/deny is
deliberately deferred — that is a custody-semantics change belonging to
a separately reviewed milestone).
New: src/pacta/walletui.py — four views over an existing wallet:
- Posture: latch state, ledger head with FULL hash-chain
re-verification, pinned quorum members, spending policy verbatim.
- Signature queue: airgap outbox/inbox, observed never operated.
- Incidents & refusals: verbatim records, newest first.
- Receipt inspector: paste attestation + receipt + log key; verdict,
per-signature results, and diagnostics come verbatim from
transparency.verify_receipt — the deployed verifier itself, reused
not reimplemented.
Design law, stated in the module and enforced by tests: THE COCKPIT
RENDERS EVIDENCE, IT NEVER ASSERTS IT. Every panel recomputes at
request time and carries a provenance line (function + timestamp);
anything unverifiable renders a loud FAILED-TO-VERIFY panel — no cached
green, no neutral gray. Panels state what they do NOT prove (e.g.
binary pinning vs source-to-binary correspondence).
CLI: pacta wallet cockpit --wallet DIR [--host --port].
Tests (10 new, suite 118 -> 128 green): recomputed-evidence rendering,
CHAIN BROKEN on tampered ledger, loud failure on collector error,
latched-state rendering, airgap queue states, verbatim incident/refusal
rendering, fail-closed inspector on garbage, real-evidence roundtrip
(skips if example evidence absent), full-sweep BYTE-LEVEL read-only
guarantee (wallet dir hash-identical after all GETs + a POST), and
fail-fast on non-wallet dirs. Rendering additionally verified visually
against a live demo wallet (posture, quorum table, incidents).
Docs: docs/cockpit.md; WALLET.md section; ESTATE.md + llms.txt updated.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
REAL DEFECT found by the operator-ordered doc-freshness audit:
published_assets.py still carried the PRE-HARDENING fail-open verify.py
and the pre-Tier-2 README as the templates that log-publish drops into
the mirror — the next publish would have silently overwritten the
round-13-hardened fail-closed verifier and the corrected README with
the old versions. Fixed:
- published_assets.py regenerated from the canonical mirror files
(byte-identity verified by round-trip exec), now also carrying
verify_selftest.py; SYNC RULE documented in the module docstring.
- transparency_log.publish() now writes verify_selftest.py too.
- NEW tests/test_published_assets.py pins the security-critical markers
(fail-closed FATAL, RECEIPT_TYPE, verify_receipt, --all receipt
coverage, required fingerprint) so template drift fails CI instead of
shipping.
- test_web_and_witness updated to the hardened verifier's markers —
the published test log now passes FULL signature mode end to end
('RESULT: OK [full]'), a stronger assertion than the old string.
Doc refresh in the same pass:
- llms.txt: thirteen leaves + entry-13 self-attestation + fail-closed
verifier; paper line -> new title, 23 pages, v0.2/v0.1 archives.
- Course (generator + generated 06b notebook): 'the git hash IS the
content hash' -> 'the commit pins the exact source tree';
'irrevocably part of the log every other agent sees' -> 'committed to
the log's signed view, which any agent can compare' (the two Tier-2
scope corrections had never reached the teaching material).
- test_paper_verifiers.py docstring rescoped: its 164k counts are the
archived v0.2 report's citation; the current paper cites the corpus
harness and makes no extensional-equality claim.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Found by the entry-13 12->13 rehearsal: build_attestation emitted
subject/environment/replay/certificates but NO scope — the profile's
guarantees/exclusions/deployment_constraints (which carry a repo's
known_status scoped-claim wording and known_exclusions) reached only
the claim card, never the published leaf. So the round-6 requirement
that entry 13's LEAF carry its scoped attestation text was unmet by the
code; a reviewer who checked the claim card saw the wording that the
leaf did not contain. Added a 'scope' block
(guarantees/exclusions/deployment_constraints) to the leaf; pure text,
safe to publish, validator is additive. Two provider tests assert the
block exists and that a repo's known_status/known_exclusions reach it.
Suite 115 passed.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
R6-B1 (Claude, executed end-to-end): provenness was decided by a
WHOLE-OUTPUT 'no axioms' sentence, so an axiom-free certificate whose
line was entirely absent still scored proven+clean ([]==[]). The
reviewer drove a doctored 60-line output through the real gate and got
61/61 with domsep never audited. Classification is now extracted into
classify_certificates(): proven iff the certificate's OWN anchor was
parsed (axiom-free anchors populate []); absent certs are
unknown/failed + not_checked — never clean. This also fail-closes the
typo'd-future-cert case (R6-C2).
GPT §6: parse_axiom_output is now RECORD-scoped — anchors delimit
records, a cone bracket is accepted only inside its own record, missing
or truncated brackets yield MISSING (fail closed) instead of borrowing
the next certificate's bracket, and cones may wrap arbitrarily (the
old fixed 16-line window was a latent overflow for the 11-axiom
ed25519 apex cones on this estate). Anchor names are captured between
the exact quotes Lean prints.
Six new regression tests (absent-axiom-free-not-clean, missing-bracket
no-steal, truncated cone, >16-line wrap, duplicate anchor, interleaved
diagnostics). Suite: 114 passed / 0 failed.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Found by the entry-13 rehearsal (the accumulator corpus is the first
subject with axiom-free certificates — every fork certificate carries
at least the boundary axiom, so this path was never exercised):
- an axiom-free certificate ('X' does not depend on any axioms) was
parsed by opening a 16-line window and taking the first bracket in
it — which belongs to the NEXT certificate. domsep/Hash/
instDecidableEqHash/take_append_drop were reported with their
neighbors' cones and flagged dirty.
- certificate names were matched as bare substrings, so 'Foo' could
anchor on the line for 'Foo_bar'. Now anchored on the exact quoted
name Lean prints.
The no-axioms decision is now made on the anchor line itself, before
any window. Two regression tests added (steal-next-cone, exact-name);
suite 108 passed / 0 failed.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Two Fable-5 inventory agents cross-checked every empirical claim in the
paper against code/deployed log, and every external pointer against the
live internet. Fixes on both sides:
CODE (system brought up to the paper's claims):
- SECURITY: pin-store mutation (incl. permanent poisoning) was reachable
via receipts whose head signature FAILED verification in two of three
consumer paths (attestation.py, cli.py) - an unauthenticated forged
head at the pinned size could poison a consumer's pin forever and
pollute the equivocation-evidence pair with an unverifiable head,
contradicting SS5.4's 'validly signed' precondition and Prop 1.
Both paths now gate the store on a verified Ed25519 head signature
(logclient.py already did). Regression test added.
- Prop 2 made literally true: _normalize_certificate now derives the
cleanliness verdict purely from (observed cone, local allowed set) in
EVERY branch; the operator's axiom_status label is never copied (was
passed through for non-proven certs), missing cone => unverifiable
always. Labels can deny, never grant. Test added.
- webdocs: '/v1/sth-history: every head ever signed' -> 'the published
head history'.
PAPER (claims brought down to reality):
- 'every head ever signed' -> the signed head history since publication
began (heads for sizes 1-7 predate the mirror and were not retained).
- Run-3 bullet: 'independently checkable by diffing the two commit
trees' was no longer reproducible (pre-rewrite objects discarded);
now states the log-internal corroboration (identical cert lists and
cones across leaves 4-7 vs 8-11) and that tree diffs are not public.
- Appendix A leaf block now actually verbatim: scheme
openssl-ed25519, verified_backend serial/u64, real Lean version
(4.30.0-rc2) instead of 4.x.y placeholder, leaf's actual axiom order
(finalize/new/update), machine_protection note quoted, elisions
marked; preamble wording matches.
- Appendix C upstream boundary reordered to check.sh's verbatim order.
- '27 lines - all annotation' -> honest description (axiom-list entries
+ operation reordering from one fork's black_box barrier).
- Prop 2 proof + App A: status label consulted only negatively.
- SS7: provenance fields noted as outside the signed payload; consumer
chain relies on none of them.
- Bibliography: all 20 entries verified against DBLP/RFC-editor - zero
errors; added missing page numbers to 6 entries; thebibliography
width 19->20. All URLs verified public; no PlanetMacro leakage.
17 pages, 106 tests green, accumulator untouched (tree_size 12).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Re-auditing the prior (Opus-produced) depth pass adversarially found and
fixed three genuine issues:
1. OVERCLAIM (serious): §5.3 said the consistency verifier was
differential-tested 'on all (n0,n1) with n1<=256' but the script only
SAMPLED sizes (5,508 cases). Ran the genuinely exhaustive test — all
1<=n0<=n1<=256, honest + 4 mutations — 164,224 invocations, and the
inclusion verifier likewise (164,479). Paper now states the true scope
and counts; both are pinned in a new CI test (test_paper_verifiers.py,
104 tests) so the numbers cannot rot.
2. PROOF IMPRECISION: Lemma 2 (Root binding) was applied to ConsRec's
first component, which PASSES THROUGH (no hnode) at some levels and so
is not the hash-fold the lemma needs. Reworked: Lemma 2 now defined
over 'hash-folds' only; Theorem 3 restructured into 3 clean steps that
put only the full-hashing second component through the lemma, then
argue algebraically + one honest-tree collision. Also hoisted Lemma 2
above Theorem 2 and made Theorem 2 invoke it (was inlined), so the
'two theorems share the lemma' remark is now true; deduped the remark.
3. MISLABELED TABLE: Table 1's 'files vs upstream' column actually held
line-diffs against different baselines. Dropped it for clean comparable
columns (files / apex axioms / SHA-512 shape); the diff story stays in
the portability paragraph where each baseline is named.
17 pages, all refs resolve, 104 tests green.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Removal (user decision): paper/ltl-v0.0.{tex,pdf} deleted; /paper/v0.0
route removed; test now asserts 404 for it; /paper/v0.1 stays for
citability and is linked from the docs card.
Audit findings from re-reviewing the last session's work, all fixed:
- Appendix A claimed 'all other fields are verbatim' over elided
placeholder values - reworded to state exactly what is elided vs
verbatim (a paper about exactness cannot say verbatim over an ellipsis)
- LTL docs paper card still described the 4-page v1 (old title, old
scope) - now the revised title, 14 pages, proofs summary, v0.1 link
- llms.txt paper line updated to the revised title
- paper/eprint-submission.md rewritten as the RESUBMISSION kit: new
title/abstract, message-to-editors change note, form-not-email
guidance, author-only checklist
102 tests green.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Paper:
- v2 (12->14pp: appendices) promoted to paper/ltl.tex; v1 kept as
ltl-v0.1.tex, pseudonymous variant as ltl-v0.0.tex (identity-clean)
- filled from verified artifacts: App C (3 verbatim per-fork boundaries:
dalek 11 / hash3 8 / anza 7), App D (real 4-tier ladder + parser
hypotheses; the other agent's 'Tier 3/4' guess corrected), App A (real
leaf 8 structure); §8 now twelve leaves / three runs incl. the
history-rewrite absorption (a live G2 demonstration); §7 self-check
index 4->8; Limitations count fixed; two overfull math displays fixed
- title/author/ORCID unchanged from the revision
Hosting: web.py serves /paper (current), /paper/v0.1 (prior named),
/paper/v0.0 (pseudonymous) - older versions unlisted in the endpoint
index; test added.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Makes the paper's pin-store safety proposition true in the deployed code:
- the full signed STH is retained at pin and at each advance (not just
size+root), so on equivocation both conflicting heads are transferable,
signature-verifiable evidence;
- any equivocation (same-size root mismatch, or a consistency anchor
disagreeing with the pin) persists poisoned=true with both signed
heads and refuses ALL further operations for that log, restart-proof
and independent of the update flag;
- rollback unchanged. 102 tests (was 100): poison persistence, evidence
transferability, full-head retention.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Consolidates the consumer-side trust framing that was scattered across
notebooks 05/06b and WALLET.md into one on-ramp: the allowed-axioms list
as a requirements card you own and can write yourself; measurement vs
publication vs judgment (operator/log/you); the three honest outcomes
when your card is stricter than the supply (relax itemized / walk away /
grow the supply). Executable: a self-written card is shown to equal the
real APEX_BOUNDARIES cone exactly (supply == wish: True), and a strict
no-oracle card is REFUSED with the real SHA-512/wire gap itemized.
Registered in course map + notebook test; 101 tests green.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Generic mechanism: bare-name PDFs placed in the log directory's site/
folder are served by name, checked LAST in the route chain (can never
shadow an API route), traversal-safe, noindex, and deliberately absent
from the endpoint index and the docs page - the operator decides who
receives a link. Tested: serve, unlisted-in-404, traversal rejected.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The provider public key is the one thing a consumer takes on trust;
hiding it behind /log-public-key inverted the page's priorities. New
'The trust anchor - pin this key' section at the top of the docs page
shows the PEM in full with its SHA-256 fingerprint, the mirror-compare
instruction, and the raw endpoint for scripts. Honest 'missing' card if
a deployment lacks the key. Test asserts the page renders the key.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Socratic audit findings, all verified against artifacts:
- 'zero lines between structurally identical forks' was FALSE: risc0 vs
betrusted differ by 27 lines (all annotation, documenting the risc0
fork's black_box trusted-base entry). Corrected to the true number.
- '~64 Lean files per fork' over-rounded anza's 58. Now '58-64'.
- completeness parenthetical now states both hypotheses (a=-1 square, d
non-square), not just d.
- 'key published in two independent locations' was ASPIRATIONAL: the
site served only a fingerprint. New /log-public-key endpoint serves
the key bytes; docs-page artifact-1 row links both copies; test added.
Verified exactly and kept: 215-line parser diff (FromBytesSpec), 121-line
signature-glue diff (SigApexSpec), byte-identical x4 math files incl. the
carry-telescope file, 11-axiom upstream boundary, 16 certs/leaf, 153-line
mirror verifier, leaf fields (toolchain + machine_protection), all 17 refs.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Correctness:
- ledger: single-flight fcntl lock over read-modify-append + fsync. Two
concurrent writers previously could fork the hash chain (read same tail,
same prev_hash). New test races 8 threads x6 appends; chain stays intact
with contiguous indices.
- small-order list: the order-8 encodings were hand-typed and unverifiable
and diverged from the canonical libsodium blocklist. A BOGUS entry is the
only dangerous direction (it down-grades a real tamper to a note, skipping
the latch), so the list is now the certain-low-order set only (y in
{0,1,-1}, reduced/non-reduced, both sign bits); order-8 edges escalate to
tamper until a derived list lands. Fail-safe asymmetry documented + tested.
- freshness: removed a tautological .
Non-functional:
- quorum members now run concurrently (ThreadPoolExecutor): a verify costs
one member's latency, not the sum (~17ms for 4 members, live).
- Wallet.quorum() memoized per state_dir: binary swap-detection hashes run
once at assembly, not on every verify; documented rationale.
85 tests green; live 4-fork wallet re-verified end-to-end.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- web.py: /paper (and /paper/ltl.pdf) serve the committed PDF, loaded
once at startup from the repo checkout; listed in the 404 endpoint
index; covered by the web roundtrip test
- docs page: 'The paper' card linking the PDF
- DEPLOY.md: the second witness mirror belongs on a host the operator
does NOT control (a self-hosted mirror adds no equivocation defense)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- serve/webdocs/cli default to base_path='' (own subdomain, root serving)
- webdocs link builder handles the empty base like web.py already did
- all docs, paper, notebook 06b, and published-mirror README point at
https://ltl.zkdefi.org; DEPLOY.md rewritten for subdomain + redirect
- tests: root mount is the production shape; one test keeps exercising
the path-mounted variant
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Three synchronized faces of one log - transport orthogonal to trust:
- PUBLISHED GIT MIRROR: log-publish exports the public face (one file
per leaf so git history mirrors log history; the FULL STH history as
the witness channel; per-component attestations + receipts; the
provider public key; a standalone stdlib-only verify.py and customer
README). Live at github.com/saymrwulf/lean-transparency-log (genesis:
8 leaves incl. the honest failed-run entries, dogfood-signed head).
- ONLINE SERVICE (pacta_provider serve): read-only, zero-dependency
HTTP with CT-style endpoints under a base path for
zkdefi.org/lean-transparency-log - /v1/sth, /v1/sth-history,
/v1/sth-consistency?first=N, /v1/proof, /v1/attestation, /v1/entries,
/v1/metadata, /healthz - plus self-contained customer documentation
at /docs (current state, attested components, API, the verify-
without-trusting-this-site path, and the means/does-NOT-mean
boundary). The process never loads private keys: heads are signed
offline; a compromised server can withhold or replay (pinning +
freshness detect both) but never forge. STH history now recorded
append-only by the provider (with a backfill head signed for the
existing log).
- AGENT ONLINE CLIENT: pacta log-fetch (download evidence; explicitly
UNVERIFIED until receipt-verify runs - transport is not trust) and
pacta sth-refresh (fetch head, verify signature, advance the pin via
an online consistency proof from the pinned size; fail closed).
- WITNESSES: pacta witness-audit over a clone of the published mirror
recomputes every prefix root from the public leaves and checks every
historical head + signature - no consistency proofs needed when the
leaves are public. Tampering one published entry trips both the
leaf-hash check and the prefix-root check (tested). verify.py gives
customers the same audit with zero installation.
- DEPLOY.md: the complete server-session checklist for zkdefi.org -
reconstruct the servable log FROM the published mirror (the server
stays in witness trust-position), hardened systemd unit, nginx/Caddy
path routing, Forgejo mirror setup, the provider->world update
cycle, and remote smoke tests.
Validated end-to-end on the REAL log: all 10 endpoints, online-fetched
proof re-verified locally through the dogfood verifier with pinning,
online pin refresh, publish + witness audit green, tamper caught,
standalone verify.py green in the published clone. 54/54 tests.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The trust architecture has exactly two roles and the curriculum now
mirrors that split structurally - the conceptual burden is the design,
stated as such to the student:
- 06a THE PROVIDER'S SIDE (singleton). Domain banner in the provider's
voice. The full build pipeline run live in a scratch log made from
the REAL attestations: verify (Lean replay = the leaf-making step,
the only expensive one - the shipped evidence IS its output) -> leaf
(0x00 domain separation) -> tree -> STH signed via the MERKLEIZED
LIBRARY -> the self-inclusion check embedded in the signature block.
A generated SVG draws the student's own tree: leaves, internal
nodes, root, and the signature box, framed in the provider's domain
color. Closes with the singleton-vs-many justification table
(key/cost/obligation asymmetry) and exercises.
- 06b THE AGENT'S SIDE (one of many). Domain banner in the agent's
voice: you own the public key, the evidence files, ~25 lines of
hashing - and explicitly NO Lean. The COMPLETE RFC 9162 inclusion
verifier is implemented from scratch in one cell (hashlib only, no
pacta imports for the core) and run against the REAL dalek receipt
(leaf 4 of 8, three siblings, dogfood-signed root); then the STH
signature, the provider's signing_provenance read and interpreted
(why the agent still re-checks inclusion itself), the pin store, and
an SVG of the real log with the agent's path highlighted against the
grey leaves it never needs. Cost line: ~4 hashes + 1 signature.
- Lecture 06 now routes students into the pair and states the mirror
rule ("if you cannot say which notebook a step belongs to, you have
not understood the step"); lecture 09 records that dogfood now runs
in BOTH directions; course map + README updated.
Every cell of 06a/06b/09 executed against the real evidence before
commit (SVGs render in Jupyter, fail soft in plain exec). One
generation bug found and fixed: a single-backslash \\x00 in the
generator produced a literal NUL byte in a cell. 50/50 tests green
with the notebook inventory at twelve.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The dogfood principle now runs in BOTH directions. Agents already
verified signatures through the proven dalek path; now the provider
SIGNS with it too, and proves to itself that the signing code is in its
own log before every signature:
- dogfood binary gains a `sign` mode (seed over stdin, never argv;
ed25519_dalek::SigningKey from the same pinned merkleized workspace).
Honesty ledger unchanged: the library's VERIFY path is
certificate-covered; its signing path is declared trusted base - but
it is the ATTESTED artifact, not an un-attested third implementation.
- sign_payload_ed25519_detailed: signing dispatch mirroring the verify
dispatch; the backend that actually signed is recorded in every
attestation signature block and STH.
- THE SELF-REFERENTIAL CHECK: before signing any tree head, the
provider runs the SAME Merkle inclusion verification an agent runs -
against the very tree it is about to sign - for the newest leaf
attesting the signing library itself, and embeds the result in the
signature block:
signing_provenance:
signing_backend: verified-dalek-serial
signing_library_component: dalek-ed25519-verified
signing_library_source_commit: aa0f6ab...
self_inclusion: verified
signing_library_leaf_index: 4
signing_library_certificates_proven: 16/16
A root signature that names the leaf vouching for the code that
produced it. First-append chicken-and-egg is handled honestly
(self_inclusion: library_not_in_log).
- Evidence refreshed: all four receipts re-issued under dogfood-signed
STHs; the full agent verify loop re-run green.
50/50 tests (new signing roundtrip test, skip-safe where unbuilt).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The notebooks now carry the same didactic contract as the companion book
(the "ratchet rule", stated in the course map): every load-bearing idea
runs twice - napkin scale, then real scale - and every pair is EXECUTABLE
in the notebook, not narrated.
- Lecture 1: the truth boundary updated to the proven four-tier apex,
with the what-is-still-NOT-proven list (SHA-512, parsers, signing,
wallets) given equal weight.
- Lecture 2: napkin/real scoring pair - a two-certificate toy card
scored in your head, then the shipped sixteen-certificate R4 fixture
through the same function, residual blockers and per-tier boundary
axioms printed.
- Lecture 6: new split-view section. A runnable equivocation drill:
pin a two-leaf view, grow it honestly with a consistency proof, then
present a forged same-size root and watch the pin store name the
attack. Real-scale pointers to --sth-store, log-consistency,
log-audit, and the freshness policy; a new exercise asks students to
construct the lie a size-only anchor check would miss.
- Lecture 7: the wallet gate now swings BOTH ways on real evidence -
a partial card denied at R3, the shipped R4 card allowed - both
runnable.
- Lecture 8 capstone: "design R4" became "audit R4": read the shipped
card like an auditor, then design the R5 discharge plan (parser
specs, verified SHA-512, signing-side, per-fork production-path
mapping).
- NEW Lecture 9, "Eat Your Own Dogfood": the honest coverage ledger of
the proven-path verifier; a napkin PEM decode (the fixed 12-byte
Ed25519 SPKI prefix, read with your eyes) paired with the mechanical
extraction; live backend dispatch; the fail-closed
--require-verified-verifier policy; and the hybrid-PQC section -
proven-classical Ed25519 plus a required-but-honest ML-DSA slot
("blockers get fixed; placeholders get trusted").
Every code cell of the changed notebooks was executed end-to-end before
committing (outputs stripped per house rules). 49/49 tests green with
the notebook inventory updated.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
"Eat your own dogfood": pacta consumes certificates about a verified
Ed25519 implementation while checking those certificates' signatures
with OpenSSL. Now it can use the object of its own evidence:
- dogfood/pacta-verified-verify: a ~90-line Rust binary built against
the PINNED proven source workspace (saymrwulf/curve25519-dalek-source
at the exact commit the dalek certificates pin - the build records it:
aa0f6ab...) with the serial backend pinned via RUSTFLAGS exactly as
the verified extraction pins it. Cargo.toml is committed as a template
({{SOURCE}} placeholder) so no machine path is hardcoded; the rendered
file, target/, and the built binary are gitignored.
- pacta dogfood-build --source <workspace>: renders, builds, installs
to dogfood/state/, and writes a provenance sidecar (source commit,
backend cfg, rustc, and an honest coverage note: the certificates
cover verify_sha512, the extraction-refactored image of this verify
path; SHA-512 and the wire glue remain the theorems' documented
boundary). pacta dogfood-status reports the active backend.
- signing.verify_payload_ed25519_detailed: dispatch - the dogfood
binary when present (backend "verified-dalek-serial"), OpenSSL
fallback otherwise, and the backend that ACTUALLY ran is recorded in
receipt signature statuses and attestation evidence. Fallback is
never silent.
- --require-verified-verifier (receipt-verify + agent): policy fails
closed when verification did not run on the certificate-covered
path.
- ML-DSA is deliberately unchanged: no proven implementation exists,
so the slot stays fail-closed "unavailable" - the honest hybrid-PQC
posture is one proven-classical signature plus one required-but-
unproven PQC slot, never a pretend backend.
Validated live: receipt verification through the proven verifier
(backend recorded), a corrupted signature bit rejected BY the proven
binary, tampered attestations rejected, and the policy failing closed
when the binary is absent. 49/49 tests green (incl. PEM-SPKI raw-key
cross-check against openssl, dispatch/backend recording with a stub,
and a real-binary roundtrip that skips gracefully where unbuilt).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
A transparency log without split-view defense is just a signature with
extra steps: the provider could serve one tree to the agent and another
to the world, or roll the log back, and standalone receipt verification
would never notice. The primitives (RFC 9162 consistency proofs) were
already implemented and correct; this closes the loop on the AGENT side.
- src/pacta/sthstore.py: a local STH pin store. Unknown log -> pin
(trust-on-first-use, recorded as such). Same tree size -> the root
must match the pin byte-for-byte; a mismatch is named EQUIVOCATION
and is a hard rejection. Larger tree -> a consistency proof FROM THE
PINNED SIZE is required and verified before the pin advances
(receipts already embed a from-previous anchor; the anchor's root is
itself checked against the pin so a lying anchor cannot bridge a
split view). Smaller tree -> LOG ROLLBACK, hard rejection.
- Freshness policy: --max-sth-age-seconds rejects stale (or
future-dated) tree heads - an old-but-valid STH can hide later
entries.
- Wired into receipt-verify, claims, and agent (--sth-store,
--consistency-proof, --max-sth-age-seconds); evidence records the
pin action; any accountability failure fails the receipt closed.
- Provider: log-consistency --from-size N (serve proofs for pinning
agents whose pin is older than the receipt's embedded anchor) and
log-audit (monitor self-check: recompute the tree, verify the stored
STH and per-entry leaf hashes).
Live drill in this commit's validation: pin-on-first-use -> matched ->
grown-with-proof advance -> a real forged same-size split view REJECTED
with the equivocation diagnostic -> freshness rejection -> clean
self-audit. tests/test_sthstore.py covers pin/match/equivocation,
growth-without-proof, lying consistency anchors, rollback, freshness.
45/45 tests green.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The verified corpus completed its phase 2 on 2026-07-06: every ed25519
fork now carries FOUR button-enforced apex tiers up to the full lift
(accept <=> decompress(R) = [k](-A)+[s]B as points), the complete scalar
layer, and the constructive encoding/decoding chain. pacta was calibrated
to the pre-apex corpus and - worse - had no vocabulary for
boundary-audited certificates: its axiom audit knew only "clean = exactly
the three standard axioms", so the apex tiers would have scored dirty.
New vocabulary:
- Profile.certificate_axioms: per-certificate ALLOWED axiom sets;
expected_axioms_for(cert) resolves each certificate's own boundary.
- RepoConfig.apex_boundary: a simple per-fork key (dalek-wrappers /
hash3 / anza) expanded by the ed25519 profile into the exact
per-tier allowed sets. AUTHORITY NOTE in profiles/ed25519.py: each
repo's check.sh Phase 3b is the enforcement point; if the button and
this table disagree, the button wins.
- run_axiom_audit compares each certificate against ITS allowed set;
deviation in EITHER direction (extra axiom or missing boundary
axiom) is dirty.
New risk reality:
- R4 is now reachable: full four-tier apex + constructive chain +
scalar arithmetic, all proven with cones pinned to their documented
boundaries. R4 always carries explicit residual blockers (SHA-512
oracle, hypothesis-parametric wire parses, translation faithfulness,
no side-channel/build assurance - those gate R5).
- R3 unchanged (arithmetic pair) and now explains exactly which apex
certificates are missing for R4.
Attestation trust model hardened:
- The provider is trusted for its OBSERVATION, never its VERDICT:
axiom_status is re-derived locally from observed_axioms against the
agent's own boundary policy. A provider that labels a dirty cone
"clean" gains nothing; "proven" with no observed axioms is
"unverifiable".
- Partial attestations degrade instead of being rejected: uncovered
certificates stay unproven and the score caps accordingly (an
arithmetic-only attestation still authorizes an R3 library capsule,
never a wallet).
Also: scripts/mini_pytest.py - a dependency-free test runner (tmp_path,
raises, monkeypatch, capsys) for hosts without pytest; examples
regenerated FROM the tool (dalek/anza fixtures now R4, 16 certs; new
full four-tier attestation example); tests updated + new
tests/test_boundaries.py (lying-provider, missing-boundary-axiom,
partial-coverage cases). 40/40 tests green.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>