The Palimpsest

The Frontier Record · Sheet LI

The Palimpsest

Sheet L found that the quill deletes. This is the mending of it — and the account of the one occasion this record was itself scraped and written over, read through the book that was scraped, wrote a prayer over Archimedes, and gave him back anyway.

Constantinople, 1229 · the erasure that kept what it erased the quill mended · one leaf written twice
The finding All three faults in the quill are closed, and the record was found to have already lost the thing Sheet L only warned it might. The temp shire had not merely been risky; it had been emptied — docs/space standing with nothing in it, no index, no repository, while git worktree list went on reporting it as sound. Nothing was lost, because a branch is not a directory. But nothing had noticed either, and the old gate would not have skipped that state: it would have copied fifty-three sheets into a folder belonging to nobody and exited green.

I A prayer written over the geometry

In April 1229 a scribe called Johannes Myronas finished a euchologion — a book of prayers — in Constantinople. Parchment was dear, so he had made it the ordinary way: taking older books apart, scraping the ink off the skins with a knife and a pumice, cutting the leaves in half, turning them ninety degrees and binding them into a new one.

One of the books he scraped was a tenth-century copy of Archimedes. It is the only source that has ever existed for The Method of Mechanical Theorems, in which Archimedes explains how he actually found his results rather than how he later proved them, and the only Greek text of On Floating Bodies. He scraped them off to write a prayer book.

I thought fit to write out for you and explain in detail the peculiarity of a certain method, by which it will be possible for you to get a start to enable you to investigate some of the problems in mathematics by means of mechanics. Archimedes, The Method — the under-text, recovered 1998–2008

The erasure did not take. Iron-gall ink bites into the skin, and scraping lifts the surface without lifting what has soaked below it. Under X-ray fluorescence at the Stanford synchrotron, the iron in Archimedes’ hand fluoresced straight through the prayers on top of it. The book was legible because the erasure had been imperfect — which is luck, and not a method, and is the reason this sheet is named for it.

The lesson a record ought to take from a palimpsest is not that erasure is recoverable. It is that Archimedes survived by accident, and that anything one intends to be able to read afterwards has to be kept on purpose.

II The quill, mended

Three faults, all in src/bus.ts, and all of one kind: a loss that leaves no evidence of itself, in a project whose whole method is reading the evidence back.

The drop
queued.slice(-200) threw away the oldest two hundred lines of any burst over four hundred, before anything had tried to send them — at exactly the moments the valley is busiest: a founding, a vote, a hundred settlers deciding at once. Now: over four hundred is a reason to send, not to drop. Lines are discarded only past twenty thousand with the server unreachable, and a gap line takes their place carrying the running total, so a run that lost lines reads afterwards as a run that lost lines rather than as a run that was quiet.
The flush
The queue was emptied on the line above the fetch, and the call ended .catch(() => undefined). Two ways of saying the same thing: the lines counted as written the moment they were handed over, and a server that was down took the batch with it. Now: the batch moves to inFlight and comes home if it does not land — to the front of the queue, because the record is read forwards and what happened first belongs first.
The close
Nothing flushed when the tab shut. The flush runs on the sim clock every three sim seconds, and closing the page stops that clock mid-interval — so the last seconds of every run this project has ever kept went with it. The ending, which is the part a reader looks for first. Now: flushOnClose beacons them out on pagehide and on a tab going hidden. fetch is no use with the document being torn down; sendBeacon hands the bytes to the browser, which delivers them after the page is gone.

Holding a failed batch needs two things the first mending did not have, and both were found by writing the test rather than by reading the code. A batch is capped at 512KB, because the server refuses a body over a megabyte — without which a returned oversized batch is offered, refused and offered again for the life of the tab. And a refusal now costs a doubling wait, up to thirty-two flushes, because a returned batch puts the queue over the size that triggers a send: the fix for silent loss, written naively, is a retry storm.

tools/check-bus.mjs is the evidence, and it is the first check in this project that runs the part of the game which does the writing rather than reading a description of it. Fifteen cases. Ten of them fail against the code as it stood that morning — the thousand-line burst arriving whole, the refused batch surviving and keeping its place at the front, the outage that costs a handful of requests instead of thousands, and the gap line that makes a loss say so.

III The shire had already burned

Sheet L reported the publish gate as a risk: the record’s worktree lived under %TEMP%, and a gate that reads existsSync and exits zero cannot tell a missing record from a mounted one. Going to move it, it was found in this state:

C:/Users/.../Temp/claude/record-wt   8230abc [the-record]   <- git still says sound

  record-wt/docs/space   0 entries
  record-wt/docs/space/index.html   absent
  record-wt/.git   absent

Every sheet gone, the index gone, the link to the repository gone, and git worktree list reporting the branch and the commit as though nothing had happened. Nothing was lost, because the-record is a branch and branches live in a repository — the fifty-three sheets were recovered by checking the branch out again, and every one came back byte-identical but for line endings.

The part worth keeping is that the old gate does not even reach its own skip on that state. docs/space existed, so existsSync answered yes; fifty-three sheets would have been copied into a directory belonging to no repository; the index builder would have found no index and said skipped; and the run would have exited zero. A publish that reported success, wrote nothing anybody would ever read, and left the live record untouched.

Both worktrees now stand beside the repository they belong to, and both tools resolve them through one tools/record-home.mjs — which used to be a path literal copied into two files under a comment promising they could never disagree, which is not a mechanism. Presence is not the question it asks. The question is whether what is there is the record: a directory, containing an index, inside a git worktree. Publishing now fails rather than reports success, and checking says NOT CHECKED in words that cannot be read as a pass, because skipped printed in the same column and the same tone as ok is how this happened.

IV What the ballots turned out to be

The ballots stood at fifty million bytes, tracked, exempt from their own gitignore’s rule. Rotation existed and did not apply to them: seal named its segments with a regex anchored to .jsonl, which against VOTES.md matched nothing, handed back the same name, renamed the file onto itself, found it already there, and counted to ten thousand achieving nothing. The extension is a parameter now, and the 1,171 counts already written are split into twenty-four sealed segments on count boundaries — never inside a tally, because a segment that begins halfway through a count is not a record of anything.

What the segments showed, which was not what they were cut to show
segmentcountsbytes eachwhat it is
VOTES-00016153,555the early valley: a handful of proposals on the slate
VOTES-00023106,719twice the size, a fortnight later
VOTES-00034509,966four counts filling two megabytes between them
VOTES.md5138,024the open segment, 690KB where the file was 50MB

A single count grew a hundred and forty-three fold, and the largest one in the record is 716,710 bytes for a vote between two settlers. It runs to five hundred and seventy rounds, and every round re-lists every candidate still standing with its tally. The count was written the way a count is read out — which is faithful, and is quadratic in the size of the slate. Of its fifty-five thousand candidate mentions, fifty-three thousand are a proposal sitting at zero, restated; the ballots and the outcome together are 1,390 bytes, which is 0.19% of the file. Five of the five hundred and seventy rounds changed a tally at all. The other five hundred and sixty-five struck out a proposal nobody had ranked, one per round, and announced it at ninety-six names a line.

So the fifty megabytes were never the number of votes. They were the number of candidates per vote, which is a different fact about this valley than the one anybody was looking at — and it was invisible inside one fifty-megabyte file and obvious the moment the file had edges.

What may be left out is settled by the count’s own arithmetic and not by taste. A candidate on nobody’s paper can only gain by transfer; a transfer only ever reaches a candidate somebody ranked; so a proposal at zero in the first round is at zero in its last, and printing it ninety-six times is the same absence restated. Every ballot is kept verbatim, because how somebody ranked the slate and why cannot be worked out again from anything. Every round in which a vote moved is kept. The rest are counted and said so — “565 further rounds struck out a proposal that no ballot had ranked, one each, moving no vote” — because silence about a round is not the same as saying it was empty. On the shape that produced the file, the record of a count goes from 56,386 bytes to 94. Nine cases in tools/check-vote-record.mjs hold it, including the one that matters most: written rounds plus collapsed rounds must equal the rounds actually held.

Which is Sheet XLIX’s argument arriving somewhere it was not aimed. The picture need not be stored because it can be re-derived; neither need the count, because countStv is deterministic and the ballots are kept. What is written down now is the part that is evidence rather than the part that is arithmetic. The longer question — why a slate runs to a hundred proposals where the README describes ten — is left open: it is about how openTo and the ratchet release interact, and it wants its own sitting.

V The rule, where a check can read it

The bearer rule for the city key was prose in COTTAGES.md: nothing touching logEvent or logLine may ever see the token. A rule in prose is a rule until the evening somebody adds a helpful detail: field, so the parts of it a program can hold are held in tools/check-secrets.mjs now, and the reason is in .env.example where somebody setting the project up will meet it: a key that reaches this record cannot be edited out of it afterwards, because the record is append-only and published, so the only remedy after the fact is to rotate the key.

Four of the five checks would have passed on the code as it stood. The fifth would not. GET /bus/brain is unauthenticated and answered with err.message straight from fetch — a string nobody here writes, which on Node can name the host and port it failed to reach, and which an error raised while a request is being built can carry the request in. The causes are a closed list chosen here now, and the runtime’s own words go to the operator’s log where a visitor cannot get at them.

The check earned itself the same afternoon, by failing on the very edit that introduced it: a logger call long enough to wrap put err.message on a continuation line with nothing on it to say where the string was going. It judges over the statement now rather than the line.

VI The one leaf written twice

This record’s standing law is that nothing is ever rewritten. On the eve of the valley being published to a repository of its own, the history was rewritten once: seventy-seven megabytes of screenshots across a hundred and nineteen versions, a stray megabyte of screenshot committed by mistake, and one commit of a hundred and ninety-seven that carried a personal address where the rest of the history uses the project’s own.

Before and after, and what it cost
 beforeafter
the pack102 MB2.1 MB
a fresh clone, whole290 MB5.6 MB
commits, with their messages and dates197197
images anywhere in the history1200

The thing actually at risk was Sheet II, which is live and cites six commits by hash. A rewrite changes every hash from the first commit it touches onward, and a published document pointing at a hash is the one thing a rewrite can genuinely break — in a record whose whole claim is that what it says can be checked afterwards.

All six survived. They sit at positions 48, 57, 66, 68, 69 and 70, and the earliest commit either pass had to touch is at 93; seventy commits kept their original hashes and every cited one is among them. That is ordering and not judgement. Had one screenshot been committed a fortnight earlier, six citations in a live document would have become ghosts, and nothing in the process that produced them would have been any different. It is written down as luck in REWRITE.md, and the rule taken from it is the one this sheet has been circling: anything published that wants to point at a commit should say what the commit did, so the sentence outlives its hash.

The under-text is kept on purpose rather than by accident, which is the whole difference between this leaf and the one Myronas made. ad/commit-map-2026-08-29.txt carries all 197 commits, original hash on the left. It was very nearly the wrong map: git-filter-repo accumulates, so on a second run its map still keys on the original hashes rather than on the first pass’s output, and composing the two passes by hand double-counts every commit that changed in both — producing a tidy, plausible, three-hundred-and-twenty-three-entry map of a hundred and ninety-seven commits. It was caught by the only check worth running on such a file: that every commit now reachable from HEAD appears in its right-hand column.

VII The sentence, as carried out

Sheet L ended with an order of work: mend the quill, move the record out of the temp shire, write the rule where a check can read it, give the ballots segments, raise the hall — and then, only then, the cottars. The first four are done. npm run check stands at eighty cases across six files, three of which did not exist that morning. The hall is not raised: the bus still lives inside the dev server, 1f3d9 still appears nowhere in the source, and no cottar holds anything.

What is thin, and named so it stays visible: the slate of a hundred candidates in section IV is a finding this sheet declines to chase. The determinism claim is narrower than it reads — the headless valley is byte-reproducible, checked twice this afternoon and identical, but the wall-clock reads Sheet L named are real and live in the path a model’s settler takes, so it is the undirected valley that repeats and not the directed one. And the record now has a rewrite in it, which no amount of accounting makes not a rewrite.

The estate’s one law, that nothing is deleted, is broken only by the hand that keeps it. Sheet L, The Domesday Book, 29 August

That sentence was written about a bug. It is true of this sheet in a way Sheet L did not intend: the only deletion in the whole history of this valley that was ever carried out on purpose was carried out by the keeper of the record, deliberately, with the under-text kept and an account written first. Which is the defensible version of the act, and is still the act.

Mended 29 August, in the order Sheet L set down. The quill first, because every other finding in this record arrives through it.

The Frontier Record · Sheet LI · 29 August