Skip to content

Slice 024: Effect catalog, authority selection, local receipts - #36

Merged
HackTuah merged 19 commits into
mainfrom
slice/024-effects-authority-receipts
Sep 20, 2026
Merged

HackTuah merged 19 commits into
mainfrom
slice/024-effects-authority-receipts

Conversation

@HackTuah

Copy link
Copy Markdown
Member

The membrane, the authority and the receipts. Every tool call is decided once by the gate and receipted before anything runs; reads run directly with a query receipt; everything else is a staged effect that Trinity.Effects.execute/2 admits or denies with a receipt (decision, effect class and catalog, the fingerprint re-derived, the idempotency key, the authority in force). Trinity.Authority.Local is the one caller of execute/2 for effectful tools, held by a census over git ls-files with a planted bypass. TRINITY_AUTHORITY is read once at boot and refuses by name.

Receipts: per-scope hash chains in their own database (synchronous: :full), signed through the signer seam (Ed25519; P-384 in FIPS mode, proven on the fips leg; ML-DSA-87 by configuration where the runtime has it) over DSSE's PAE with the scheme as payload type; RFC 7638 key ids; an append-only registry the verifier reads the algorithm from; RFC 5848-shaped checkpoints over query receipts; a verifier with the exit vocabulary 0/1/2/5/6 and a standalone copy that runs from an empty directory with elixir alone; a receipts page per session and the boot receipt's page. Design checked against DSSE, RFC 8725, RFC 7638, RFC 5848, C2SP and FIPS 186-5 (NOTES.md, research).

PROOF.md at slices/024-effect-catalog-authority-modes-receipts/PROOF.md. Also carried: fix(s021) for the Session dropping a decision made while its tools still ran (the decision receipt widened a window 003's close had already seen once).

Signed-off-by: Ayla Croft aylacroft@proton.me

…he slice opens

ROADMAP row 024 to in_progress. NOTES.md records the signing costs of
Ed25519, P-384 and ML-DSA-87 on this machine and on the 003 image (DER
sizes, not the table's 96), the exqlite insert costs that set the
receipts file to synchronous full and the query checkpoint at N=100 or
T=5 s, the signed field set proposed for the R21 review with the
default the slice names, the ten-line build plan, the empty manual
queue, and four deviations stated before any code. plan_check: PASS.

Signed-off-by: Ayla Croft <aylacroft@proton.me>
…5848, C2SP and FIPS 186-5; five G1 amendments

A DSSE-style PAE with the scheme as payload type (one key will sign
two protocols); the verifier's allowed-algorithm set and the one key,
one algorithm rule from RFC 8725; key ids as RFC 7638 thumbprints;
checkpoints shaped like RFC 5848 signature blocks with their coverage
and the boot they belong to; C2SP's unknown-key and consistency rules
as the verifier's and the writer's tests. The linear chain stays, with
the Merkle upgrade path recorded, and the P-384 selection stays, with
FIPS 186-5's approval of EdDSA noted as OTP's limit rather than the
standard's.

Signed-off-by: Ayla Croft <aylacroft@proton.me>
…and the registry

Trinity.Repo.Receipts starts in every environment with its own file
(synchronous full, its own migrations under priv/repo_receipts, its
own migrations table on Postgres); the receipts and
receipt_checkpoints tables. Trinity.Receipts.Signer with Ed25519,
P384 and MLDSA87; Envelope (RFC 8785 body, DSSE PAE with the scheme
as payload type); KeyRegistry (append-only rows, the newest per key id
in force); KeyCustody (P-384 when info_fips is enabled, Ed25519
otherwise, ML-DSA-87 by configuration where the runtime has it; the
key file 0600 under the keys directory, read on every sign; RFC 7638
thumbprints as key ids). Tests: 10 in signer_test.exs, the repo config
test's 010 slot assertion superseded.

Signed-off-by: Ayla Croft <aylacroft@proton.me>
…d Local, the boot receipt, the verifier

Trinity.Receipts.ChainWriter: one temporary process per scope under
Trinity.Receipts.WriterSupervisor, appends as calls, per-row signing
for decision, effect, boot and cap, unsigned chained query rows
covered by receipt_checkpoints rows (count, time, shutdown,
rehydrate), a tail or checkpoint that does not verify stops the writer
with the reason. Trinity.Receipts facade (append, list, export, the
boot hash), Alarm (:alarm_handler and telemetry), the insert census
with a planted bypass in test support. Trinity.Authority (stage,
decide, execute, receipt), Local (the one execute/2 caller for
effectful tools), Staged, Selection as a supervised child that refuses
the boot by name. Trinity.Effects.Boot writes the boot receipt.
Trinity.Receipts.Verifier walks an export. The effect catalog moves
to Trinity.Tools.Catalog (deviation e: Effects depends on Tools).
Suite: 287 passed.

Signed-off-by: Ayla Croft <aylacroft@proton.me>
…andalone script

verifier_test.exs: 1,000 mixed receipts verify with their checkpoints;
a flipped byte in any signed_payload is 1; an unknown key id 5; a
compromised key 6; a gap, a wrong prev_hash and a forged signature are
1; the algorithm comes from the registry row (a body claiming P-384
under an Ed25519 key is refused for the family, before any signature
check); a P-384 receipt presented to a verifier told to accept only
Ed25519 is refused at the scheme string. mix trinity.receipts.export
and mix trinity.receipts.verify with the exit vocabulary.
bin/verify_receipt.exs: elixir and :crypto only, run from an empty
directory by its test, and an agreement test over six variants
against the in-app verifier.

Signed-off-by: Ayla Croft <aylacroft@proton.me>
… start failure, the standalone assertion under local

Signed-off-by: Ayla Croft <aylacroft@proton.me>
…oned, not dropped

The gate broadcasts the request from inside the runner, before the
runner returns, so an owner can decide before the Session has entered
approval_wait; the catch-all clause dropped that decision and the
Session waited for one that had happened. Seen once by chance at slice
003's close (its NOTES finding 11, session_flow_test.exs:108) and on
every run once slice 024's decision receipt widened the window from
microseconds to a fsync. In tool_wait the decided event is postponed;
gen_statem redelivers it on entering approval_wait.

Signed-off-by: Ayla Croft <aylacroft@proton.me>
…or on Tools.Runner

Trinity.Effects.execute/2 over a Staged effect: denies with a receipt
when the decision is not allow, the effect class is not admitted or a
catalog tool is not in the catalog, the fingerprint re-derived from the
arguments it holds is not the one the decision bound, or an effect
receipt already names the session and call id; then the authority
stages and decides, the admission receipt is written (a signer that
cannot sign denies, with the alarm), the authority executes, and the
outcome receipt follows. Trinity.Effects.Runner is the tool runner in
force: it decides through Tools.Runner.decide/3, receipts every
decision, runs effect: :none calls directly with a query receipt and
sends the rest through the membrane. Tools.Runner takes the executor
as a function; its own call_tool/3 refuses an effectful entry by name.
Context carries call_id. Suite: 300 passed.

Signed-off-by: Ayla Croft <aylacroft@proton.me>
… every decision and effect receipted, the M2 re-verify, the idempotency key, the catalog and decision checks, the key removed mid-run, Local's callbacks

Signed-off-by: Ayla Croft <aylacroft@proton.me>
…pt's tests (AC6)

Signed-off-by: Ayla Croft <aylacroft@proton.me>
…t, with verify

TrinityWeb.ReceiptsLive at /s/:id/receipts and /receipts/boot: the
rows in seq order with kind, subject, decision, signed or
checkpointed, hash prefix; the checkpoints; a verify button running
the verifier over the scope's export with the exit code shown. The
chat's bar links to its session's receipts. Four LiveView tests.

Signed-off-by: Ayla Croft <aylacroft@proton.me>
…ripped beams; mode-aware assertions

test/fips/receipts_test.exs (tagged :fips): the mode on, Ed25519
unavailable, P-384 selected, the boot receipt naming it, an effect
running with P-384 receipts that verify and are refused at the scheme
string by an Ed25519-only verifier. CorePolicy hashes beams stripped
of debug info and docs: the debug-info chunk renders a large map
literal in an order that depends on the compiling VM's atom table, so
the boundary test's forced recompile changed the hash mid-suite. The
signer, chain writer, boot receipt and 012 unit tests derive their
expectations from the selection instead of naming Ed25519. Suite:
317 passed, three runs.

Signed-off-by: Ayla Croft <aylacroft@proton.me>
Signed-off-by: Ayla Croft <aylacroft@proton.me>
Flatter functions in the chain writer, the verifier, the authority and
the runner; the authority selection makes no atom from the
environment's text (String.to_existing_atom, an absent module reported
by its text); inline sobelow skips with their reasons on the key
custody and registry file operations, whose paths are the keys
directory plus constants. Gate exit 0: 317 passed, credo and sobelow
clean, plan_check PASS.

Signed-off-by: Ayla Croft <aylacroft@proton.me>
…ion names the owner

Run 35542450360: the fips leg selects P-384 and the signer, boot and
chain tests named Ed25519 (the earlier edit never landed); the peer
assertion found a TLS connection on the runners this machine does not
open and said nothing about its owner.

Signed-off-by: Ayla Croft <aylacroft@proton.me>
…ign one from the selection; the peer assertion describes the owner

Signed-off-by: Ayla Croft <aylacroft@proton.me>
…cation's processes

Run 35542784455: on the hosted runners Mix's Hex client holds a TLS
connection to hex.pm in the suite's VM (Cloudflare addresses, port
443, opened before the application, no Trinity ancestor); this
machine's warm cache never opens one. The census asks about Trinity's
connections: owners are resolved with :application.get_application/1
and only :trinity's must be the database's.

Signed-off-by: Ayla Croft <aylacroft@proton.me>
…local receipts)

PROOF.md with every criterion's evidence by test name against run
35542904049 (gate, postgres and fips green; the FIPS half of AC8 on the
leg: P-384 selected, the boot receipt naming it, an effect running
with P-384 receipts that verify). NOTES.md: fourteen findings, four
more deviations, follow-ups for 002, 026, 061, 090 and 100. ROADMAP
row 024 to done; coverage.tsv row 76.55 %. Gate exit 0 here: 317
passed, 17 excluded, plan_check PASS.

Signed-off-by: Ayla Croft <aylacroft@proton.me>
Signed-off-by: Ayla Croft <aylacroft@proton.me>
@HackTuah
HackTuah merged commit 8173516 into main Sep 20, 2026
8 checks passed
@HackTuah
HackTuah deleted the slice/024-effects-authority-receipts branch September 20, 2026 23:23
@HackTuah HackTuah mentioned this pull request Sep 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant