A drawing session hesitates: a short stroke, drawn and erased again, fifteen hundred times over. The canvas is kept as a journal: every act performed on it, in order, replayed whenever it is rebuilt. So every one of those pairs is still there, though none of them is in the picture. This demo removes them — tried first on a copy that touches nothing, checked against the questions the canvas answers, then done for real — and measures what the journal gains and what it gives up.
A drawing canvas and its rules, one scripted session, and the two questions asked of it: the picture and the stroke count
The journal: complete → marked, every record still on disk → shortened, the marked records gone
Architectural question
The journal keeps everything. Can part of it be removed, with proof that nothing anyone can see has changed?
What is being measured
A drawing canvas whose rules are a small, complete domain: strokes laid on a stack, each later stroke over the earlier ones, and an eraser that lifts one stroke out and leaves the rest as they lay. The picture is the stack read from the bottom up, so a stroke that was drawn and then erased leaves no trace in it. A scripted session draws a flower in 500 strokes and hesitates 1,500 times on the way — a short stroke, erased a few acts later. Its journal ends with 3,504 records: 3,000 are those hesitations, each drawn and then erased; 500 are the strokes in the picture; the other four create the canvas and define its two operations.
The rule
One rule, written in one place, decides what may be forgotten. It does not judge acts one at a time; it looks for a pair:
- a stroke is drawn, and the rule notes the stroke's id
- later, the stroke with that same id is erased
- both records are marked as forgotten: they stay in the journal, and replaying it steps over them
Puppeteer does not decide what is safe to forget. This rule is that decision, and the next two sections are its check.
Preview, on a copy that touches nothing
The rule runs first on a copy of the canvas, rebuilt from the real journal into storage of its own, so nothing done to it reaches the original. There it runs in a mode that only lists what it would mark, and marks nothing. It is the first of three steps, and the order is the claim: nothing on disk changes until the two steps that change nothing have both run.
It listed 3,000 records: the drawing and the erasing of every hesitation, and nothing else. On the real canvas, the number of the last record, the record count, the bytes on disk and the printed picture were compared before and after, and none of them moved.
The proof
Before anything is removed, a comparison rebuilds the canvas twice from the journal — once whole, once skipping a set of records — and compares the answers to the same two questions, the picture and the stroke count, character for character. It was given two sets: the rule's, and a deliberate near miss, the same set with one drawing left out of it, so that the replay draws that stroke and never erases it.
| Records skipped | Picture | Stroke count | Verdict |
|---|---|---|---|
| The rule's 3,000 | unchanged | unchanged | safe |
| The same, with one drawing left out | changed | 500 → 501 | unsafe |
Both drawings are made from the comparison's own output, the same text it compared.
The commit
Then the same rule runs on the real canvas and marks the pairs in its journal. Marking removes nothing: it writes a mark beside each record it forgets, so the journal grows, though it already starts faster, because a start skips what is marked. Nor does it touch the canvas that is running: it changes what is replayed the next time the canvas is rebuilt, so a wrong mark would not show until then. A second step shortens the journal, removing the marked records and their marks from disk, and the canvas is closed and opened again from what is left. Puppeteer calls the marking “elision” and the shortening “Distill”.
| Journal state | Records | Bytes on disk | Time to start |
|---|---|---|---|
| Complete | 3,504 | 196,236 | 41.4 ms |
| Marked, every record still on disk | 3,504 | 256,574 | 37.0 ms |
| Shortened | 504 | 34,666 | 14.2 ms |
One file, drawn twice: the two sides of the comparison the lab ran before anything was removed, and the answer it came back with.
After the restart the picture is the same text, byte for byte, and the journal keeps its numbering: the next act is record 3,505, as if nothing had been removed. Each time is the median of five starts on one machine, each opening a fresh copy of that journal inside a program already running, with its files already cached — a cold canvas, not a cold machine. At ten times the session the same three starts take 380.8, 222.8 and 57.7 ms.
What was given up
A hesitation leaves nothing in the final picture, but for the few acts between its drawing and its erasing it was on the canvas. The rule forgets both of its records, the drawing as well as the erasing, so a canvas rebuilt to any moment in that interval has no record to draw it from. To make that loss visible, the lab searches the middle tenth of the session for the moment with the most hesitations on the canvas at once: right after record 1,695, when 241 strokes were on it and seven of them were hesitations not yet erased.
The present is intact.The past is not.
The comparison saw it coming. Asked about that point before anything was forgotten, it called the same forgetting unsafe, and the picture it predicted is, byte for byte, the one rebuilt afterwards.
Nothing failed: replaying a moment takes every record up to it, and this journal no longer has them all. A product that needs those moments — to undo, to audit, to replay how a drawing grew — should not run this rule. The comparison says so, provided it is asked about the past and not only about the present.
What it does not establish
The limits, stated before anyone else has to state them.
- “Safe” means safe for the questions the comparison is given, here the picture and the stroke count. A question outside that list can change, and the middle of the session is one.
- The developer writes the rule. Puppeteer does not work out what is safe to forget; it previews, proves and carries out the forgetting it is told.
- It is not a personal-data erasure mechanism. Nothing here reaches copies, backups or anything outside this one journal.
- The timings come from one machine and two session sizes. It is not a performance evaluation.
Run it yourself
The example is one folder of the examples repository: the canvas and its rules, which never mention Puppeteer; one layer that connects them to it; the lab that plays the session and measures it; and their tests. Its README has a place to start reading the code: each step of the forgetting in Puppeteer's own calls, and a test that runs them as written.
The example, open as a pull request- dotnet test Sketch/Sketch.sln38 tests of the canvas alone, 30 end to end
- dotnet run --project Sketch/forgetting -c Release -- --out Sketch/out/scale1the report, the numbers, the pictures
- dotnet run --project Sketch/forgetting -c Release -- --out Sketch/out/scale10 --scale 10ten times the session
The lab checks every claim on this page while it runs, and stops before writing any evidence if one does not hold.