Two real forms, end to end
Two forms of the pre-registered random 300, followed from the request to the receipt: 080310B0100, which the gate accepted, and 122655C0100, which the gate routed to a person because the arithmetic refused a misread. Vote rows are Option NN. Generated by scripts/build_trace.py from stored data (no model call), checked by make eval; the same trace as docs/TRACE.md.
The request (the same for both forms)
| model | Gemma-4-31B-IT run record (results/calls_gemma.jsonl) |
| endpoint | AMD Token Factory, OpenAI-compatible POST /chat/completions the key comes from the environment and is never stored |
| prompt sha256 | 3664253035b912184e24a205852e7b8e686f0abb36a4340e91834d60dc71193f run record; rebuilt from twohands/reader.py: the same |
| temperature | 0 |
| max_tokens | 2000 |
| response_format | none |
| images sent | 7: the masked page, then 6 masked tiles (left_column, party_rows, coalition_rows, bottom_rows_sec7, party_logos, coalition_logos); JPEG, longest side at most 2400 px, quality 88 |
| image tokens billed | 1,843 per form |
(a) Accepted: form 080310B0100, Unused ballots
1. The photo
The exact crop bytes the receipt hashes: /crop/080310B0100/SOBRANTES.jpg?pad=0.02&label=0 · masked page
2. The read
One request, 2026-10-15T05:59:07Z: 53.6 s, 1 attempt, finish stop, 2,609 tokens in, 810 out, $0.000145957. Raw output: 1,765 characters, sha256 45bd81cd8b39daf863eb110fc143c528e65333e24380063ed260e99951a30b6d, 23 items. Item 1 (Unused ballots), as returned:
{"label": "BOLETAS SOBRANTES", "n": 180, "w": 180}
3. The gate
twohands/gate.py, run again on the raw output. Shape: 23 values, the form has 23. Row labels: consistent. Digits read: 23 of 23. Words: 22 of 22 fields with words read: digits = words (Unused ballots: digits = words).
| identity | left side | right side | result |
|---|---|---|---|
| rows sum to TOTAL | 277 Option 01 117 + Option 02 21 + Option 03 6 + Option 04 6 + Option 05 7 + Option 06 16 + Option 07 65 + Option 08 10 + Option 09 5 + Option 10 0 + Option 11 0 + Option 12 8 + Option 13 3 + Option 14 4 + Option 15 2 + Unregistered candidates 0 + Null votes 7 | 277 TOTAL 277 | pass |
| votaron + representantes = section 5 | 277 Voters on the list 273 + Representatives who voted 4 | 277 Voters + representatives 277 | pass |
| section 5 = section 7 | 277 Voters + representatives 277 | 277 Ballots taken from the boxes 277 | pass |
| section 7 = TOTAL | 277 Ballots taken from the boxes 277 | 277 TOTAL 277 | pass |
4. Decision
Accepted, no person: every check holds; the same as the stored record. Unused ballots is in no identity; on this field the check that holds is digits = words.
5. Against the official record
The official first capture keyed 480; Gemma read 180 (digits) and 180 (words); the paper says 180 (the AI adjudicator's reading of the crop: words "CIENTO OCHENTA", boxes 1 8 0); certified count: none (the certified count covers the vote rows and TOTAL, not this field). Disputed fields on this form in the sample audit: 1.
6. The receipt
Leaf 43 of 267 in the sample audit's Merkle tree (twohands/merkle.py: leaf = SHA-256(0x00 || canonical JSON), node = SHA-256(0x01 || left || right)).
{"crop_sha256": "e1bf660ece41a082946b06e211c5be41684abca692dbfa113bd4b01b5033507d", "field": "SOBRANTES", "form": "080310B0100", "keyed": "480", "model": 180, "tier": "medium", "words": 180}
Leaf hash 6d5fc26fd391fb0c70375495ed54a6d1511dc3342e2d4c442e4a0fdca3c5b7b1. Proof path (9 steps):
| step | sibling on the | sibling hash |
|---|---|---|
| 1 | right | 7fc780500562c07d3a7b9f4a9f93429925cd3e5ecd30d6729cf53bd2e91b099b |
| 2 | left | 85eebdae9fd6ebe2cec48060a5b64ce05aa8486e8286023eebf94cca2efcfda3 |
| 3 | right | 8a56a66a35be65eae539f6e5732f3eb23dd2bee3cf483f3e3f8cfece56cba7e3 |
| 4 | left | 800d2893661b694bf2fa322f30c45545085c9ee7c5e5792ed6500183714dd4be |
| 5 | right | 2a39cdb982914400e0d253d9be880440d1bd58207663bb6c8a2d3ce788e67013 |
| 6 | left | 12940b49c48d44f585f54395196af75f6685bc898cfe45a2ce64d9d1092de02d |
| 7 | right | 2d220120869fd6862e540b4ad140d8c1239f51aceec69482fba04bb17bf97435 |
| 8 | right | 297c803d134dee3409fbf0e80b997ce9d9c14780bcf38bf4a4b04919392176fa |
| 9 | right | 355a9c831b9a43c89a9d2fef79211aececbc49d556d971c2861dc3f6bf7b07f4 |
Root e56a8ef4f011b9e5a3b7bd91dd708580fe1a8912e3bd65f51d780a6dd5898721 (published in results/sample_audit_root.txt: the same; anchored with OpenTimestamps). Open the receipt: /verify/080310B0100/SOBRANTES. Verify it offline:
curl -sL https://<host>/verify/080310B0100/SOBRANTES -o receipt.json curl -s "https://<host>/crop/080310B0100/SOBRANTES.jpg?pad=0.02&label=0" -o crop.jpg python -m twohands.verify_receipt receipt.json --crop crop.jpg --root e56a8ef4f011b9e5a3b7bd91dd708580fe1a8912e3bd65f51d780a6dd5898721
- ok: leaf recomputed from the record (6d5fc26fd391fb0c)
- ok: crop SHA-256 matches the record (e1bf660ece41a082)
- ok: path of 9 steps reaches the receipt's root (e56a8ef4f011b9e5)
- ok: receipt's root matches the root given (e56a8ef4f011b9e5)
VERIFIED. The receipt proves this record (form, field, keyed value, Gemma's digits and words, tier, crop hash) is unchanged since the report was sealed. It does not prove the reading is right; the paper settles that.
(b) Routed: form 122655C0100, Option 02
1. The photo
The exact crop bytes the receipt hashes: /crop/122655C0100/OPT02.jpg?pad=0.02&label=0 · masked page
2. The read
One request, 2026-10-15T06:38:24Z: 60.7 s, 1 attempt, finish stop, 2,609 tokens in, 815 out, $0.000146307. Raw output: 1,766 characters, sha256 e8fc7875af26ec52cde18733b4ac7b1f92b103174850976a6f757bb2aea4aa22, 23 items. Item 7 (Option 02), as returned:
{"label": "(printed row logos; shown here as Option 02)", "n": 23, "w": 23}
3. The gate
twohands/gate.py, run again on the raw output. Shape: 23 values, the form has 23. Row labels: consistent. Digits read: 23 of 23. Words: 23 of 23 fields with words read: digits = words (Option 02: digits = words).
| identity | left side | right side | result |
|---|---|---|---|
| rows sum to TOTAL | 366 Option 01 1 + Option 02 23 + Option 03 3 + Option 04 26 + Option 05 22 + Option 06 98 + Option 07 165 + Option 08 0 + Option 09 0 + Option 10 0 + Option 11 0 + Option 12 7 + Option 13 0 + Option 14 0 + Option 15 0 + Unregistered candidates 0 + Null votes 21 | 466 TOTAL 466 | FAIL |
| votaron + representantes = section 5 | 466 Voters on the list 466 + Representatives who voted 0 | 466 Voters + representatives 466 | pass |
| section 5 = section 7 | 466 Voters + representatives 466 | 466 Ballots taken from the boxes 466 | pass |
| section 7 = TOTAL | 466 Ballots taken from the boxes 466 | 466 TOTAL 466 | pass |
4. Decision
Routed to a person. Cause: rows sum to TOTAL: 366 != 466 (the only reason; the same as the stored record). Option 02: digits = words, so only the arithmetic could catch it. With the paper's 123, rows sum to TOTAL gives 466 = 466.
5. Against the official record
The official first capture keyed 123; Gemma read 23 (digits) and 23 (words); the paper says 123 (confirmed by the certified count); the certified count says 123 (settled by comparison with the paper, Cotejo). Disputed fields on this form in the sample audit: 1.
6. The receipt
Leaf 146 of 267 in the sample audit's Merkle tree (twohands/merkle.py: leaf = SHA-256(0x00 || canonical JSON), node = SHA-256(0x01 || left || right)).
{"crop_sha256": "0ddd5b7520df372496cd137744a8d31be0cdffdffcfef9812b1358a3de809d5b", "field": "OPT02", "form": "122655C0100", "keyed": "123", "model": 23, "tier": "weak", "words": 23}
Leaf hash 40c90012f177f089c23b4a4f5f56558fc2c9ed489fee719cef3c60d0e847361f. Proof path (9 steps):
| step | sibling on the | sibling hash |
|---|---|---|
| 1 | left | 134876b1756ecee927e725ee60966f13cbbfc8b3955072095e2f2639b2cf5fce |
| 2 | right | b87781825f1cd133901c74b698399fc539475725db6ca863342536e3eb6f0f63 |
| 3 | right | 224d88fda1f6144a223a537702ae1bc1a958a13718479a1351240ab985f8842d |
| 4 | right | ba58cd05893fcc607a40fba41422ce3db362ebd3befb49cf3f54fe398824b1a6 |
| 5 | left | 9382ecef0e39550e659cd450202a30f81250e7b871f6c6892116dc010521dffe |
| 6 | right | f29cd346d804255b42d45aac2b6b0a381b6ae6ae2e47836ae072d63ee3d3cd73 |
| 7 | right | e3433d72e84e9f9836b00bcbef6a9132281a17a7b5551f203dc42917839b2f1f |
| 8 | left | 0691cdcdd271df7c343f3ac2eecf2b20957ea05c53c1fe4f73aeb06f49d67581 |
| 9 | right | 355a9c831b9a43c89a9d2fef79211aececbc49d556d971c2861dc3f6bf7b07f4 |
Root e56a8ef4f011b9e5a3b7bd91dd708580fe1a8912e3bd65f51d780a6dd5898721 (published in results/sample_audit_root.txt: the same; anchored with OpenTimestamps). Open the receipt: /verify/122655C0100/OPT02. Verify it offline:
curl -sL https://<host>/verify/122655C0100/OPT02 -o receipt.json curl -s "https://<host>/crop/122655C0100/OPT02.jpg?pad=0.02&label=0" -o crop.jpg python -m twohands.verify_receipt receipt.json --crop crop.jpg --root e56a8ef4f011b9e5a3b7bd91dd708580fe1a8912e3bd65f51d780a6dd5898721
- ok: leaf recomputed from the record (40c90012f177f089)
- ok: crop SHA-256 matches the record (0ddd5b7520df3724)
- ok: path of 9 steps reaches the receipt's root (e56a8ef4f011b9e5)
- ok: receipt's root matches the root given (e56a8ef4f011b9e5)
VERIFIED. The receipt proves this record (form, field, keyed value, Gemma's digits and words, tier, crop hash) is unchanged since the report was sealed. It does not prove the reading is right: here Gemma's reading is wrong, and the receipt seals it all the same; the arithmetic is what caught it.
Source: scripts/build_trace.py from results/calls_gemma.jsonl, app/data/audit_sample_prep300.csv, results/adjudication/, data/masked/ (no model call).