← All writing

Read Backwards, Build Forwards

Two different requests produced two reports of 486,337 bytes each, byte for byte the same; two refactors carried the bug along, and one written statement of what each report was for fixed it in under thirty minutes. Every transformation passes through intent, and AI has made the forward half, building from a clear statement, cheap, so the leverage has moved to reading backwards: recovering what an existing module is for, like the Archimedes text read back from under a medieval prayer book. Palimpsest is that backward half as a small method, and its first run found defects that a heavier extraction and a same-session certification had missed.

Michael Shatny··9 min read

Two Reports, One File

The StratIQX analysis platform produced three kinds of report: a brief, a basic report and a comprehensive one. The brief was meant as a short companion to a longer report, not a setting of its own. Two different requests went in, one for an executive brief and one for a full report, and two files came out at 486,337 bytes each. Byte for byte, they were the same document.

✗the line that decided
// what decided the type of report
var isExecutive = analysisDepth === 'quick';

// result: an executive brief and a full report,
// both 486,337 bytes, byte for byte the same

The cause turned out to be one line: a technical setting, the depth of analysis, was deciding what kind of document to write. Finding it took longer. The large worker file behind the pipeline was first refactored into abstract services. The bug moved with the code. It was then rebuilt as a chain of documents. The bug moved again. Each rewrite rearranged the implementation faithfully, and the implementation was where the bug lived.

What fixed it, in under thirty minutes, was not a third structure. The monolith stayed. Each report type was tied to what it was for, and that mapping was frozen so nothing downstream could reinterpret it. More than three weeks of debugging and rearranging had changed nothing; one statement of intent changed everything. That fix became Semantic Intent as a single source of truth.

Writing Under the Writing

Around the year 950, a scribe in Constantinople copied works of Archimedes onto parchment. In 1229 the book was taken apart, its pages scraped, washed and written over with prayers, and bound again as a prayer book. Parchment was costly; old text was material. For nearly seven centuries the mathematics sat under the prayers, and when a scholar identified it in 1906, much of it still could not be read. Between 1999 and 2008, imaging work at the Walters Art Museum, using ultraviolet, infrared and visible light and later X-ray fluorescence, brought most of it back. The Archimedes Palimpsest is now read through its overwriting, not despite it.

A legacy module is a palimpsest. Its first intent, what it was for and which rules it had to keep, is still on the page, under years of fixes, features and workarounds written over it. A refactor writes another layer. A port copies the top layer into a new language. Neither reads what is underneath, which is why both carry the same bugs forward so faithfully.

!

A refactor rearranges the implementation. A bug that lives in the implementation survives every rearrangement.

Only a statement of what the code is for gives a rewrite something to be checked against.

The Forward Half Got Cheap

Every transformation passes through intent, whether anyone writes it down or not. It has two halves: read backwards from what exists to what it is for, then build forwards from that to something new. For most of software's history the forward half was the expensive one, so methods put their effort there.

That has changed. When case PX-001 rebuilt a paused Flutter app as a local-first web app, the whole run, from extraction to five build passes and 51 tests, fit in one session on a single morning. Building forwards from a clear statement is now the cheap part. The leverage has moved to the half that produces the statement.

✓the same bug, read backwards
R-DOC-01  A report's type is set by what was requested,
          never by a technical flag
  evidence:  isExecutive derived from analysisDepth === 'quick'
  status:    CONFLICT: the code ties type to analysis depth
  decision:  type comes from the request; the brief is a
             companion to its parent report
  check:     Given requests for a brief and a full report on
             the same case, then two different documents result

Read backwards, the report bug becomes a rule with its evidence, a question for a person, a decision and a check. Any builder can act on that. A port of the original could not have found it, because the original was doing exactly what its code said.

What a Blind Reading Found

Palimpsest is that backward half written down as a small method: four stages, four Markdown files, any model. It was tested on the original code of the same app PX-001 had rebuilt. A separate agent read the Flutter source with only the stage instructions, never the earlier analysis, and produced 16 workflows, 59 rules and 17 questions in about two dozen tool calls.

It found the two defects the earlier, heavier extraction had found in that area: deleting a property left its expenses behind, and loan-to-value divided by zero when a property had no market value. It also found six the earlier extraction had not recorded. A market-value edit from one screen was saved only if the last tab opened elsewhere happened to be the main one; otherwise nothing was stored, and the app still said “updated”. A rent limit was saved under one field name and read under another, so it never appeared again.

None of these were hidden in any deep sense. They were simply written over. A reader looking for what the code was for, rather than what it did, saw where the two had come apart.

The Check That Never Saw the Build

The last stage is verification, and it has one rule that matters more than the others: it runs in a fresh session that never saw the build, with only the intent files and the new code. A check that shares the builder's context shares the builder's blind spots, the same problem as a validator kept as a second copy of the rules.

Run against the PX-001 rebuild, the one its own same-session certifier had given a conditional pass, the fresh check passed 30 rules and failed 14. Six failures were the rebuild's deliberate redesign. Eight were defects in the live app. A one-off expense was counted in every month's cash flow. Totals ignored each amount's currency. Dates showed a day early in Canadian time zones. The original certification had listed none of them, though the expense option was added after it ran.

Not New, Newly Cheap

Reading code backwards into rules is old. Business rule extraction has been a category in mainframe modernisation for decades, and the large vendors still sell it: AWS Transform for mainframe extracts business logic from COBOL, and IBM's watsonx Code Assistant for Z discovers and documents business rules. Open projects are moving the same way; Reversa, a multi-agent framework published in May 2026, turns legacy systems into specifications for coding agents.

What changed is the cost. Reading backwards used to be a specialist programme run over a whole system. Now one module can be read in a sitting, before anyone touches it, with every rule tied to the line it came from and every disagreement left for a person to settle. The small version matters: a method too heavy to run on an ordinary Tuesday becomes the next thing nobody uses.

One case is not a finding. The app was small, its owner wrote it, and the comparison was made by someone who knew the earlier results. The next test is the one that would count: the same unseen module rebuilt twice, once as a straight port and once read backwards first, with the defects each carries over counted.

Read Before Writing Over

The prayer book was not a mistake. Parchment was scarce, and the scribe needed pages. What was lost was not the mathematics, which stayed on the leaves, but the habit of reading what was there before writing over it.

Every rewrite of working software makes the same choice. The original intent is still on the page, under the fixes and the flags. Rearranging the top layer, however carefully, copies what is wrong with it. The two reports that came out the same to the byte were not fixed by a better structure. They were fixed by reading backwards first, and only then building forwards.

Related

Michael Shatny is a software developer and methodology engineer and founding contributor to .netTiers (2005–2010), one of the earliest schema-driven code generation frameworks for .NET. His work spans 28 years of the same architectural pattern: structured input, generated output, auditable artifacts. Palimpsest runs that pattern in reverse: an existing module in, a structured statement of its intent and a check that never saw the build out.

ORCID: 0009-0006-2011-3258