DemosJOURNAL DEMO

Forgetting on Purpose

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.

What remains fixed

A drawing canvas and its rules, one scripted session, and the two questions asked of it: the picture and the stroke count

What changes

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.

A flower drawn in loose pen strokes: a red blossom with eight petals round an ochre centre, a green stem with two leaves, a blue cloud to one side, and a grey line of ground across the bottom.
The picture the session draws, in 500 strokes. None of the 1,500 hesitations is in it.

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:

  1. a stroke is drawn, and the rule notes the stroke's id
  2. later, the stroke with that same id is erased
  3. 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.

1Preview, on a copyThe rule runs against a copy rebuilt into storage of its own, in a mode that only lists what it would mark.changes nothing3,504 records
2Proof, before anything movesA comparison rebuilds the canvas twice, once whole and once skipping the records, and compares the answers character for character.changes nothing3,504 records
3Commit, on the real journalThe same rule marks the pairs, and a second step removes the marked records from disk.changes the journal504 records

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 skippedPictureStroke countVerdict
The rule's 3,000unchangedunchangedsafe
The same, with one drawing left outchanged500 → 501unsafe
The flower as the journal stands: 500 strokes, the stem clear below the blossom.
×5The same corner, with nothing on the stem.
Skipping nothing: the picture as the journal stands. 500 strokes.
The same flower with one extra short stroke across the stem just below the blossom, left behind because its erasing was skipped.
×5Stroke 1114, erased during the session, back on the canvas.
Skipping the near miss: one drawing left out of the set, so the replay draws stroke 1114 and never erases it. 501 strokes, and the comparison called it 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 stateRecordsBytes on diskTime to start
Complete3,504196,23641.4 ms
Marked, every record still on disk3,504256,57437.0 ms
Shortened50434,66614.2 ms
Complete3,504 records · 196,236 bytes · 41.4 ms to startThe hatched part is the 3,000 records of the 1,500 hesitations, each drawn and then erased.
Shortened504 records · 34,666 bytes · 14.2 ms to startThe same track, so the second bar is read against the first: a seventh of the records, a sixth of the bytes, and a start in a third of the time.
BeforeThe flower as the complete journal rebuilds it.
=
AfterThe flower as the shortened journal rebuilds it: the same drawing, stroke for stroke.

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 canvas rebuilt to record 1,695 from the complete journal: a part-drawn flower of 241 strokes, with a cluster of seven short yellow strokes over the blossom.
×5Seven hesitations, drawn and not yet erased.

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
  1. dotnet test Sketch/Sketch.sln38 tests of the canvas alone, 30 end to end
  2. dotnet run --project Sketch/forgetting -c Release -- --out Sketch/out/scale1the report, the numbers, the pictures
  3. 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.