defmodule VavPipeline.LedgerL3Test do @moduledoc "The ledger over L3: a key reads its own bedikot back, signed, and no one else's (2026-10-21)." use ExUnit.Case, async: false import Plug.Test import Plug.Conn alias VavPipeline.BigdeiKodesh.Router alias VavPipeline.L3.Store @opts Router.init([]) @moduletag :l3 setup do :ok = Ecto.Adapters.SQL.Sandbox.checkout(VavPipeline.Repo) Ecto.Adapters.SQL.Sandbox.mode(VavPipeline.Repo, {:shared, self()}) on_exit(fn -> Ecto.Adapters.SQL.Sandbox.mode(VavPipeline.Repo, :manual) end) write_provision() :ok end defp write_provision do VavPipeline.MannaLedger.reset() on_exit(fn -> VavPipeline.MannaLedger.reset() end) today = Date.utc_today() |> Date.to_iso8601() expires = DateTime.utc_now() |> DateTime.add(6 * 3600) |> DateTime.to_iso8601() provision = %{"date" => today, "provision" => %{"compute_units" => 50, "memory_mb" => 512, "api_calls_external" => 10, "storage_delta_mb" => 2, "sanhedrin_panels_max" => 2}, "type" => "regular", "expires_at" => expires, "written_by" => "ledger_l3_test", "written_at" => DateTime.utc_now() |> DateTime.to_iso8601()} path = VavPipeline.Manna.provision_file() File.mkdir_p!(Path.dirname(path)) File.write!(path, Jason.encode!(provision)) on_exit(fn -> File.rm(path) end) end defp attrs(ref, key_id) do %{ bedikah_ref: ref, provenance: "claude", query: "q", output_sha256: String.duplicate("cd", 32), output_length: 5, vital_content: "", verdict: "empty", examined_at: DateTime.utc_now() |> DateTime.truncate(:second), key_id: key_id } end defp get(path, token) do conn(:get, path) |> put_req_header("authorization", "Bearer #{token}") |> Router.call(@opts) end # An examination the offering protocol finds nothing in: the :empty branch, no engine needed. defp empty_examination do %{"provenance" => "claude", "query" => "status?", "vital_content" => "", "propositions" => [], "discarded" => ["Rolled out."], "references" => [], "hebrew" => [], "roots" => [], "authority_claims" => [], "actions" => [], "self_validation" => [], "self_promotion" => [], "excluded_adversarial" => [], "frames" => [], "sources" => [], "claims" => []} end test "the record keeps the key's digest, and the ledger lists only that key's records, newest first" do mine = VavPipeline.Ledger.key_id("test-token") other = VavPipeline.Ledger.key_id("someone-else") {:ok, _} = Store.record_bedikah(attrs("bedikah-l3aaaa0000000001", mine)) {:ok, _} = Store.record_bedikah(attrs("bedikah-l3aaaa0000000002", mine)) {:ok, _} = Store.record_bedikah(attrs("bedikah-l3bbbb0000000003", other)) {:ok, _} = Store.record_bedikah(attrs("bedikah-l3cccc0000000004", nil)) refs = Store.list_bedikot(mine) |> Enum.map(& &1.bedikah_ref) assert refs == ["bedikah-l3aaaa0000000002", "bedikah-l3aaaa0000000001"] conn = get("/courtyard/ledger?limit=10", "test-token") assert conn.status == 200 body = Jason.decode!(conn.resp_body) assert body["key_id"] == mine assert body["count"] == 2 assert Enum.map(body["entries"], & &1["entry"]["bedikah_ref"]) == ["bedikah-l3aaaa0000000002", "bedikah-l3aaaa0000000001"] # never the text, never the key, never the owner column e = hd(body["entries"])["entry"] refute Map.has_key?(e, "key_id") assert e["output_sha256"] == String.duplicate("cd", 32) assert hd(body["entries"])["signed"] == false end test "one record by ref: mine answers, another key's and a missing one answer 404 alike" do mine = VavPipeline.Ledger.key_id("test-token") {:ok, _} = Store.record_bedikah(attrs("bedikah-l3dddd0000000005", mine)) {:ok, _} = Store.record_bedikah(attrs("bedikah-l3eeee0000000006", VavPipeline.Ledger.key_id("someone-else"))) assert get("/courtyard/bedikah/bedikah-l3dddd0000000005", "test-token").status == 200 assert get("/courtyard/bedikah/bedikah-l3eeee0000000006", "test-token").status == 404 assert get("/courtyard/bedikah/bedikah-l3ffff0000000007", "test-token").status == 404 end test "an examination is engraved under the caller's key and reads back signed and verifiable" do Application.put_env(:vav_pipeline, :ledger_signing_key, Base.encode64(:crypto.strong_rand_bytes(32))) mine = VavPipeline.Ledger.key_id("test-token") try do examiner = fn _o, _p, _q, _s -> {:ok, empty_examination()} end assert {:ok, r} = VavPipeline.Bedikah.examine("Rolled out.", "claude", "status?", examiner: examiner, key_id: mine) assert r.verdict == :empty assert Store.get_bedikah(r.bedikah_ref).key_id == mine back = get("/courtyard/bedikah/#{r.bedikah_ref}", "test-token") assert back.status == 200 body = Jason.decode!(back.resp_body) assert body["signed"] == true pub = Jason.decode!(get("/peah/ledger_key", "x").resp_body)["public_key"] canonical = VavPipeline.Ledger.canonical(body["entry"]) assert :crypto.hash(:sha256, canonical) |> Base.encode16(case: :lower) == body["canonical_sha256"] assert VavPipeline.Ledger.verify(canonical, body["signature"], pub) after Application.delete_env(:vav_pipeline, :ledger_signing_key) end end end