think
16px
820px

The contamination is printed on the sheet

2026-07-15 · Apostille signature fast-track · task A of "let's do all lmao"
Phase K.23 · commits 0d7b9917, dfacce9b · deployed to staging :3520


TL;DR

26.7% of registry specimen sheets are demonstrably not the filed officer's signature — and the sheet says so in printed text. No model, no training, no GPU. On-prem OCR reads the form, compares the printed "Nama Pejabat" to the registry, and flags the mismatch for the verifikator.

This attacks the root cause that K.20–K.22 kept running into: for months the matcher has been asked to compare a document signature against the wrong human's handwriting, and scoring it low was the correct answer. No amount of encoder tuning fixes a corpus that points at the wrong person.

A second fix took unreadable specimen files from 20% → 0%, and in doing so retired one of our standing "AI limitations" — it was a data bug all along.


The mechanism, read straight off Darsani's files

I'd assumed contamination was a mystery of bad data entry. It isn't. It's a structural artifact of how the registry indexes attestation forms, and the files spell it out:

flowchart TB subgraph bundle["Registry file 291063455 — ONE PDF, TWO PAGES"] p1["Page 1 — FORMULIR 01
'Penyampaian Spesimen Tanda Tangan'

Nama Pejabat: Sari Nurlistiano, S.Sos, MSi
✍️ signed by Nurlistiana — HER OWN specimen"] p2["Page 2 — FORMULIR 02
'Keterangan Keabsahan Tanda Tangan & Cap'

Nama Pejabat: Drs. H. Darsami, M.Si
'sudah pensiun dan telah diganti kepala Dinas yang baru'
✍️ signed by Nurlistiana, as his successor"] end bundle -->|"registry indexes the bundle by
the officer named in the F02"| reg["registry row:
officer_name = 'Drs. Darsani'"] reg -->|"so the matcher loads…"| out["Darsani's 'specimen'
= Nurlistiana's handwriting
"] style out fill:#fee,stroke:#c00,stroke-width:2px style p2 fill:#fff4e5,stroke:#e8a33d

A FORMULIR 02 is a successor certifying that a retired officer once signed a document. It therefore names the retired officer while carrying the successor's signature. When the registry files that bundle under the named officer, his specimen becomes his replacement's handwriting — permanently, and invisibly to any pixel comparison.

Two orthogonal tells, and each catches a case the other misses:

specimen what the sheet prints name check form check
2655 (genuine) LEGACY table, DRS. DARSANI, MSi ✅ passes ✅ passes
291063455 F01 names Sari Nurlistiano 🚩 catches ❌ misses
290994327 lone F02, names Drs. Darsani misses 🚩 catches

The 290994327 row is why a naive "does 'Darsani' appear on the sheet?" check — my first sketch — would have failed. It names Darsani perfectly. Only the form type gives it away.


Measured, not estimated

45 real registry specimens with files, scanned through the live service:

status n % meaning
NAME_MISMATCH 4 8.9% the sheet's specimen belongs to a different, named person
ATTESTATION_FORM 8 17.8% no specimen at all — a successor's attestation
OK 15 33.3% sheet names this officer
UNKNOWN 18 40.0% nothing conclusive → say nothing
UNREADABLE 0 0% (was 20% — see below)

26.7% flagged. That independently confirms the ~35% figure I'd been quoting from the Darsani case, and puts a defensible number on it.


The scan caught three of my own false positives

This is the part worth reading. The first pass flagged 31.1% — and three of those flags were mine, the exact failure the design is biased against. A verifikator told twice that a valid specimen belongs to someone else stops believing the flag at all; that's worse than today's silent wrong-person comparison.

1. Drs.Sutrisno has no space after the dot.
Normalizing on [,\s]+ made it one token — "drssutrisno" — which can never match the sheet's DRS. SUTRISNO, M.P.D. Two of one man's own specimens were flagged as somebody else's. Fixed by splitting on dots and dropping single letters (splitting M.Si leaves a stray m that pollutes the comparison; a lone initial never distinguishes two people).

2. An F02 is only contaminated if it names the officer the registry filed it under.
Id 290946147 attests for "Kolonel Cba Had Satriano" but is filed under "Hadi Sutrisno" — its signer. The ink genuinely is Hadi Sutrisno's; the specimen is fine. My blunt "any F02 → flag" rule accused it anyway.

flowchart LR f02["FORMULIR 02
names X (retired)
signed by Y (successor)"] f02 --> q{"registry filed it under…"} q -->|"X — the RETIRED officer"| bad["🚩 ATTESTATION_FORM
the ink is Y's, not X's
6 of 7 in the scan"] q -->|"Y — the SIGNER"| good["✅ stay quiet
the ink really is Y's
1 of 7 — id 290946147"] style bad fill:#fee,stroke:#c00 style good fill:#efe,stroke:#0a0

Telling those apart requires keeping the attested name alongside the specimen owner's — hence a second column. Verified across all 7 F02s in the scan: 6 name-match (contaminated), 1 names-someone-else (genuine).

Re-scan after both fixes: all three false positives gone, every true positive survived. Both are now pinned by regression tests using the real registry spellings.

A third false positive never made it out of the unit tests: on an empty field, "Nama Pejabat : NIP : 480 082 007", the lazy regex happily returned "NIP" as a person's name — which would then "disagree" with the registry and slander a clean sheet.


What the verifikator sees

A red banner in the compare modal, above the crops — a low score against the wrong person's sheet means nothing, so it has to be read before the pixels. It follows the ‹ › scroll, not the selection: you need to know a sheet is the wrong person's while deciding whether to pick it.

⚠️ Spesimen pada lembar ini atas nama "Sari Nurlistiano, S.Sos, MSi", bukan "Drs. H. Darsani, M.Si" — kemungkinan salah data di registry.

⚠️ Lembar ini hanya FORMULIR 02 (Keterangan Keabsahan) yang menerangkan "Drs. Darsani, MSi" sudah tidak menjabat — tanda tangan di dalamnya milik pejabat penggantinya, bukan spesimen pejabat ini.

Verifikator-only, like the AI score: it reports a registry data-quality defect, which isn't the pemohon's business. Fails silent — an attribution error never blocks the comparison. Lazily OCR'd per displayed specimen (Darsani has 22 registrations × seconds of OCR each) and cached.


Two process notes

The live probe found what unit tests couldn't. My first implementation judged a file by one whole-file form type — taking page 1's name and page 2's type. Every unit test passed, because I'd written the fixtures from a 620-character preview that never showed page 2. Running it against the real registry exposed it in one call. The unit of analysis had to become the page, not the file.

Staging runs prisma migrate deploy, not db push. Editing schema.prisma alone ships new code against an old database — the route 500s on a column that doesn't exist. Caught it mid-deploy; hand-authored the migration and verified it applies from scratch (21 migrations on a throwaway DB) before re-shipping.


The "AI limitation" that was a data bug

The scan showed 20% of specimen files were UNREADABLE — Azure DI returning 400 InvalidRequest. The cause was one line: the layout provider hardcoded Content-Type: application/pdf. The registry serves JPEG bytes under a .pdf name, so we told Azure DI they were PDFs and it refused. Same mislabeling that crashed poppler in K19-1; same fix — sniff the magic bytes.

It's safe on a path every extractor rides: a real PDF still resolves to application/pdf, so the PDF case is byte-identical. It only rescues files that previously failed outright. Live re-scan: UNREADABLE 9/45 → 0.

Then the interesting part. Specimen 291092585 became readable — the one that in K19-3 scored 53.5%, ranking above the genuine Darsani at 43.2%, which we recorded as a hard limit of the matcher:

"absolute cross-domain scores can't auto-rank the genuine specimen… confirms best-of-N specimen match is DANGEROUS" — K19-3

It reads: FORMULIR 02, attesting for "Bpk. Drs. Darsani. M. Si", signed by his successor Galih Yudha Praja.

It was never a model failure. That sheet really does carry Galih's handwriting; the model scored it high because it is his signature, and scored Darsani's genuine sheet lower because it was comparing across domains. The AI was right. The registry was wrong. We just couldn't read the evidence — and so we filed it as an AI limitation for a month.

Which makes all four of Darsani's registry specimens finally legible, three of them contaminated:

id what it actually is verdict
2655 legacy "Contoh Tanda Tangan", names Darsani ✅ genuine — stay quiet
290994327 lone F02 for Darsani, signed by Nurlistiana 🚩 attestation
291063455 F01 (Nurlistiano's specimen) + F02 for Darsani 🚩 named mismatch
291092585 F02 for Darsani, signed by Galih Yudha Praja 🚩 attestation

Still open

Task B — auto-tightening the detector box. K.20 proved a hand-drawn tight box makes the genuine rank #1 (the padding sweep is a clean monotonic dose-response), but auto-tightening failed twice on real CV: connectivity can't split a signature drawn over a stamp, and colour clustering leaves the stamp's dark ring bridging.

Task A reframes the question. The Darsani anchor I'd been using as the box benchmark is three-quarters contamination — "rank the genuine #1 against those distractors" was never really a box test, and attribution now answers it deterministically and better. The honest remaining question is narrower: does a tighter box raise the genuine score on clean, correctly-attributed pairs? That needs a clean-corpus run on the 988-officer val, not the anchor. Worth doing, but as its own measured wave rather than bolted onto this one.


Backend 2622 tests green · frontend 994 green · verified live on staging against the real registry.