Teaching the Archive to Doubt
Duplicate scans, an empty text extraction and a scanner rule that had to be taken back: what digitizing a pile of paper taught me about evidence, and about agents that write their own instructions.
Part 22 of the series: Building The Hub
The document was a duplicate. The date was not.
On August 30, an agent helping me process old paper found a scan whose contents already existed in two archived PDFs. Keeping a third copy seemed pointless. But the filename of the new scan carried a date that neither archived file had.
Delete it, and the archive keeps the document but loses the only clue to when it belonged.
So we renamed the originals first, checked that their contents had not changed, and only then removed the extra copy. That is the kind of decision this whole post is about: not “what is this file?” but “what does this file prove, and what disappears if I throw it away?”
A lot of paper
In the previous post I split The Hub’s memory into source documents and the current understanding built on top of them. That only works if the sources are handled carefully, and late August put that to the test. By early evening on August 30, one session had logged ten triage rounds: 233 pages read, 73 documents filed, both intake folders empty.
The volume was not the hard part. The variety was. One feeder run can contain several unrelated documents. Two similar pages can be different versions. A sheet can have the interesting bit on its back. An old filename can be more informative than a freshly generated summary.
A confident description of page one is not enough. You have to account for every page first.
Three meanings of “duplicate”
The agents checked for duplicates in a few ways: a natural key such as the issuer plus an invoice number, a checksum, and combinations like date plus organization.
Those do not prove the same thing. A matching checksum (the MD5 that Drive reports for every file) means, for all practical purposes, identical bytes. A matching issuer and invoice number means the same invoice (on its own, an invoice number does not even get you that; two suppliers can both have an invoice 1042). Neither says anything about annotations, missing pages or scan quality.
One batch had a clean scan of a quotation that already existed as a phone photo. The scan was much easier to read. The photo had yellow highlighter on the materials we picked. Choose the “best” copy on image quality alone and you throw away a decision.
So copies that are the same document but not the same bytes now go to a quarantine folder, pointing back to the existing source by its Drive ID. A human decides whether either copy adds something.
Zero characters is not zero text
On September 11 a different shortcut failed.
A scanned travel document was about 1.2 MB. The archived version was roughly 55 KB. The agent ran pdftotext on the archived file, got zero characters back, and concluded the big color scan was the better source.
Then we checked the fonts. The output looked roughly like this (font name simplified, the last three columns are what matter):
$ pdffonts archived.pdf
name type encoding emb sub uni
------------------------ ------------- ------------ --- --- ---
XXXXXX+SomeFont CID TrueType Identity-H yes yes no
Embedded fonts, Identity-H encoding, no ToUnicode map. The small file was a born-digital print-to-PDF; the text was there, it just could not be extracted that way. The empty result was a fact about the tool, not about the document.
The digital original stayed. The paper scan went to the duplicate pile.
That pattern deserves a name, because it keeps coming back: a tool reports an absence, and the next sentence quietly turns it into a fact about the source. “This command extracted no text” becomes “this file has no text”. The second sentence needs more evidence than the first.
The rule that made it worse
Here is where it gets interesting for anyone building agents that learn.
On September 3, I ran what I call a dream pass: an agent reads a few weeks of session logs, finds recurring lessons, and proposes where they should live. About thirty triage rounds went in. Out came three separate change proposals: updates to the procedure and skills, general knowledge about handling paper, and corrections to the registers themselves. A fact about one document belongs with that document’s case; a lesson about searching belongs in the workflow.
Most of the lessons were good. One correction concerned receipts that had been logged as missing from the archive and later turned up in another pile. The original search only supported “not in what I checked so far”. The log had quietly widened that to “not in the archive”. So a rule went in: an absence claim keeps its scope. Write down where you looked, not just what you didn’t find.
And then one lesson went in that was exactly the same mistake in a nicer jacket: a scan with zero blank pages has never seen the backs.
It sounded logical. It was based on a real observation from that week. It got promoted into the instructions every future agent would read.
On September 12, an audit took it out again. A duplex scanner can suppress blank pages. No blank pages tells you nothing about whether the backs were scanned. Same failure as the pdftotext story: an absence turned into a fact.
The Hub had learned something wrong, and made it easier to repeat. Writing a lesson into the right file gives it reach. It does not give it better evidence.
The replacement rule is less clever and more honest: record the scan mode and the blank-page setting for every feeder pass. If you don’t know them, they stay unknown.
Two agents, two different mistakes
Around the same time I let a second agent loose on the same work. Claude Code had been running the triage; on September 5 I asked Antigravity to plan a large scan batch and audit the recent rounds.
It found real things. Eleven existing supplier folders that my exact-name lookup had missed, which removed twelve unnecessary uploads from my plan.
It also proposed 254 uploads without any deduplication, and most of the invoice numbers and amounts in its plan did not match the actual documents.
Both of those are true at the same time, and that shaped the workflow: one agent executes and owns the log, the other reads and proposes. The executor opens the source, accepts or rejects each finding, and writes down why. A polished audit report is a list of leads until someone checks them.
Two agents agreeing is not the finish line either. They can share the same wrong assumption. The finish line is a claim tied to something outside both of their texts.
Some rules should be code
The dream pass also exposed a stale index table of all dossiers. Maintaining that by hand is one more thing for a future session to forget. So it became a generator plus a CI check that fails when the committed index is out of date. A mechanical invariant does not need a language model to interpret it every time.
The September 12 audit pushed more of the scan workflow that way. A wildcard move had swept newly arrived, unread scans into the “processed” folder. A queue count had been carried across rounds from a listing that was truncated in the first place. “Be careful” in a prompt was not going to fix either of those.
Now each round freezes its source set up front: explicit paths, file sizes, hashes and page counts. New arrivals wait for the next round. Helpers flag changed sources, overlaps and pages nobody accounted for, with regression tests for the specific mechanical failures. Those tests catch a file that changes without changing size. They will never tell me whether a handwritten note changes what a document means. That part stays mine.
What doubt looks like in practice
None of this makes the archive infallible. The pdftotext mistake happened after weeks of refining the workflow, and the blank-page rule went in through the very process meant to make things better. What saved both was the trail. The retained source scans let me revisit those decisions and restore variants the first pass had missed.
The archive is getting more useful because it can now give a qualified answer. This date comes from a ticket. This copy has an annotation. This series is complete within these folders. This page still needs a human.
On October 4, two files in the scan folder had names that looked like deletion leftovers. A month ago, that would have been enough to clean them up. They turned out to be complete scans of a club magazine, 32 and 28 pages. They stay where they are until a round has compared them with what was already filed.
“Looks like junk” is a claim too.