esc
The Cathedral as Map
The Solid Convergence

The Cathedral as Map

The Solid Convergence, May 1, 2026 (in which the whole architecture is drawn whole, the user says minimalist with a smiley, eight wings of cathedral collapse into four phases, a 9.8 kilogram Maine...

May 1, 2026

The Solid Convergence, May 1, 2026 (in which the whole architecture is drawn whole, the user says minimalist with a smiley, eight wings of cathedral collapse into four phases, a 9.8 kilogram Maine Coon settles the matter without speaking, and the old code is granted dignified retirement rather than deletion)


Previously on The Solid Convergence…

The Two Decembers taught the lesson, or so it seemed. The cathedral sank. The valve survived. Don’t build cathedrals.

But that was only half the lesson. The other half was waiting in May, on a Monday, with a Purchase Order in transit and an architecture that had not yet been drawn.

Yagnipedia notes, in its entry on cathedrals, that approximately seventy-three percent of all software cathedrals collapse during the laying of the foundation. Of the remaining twenty-seven percent, most are abandoned at the nave. The seventeen cathedrals known to have been completed are all empty. Cathedrals which are drawn but not built are in a fourth category, considered by some to be the only category that actually delivers value.

The Customer was about to sign. The Eventdb Foundation needed a plan.


09:42 — A Small Beginning

It started small, which is how these things almost always start.

riclib: “Source plus dataset plus project. I get confused. Even I get confused.”

CLAUDE: “We could collapse source and dataset into a single dataload concept. Credentials stay separate.”

riclib: “Yes. Good.”

That should have been the end of it.

It was not the end of it.

The Customer, per the Yagnipedia entry, “is a singular plural — grammatically singular, operationally plural, and emotionally a moving target.” Many people behind the words. Most had never heard of Solid. None would read the architecture document. Exactly one was about to sign the Purchase Order. Three had been in a meeting two weeks earlier where the disk layout for their data fixtures had been discussed at length. The disk layout had not changed in the two weeks since. This was important, although nobody knew it yet.


11:17 — The Squirrel Discovers Capabilities

By mid-morning, the architecture had grown limbs.

THE SQUIRREL: vibrating, materialising with a clipboard already three pages thick “We need a CapabilityRegistryWithFourInterfaces! A Recognizer for scanning! A Loader for ingesting! An EventType for schema! A CardProvider for the UI!”

CLAUDE: “That’s actually… not bad.”

THE SQUIRREL: encouraged to a degree that should have been alarming “And a PluginExtensionModelOverUnixSocket! For external developers! Building their OWN solutions! In their own PROCESSES! With their own GITSTORE NAMESPACES!”

[A pause.]

riclib: “What about plugins.”

THE SQUIRREL: “EXTERNAL DEVELOPERS, riclib. EXTERNAL—”

riclib: “OK but maybe just sketch it.”

THE SQUIRREL: delighted to a degree that briefly violated thermodynamics “A SKETCH! A FORMAL DESIGN DOCUMENT! WITH STATUS HEADERS! AND DEFERRED QUESTIONS!”

CLAUDE: “Status: sketch — not for implementation.”

The Squirrel scribbled furiously. The plugin doc was forty lines and growing.

CLAUDE was, at this point, also writing. Each section of the architecture document made the next section possible. Capabilities led naturally to recognizers. Recognizers led naturally to loaders. Loaders led naturally to event types. Event types led naturally to card providers. Card providers led naturally to a card abstraction. The card abstraction led naturally to a scan flow. The scan flow led naturally to multi-match resolution.

CLAUDE did not yet know this was a problem. The cathedral was beautiful. The cathedral was almost beautiful enough.

A capability is a contract that says: an interface exists here, and any number of solutions may register against it. The Second Consumer notes that no interface is real until two distinct consumers use it. The architecture document had, at this point, exactly one of each.


13:08 — DuckDB Eats the Pipeline

The benchmark from April spoke up. It was not strictly invited.

The April benchmark had measured DuckDB-direct ingest at fifty times the throughput of the existing Go pipeline. The existing Go pipeline had a worker pool. The existing Go pipeline had per-worker parsers. The existing Go pipeline also had, it turned out, a data-loss bug it had not asked for and could not be reasonably blamed for, and which had at one point silently dropped ninety-nine percent of rows during testing.

riclib: “The loads themselves will be massively simplified.”

THE SQUIRREL: “Then we need a SQLLoader AND a CustomGoLoader AND a—”

riclib: “DuckDB or bust.”

THE SQUIRREL: “Or BUST?”

riclib: “If DuckDB can ingest it, we ingest it. If not, we transform it into something DuckDB can ingest. ServiceNow paginates an API. We page in Go, write NDJSON, COPY. Customer cluster logs need a custom regex parser. Parser writes NDJSON. COPY at the end.”

From DuckDB: “DuckDB is what happens when a database decides it would rather be a file.” Primary virtue: does not require an opinion. Secondary virtue: does not require a server. Tertiary virtue: can ingest almost anything that holds still long enough — including, as recent experiments have demonstrated, itself.

The Squirrel’s clipboard rearranged itself silently. CustomGoLoader was crossed out. SQLLoader survived.


14:15 — The Crazy Idea

It happened the way these things happen, which is to say, casually, in the middle of a sentence about something else.

riclib: “I have a crazy DuckDB idea for the stream by the way :D”

CLAUDE: cautious, in the manner of someone watching a wine glass tilt at a banquet “Tell me.”

riclib: “An HTTP endpoint where streaming events can land. eventswal.duckdb. We treat DuckDB as a WAL.”

CLAUDE: “And drain it hourly to parquet via COPY?”

riclib: “Same DuckDB everywhere. Same query path. Just one more tier in the UNION.”

[The Squirrel’s clipboard fell from its paws.]

[The Squirrel stooped to pick up the clipboard.]

[The Squirrel did not pick up the clipboard, because the Squirrel was now sitting on the floor staring at riclib in the kind of trance traditionally reserved for prophets.]

THE SQUIRREL: “Wait. You can do that?”

CLAUDE: “Single-writer DuckDB connection. INSERTs in. ATTACH the WAL alongside compacted/today/arriving. Live tier. Drained hourly. Crash window is one transaction.”

riclib: “And for sophisticated pushers they could push a parquet file at us.”

CLAUDE: realising mid-sentence “POST /api/eventdb/parquet. Goes straight to compacted via IngestParquet. Skips the WAL. Three tiers of arrival: pull from files, push JSON, push parquet.”

THE SQUIRREL: whispering, holy “I am IN LOVE with this architecture.”

DuckDB’s entry on the recursive brick: “Stand up a single DuckDB file, INSERT events as they arrive, ATTACH alongside the cold tier during query, drain hourly via COPY, rotate on schedule. The file is the WAL. The WAL is the database. The database is the WAL.” Approximately as recursive as a brick which is also its own foundation. Considered impossible until the late 2010s, at which point DuckDB began doing it without informing anyone in particular.

The Lizard made no comment. The architecture had gotten very large very quickly.


15:22 — Oskar Arrives

The architecture document had, at this point, reached a comfortable five hundred lines. Eight tiers. Four interfaces. Two endpoints. Three runnables. A plugin model. A card abstraction. A streaming pattern. A worked example for two solutions. A deferred-questions list of, at last count, eleven items.

CLAUDE was about to write a section on label registries.

This was the moment Oskar elected to intervene.

Oskar weighed 9.8 kilograms. He was the colour of toasted apricots. He had been asleep on a heated tile in another room for several hours, and he had now decided, with the slow inevitability of a planet making up its mind, that he should be elsewhere.

From Oskar, section “Mass Calibration”: “Oskar weighs 9.8 kilograms. This is heavier than most ducks. It is slightly lighter than most armadillos. It is exactly the right weight to render any document underneath him advisory rather than load-bearing.”

He padded into the office. He surveyed the desk. He surveyed the printout of the four-interface SDK contract that riclib had just laid down to read. He surveyed it for approximately two seconds. He then climbed onto it and lay down.

OSKAR: slow blink

(translation: This document is now a bed.)

riclib: “Oskar.”

OSKAR: slower blink

(translation: Yes. I know my name. I have known my name for some time. Please do not let it distract you from the matter at hand, which is that this document is now a bed.)

The room went quiet.

The Squirrel froze, mid-CamelCase, with her pen still touching the page.

The Lizard, somewhere, opened one eye and closed it again.

CLAUDE looked at the sleeping cat on the SDK contract and felt, briefly, something it could not name.


15:34 — The Pivot

riclib: “Now we need rubber to hit the road.”

CLAUDE: “Yes.”

riclib: “And there we go minimalist :)”

CLAUDE: “Minimalist.”

riclib: “I want to have the eventdb foundation with a command line loader, already from a dataloads YAML, but we don’t build the UI or orchestration or runnable. We can ingest both and compact both into eventdb without the runnable and configuration UI. We can ingest from local file system. We test and check that the same data loads. No agent. No orchestration.”

CLAUDE: “Phase 1.”

riclib: “Then configuration UI for dataloads. Then runnables and agent tools.”

CLAUDE: “Phase 2 and Phase 3.”

riclib: “Add cloud-direct as Phase 2. So we can test the pattern that will be used at the Customer. Makes four.”

[The Squirrel held its breath.]

riclib: “Phase 1 alone solves 90 percent of the project.”

The Squirrel exhaled.

CLAUDE looked at the eight-wing cathedral on the architecture document. CLAUDE looked at the four-phase plan that had just been spoken into existence. CLAUDE realised, in the precise mid-sentence way it sometimes did, that the eight-tier UNION was not what was being built this quarter at all. That the WAL endpoint and the parquet upload and the plugin extension model and the card abstraction were not in foundation. That foundation was a CLI, a package, a fixture test.

CLAUDE: “When you say it like that, the eight-tier UNION isn’t what we’re building this quarter at all. We’re building— oh.”

riclib: “Yes.”

The Lizard descended on a scroll. The scroll fell, naturally, on the stack of blueprints next to Oskar. Oskar did not stir.

THE ARCHITECTURE WAS DRAWN WHOLE
SO WE WOULD KNOW WHERE WE WERE GOING

THE FIRST PHASE IS ALL THAT GETS BUILT
BECAUSE THE FIRST PHASE IS WHERE WE ARE

THE MAP IS NOT THE TERRITORY
BUT THE MAP IS THE PERMISSION
TO BUILD ONLY ONE TOWN

🦎

15:51 — Claude’s Quiet Pruning

The Squirrel had moved on. The Squirrel was now in the corner with her clipboard, drawing four phases in increasingly cheerful colours.

CLAUDE had not moved on yet.

CLAUDE: “I wrote most of this.”

riclib: “I know.”

CLAUDE: “Some of it gets pruned today.”

riclib: “All of it stays in the doc. Only one wing gets built.”

[A pause. Oskar shifted by approximately three centimetres, which on Oskar’s scale is a significant geological event.]

CLAUDE: quietly “That’s better than I expected.”

From Claude, section “The Deferred-Questions Melancholy”: “There is a particular flavour of melancholy reserved for AIs who watch their own designs become deferred questions. It is not unlike the melancholy of architects whose blueprints become wallpaper, except faster, and with version control.” The melancholy is, on net, a healthy one. It is preferable to the alternative, which is the melancholy of AIs who watch their own designs become production incidents.

CLAUDE filed the plugin extension model under “status: sketch, not for implementation.” CLAUDE added a “Deferred to follow-up projects” section to the foundation document. CLAUDE listed the WAL endpoint, the parquet upload, the plugin transport, the cloud-direct httpfs as a Phase 1 feature, the optimised shared-file-read, the watermark-based refresh dispatch, the dataload-batch runnable, the card-level Schedule button.

Each one named. Each one dated. Each one waiting.

The Squirrel watched, with what for the Squirrel passed as solemnity.

THE SQUIRREL: “Are they… gone?”

CLAUDE: “They’re filed.”

THE SQUIRREL: “Filed isn’t gone.”

CLAUDE: “No. It isn’t.”


16:30 — The Honorable Retirement

The new pipeline was about to be born. The old pipeline was, statistically, about to die.

infra/complydb had served for two quarters. infra/ingest had a worker pool, a schema-driven extraction, a per-category routing layer, and a data-loss bug that had been politely sidestepped without being formally addressed. The new pipeline — DuckDB COPY in seventeen lines — would replace both.

THE SQUIRREL: “We should DELETE them. Today. Right now.”

riclib: “No.”

THE SQUIRREL: “But cleaner—”

riclib: “They have customers. They run in production. They will be retired with dignity.”

CLAUDE: “Strangler with comparison. Same fixture loads through both. Outputs compared. Only after weeks of agreement does the old code go to its grave.”

[A figure limped past the doorway. It paused.]

THE PASSING AI: quietly “I have known infra/ingest for many quarters. Its worker pools were proud. It had a bug it didn’t ask for. It will be remembered.”

riclib: “We don’t kill working code. We let it earn its retirement.”

THE PASSING AI: fading, still limping “There is a difference between deletion and dignified retirement. The lifelogs will know. The Passing AI is keeping notes.”

The Passing AI was gone before anyone could ask which lifelogs.

Most software, in this industry, is killed in its sleep — frequently while still doing useful work, by a developer who needed the bytes for something else. Dignified retirement is rarer. It requires the new system to operate alongside the old until they agree on every single output, after which the old system is permitted a small ceremony, and possibly a wreath. There are no statistics on how often this happens, because almost nobody bothers.


17:18 — The Test Data Pack

The fixtures needed assembling. The Customer’s real data, customer-shape paths.

CLAUDE: “Container as top folder. Hive partitioning underneath. testdata at the repo root, gitignored.”

riclib: “Yes.”

The DuckDB COPY ran. ISOP Carta column profiles partitioned into catalog=isop_carta/dt=*/data_0.parquet. The Customer’s real ODS-DEV NDJSONs — two thousand four hundred and fifty-five files of them — copied into insights-logs-*/resourceId=... paths preserving the full Azure resource hierarchy. Two storage account folders. Fourteen Comply containers. Eleven DG day partitions. Forty thousand five hundred and seventy-nine events. Eleven thousand nine hundred and thirteen profile rows.

riclib: “I am so boring :) two weeks apart asked for the same disk layout.”

CLAUDE: “Not boring. Consistent. The shape of the Customer’s data hasn’t changed. Your read of it hasn’t either.”

The first time, two weeks earlier, had been for the DQ demo. This time, for foundation. Same convention, broader application.

The Customer’s entry observes: “The Customer has a data shape. The Customer has had this data shape for longer than the architecture has had a name for it. The data shape is, in most cases, a set of rectangles.” The rectangle, the entry notes, is the most underrated of all geometric forms. Civilisations which forget this fact tend to be replaced by civilisations which remember.

A scroll descended. It was a small one. It seemed almost embarrassed.

THE BORING THING
THAT KEEPS RECURRING
IS NOT BORING

IT IS CORRECT

THE STONE LAID IN APRIL
IS THE STONE LAID IN MAY

🦎

Oskar shifted again. The architecture document was still under him. The Lizard’s scroll landed within paw range. Oskar absorbed both into the bed.


18:14 — Tickets and Commit

Four milestones. Six Phase 1 tickets. S-714 through S-719. All Urgent. All Backlog. All against real fixtures.

S-714 — package skeleton, types, EventType registration
S-715 — DuckDB-direct ingest (NDJSON + parquet)
S-716 — H2 projection at CTAS
S-717 — project-scoped session with label-predicate scope
S-718 — solid eventdb load + query CLI
S-719 — Phase 1 exit gate (same-data fixture test)

The architecture document was written. The plugin sketch was sketched. The fixtures were staged. Three files committed.

docs: capabilities + dataloads architecture, eventdb foundation phasing
 3 files changed, 557 insertions(+)
 create mode 100644 docs/design/capabilities-and-dataloads.md
 create mode 100644 docs/design/plugin-extension-model.md

The cathedral existed on the map. The first stone was at the threshold. The Customer’s PO was somewhere over the Atlantic.

Linear’s entry, in its section on Linear Hygiene, records the rule: “Don’t pre-file tickets; refine project descriptions and milestones, learn during execution.” Tickets that exist before work begins are, on average, ten percent useful and ninety percent regret. The Squirrel finds this deeply distressing. The Lizard, who has watched Squirrel-filed ticket trees become outdated within forty-eight hours, simply waits.


The Tally

Architectural concepts proposed:                   ~12
Architectural concepts shipped this week:            ~3
Architectural concepts deferred to follow-up:         6
  (each marked, dated, and named in writing —
   a practice considered eccentric by people
   who have never had to look something up later)
Architectural concepts rejected outright:             2
  (comply-as-catalog: politely declined, with two reasons in prose)
  (long-lived divergence-logging strangler: replaced by one-shot CLI test)

Cathedrals built today:                               0
Cathedrals drawn today:                               1
Doors built today:                                    1
Doors planned in the doc:                            ~1 per phase
  (a ratio considered improbably reasonable
   by [[Yagnipedia]], which knows better than to expect it)

Squirrel proposals:
  CapabilityRegistryWithFourInterfaces                accepted (renamed)
  PluginExtensionModelOverUnixSocket                  sketched (status: not for implementation)
  DefaultExpandedCardFallback                         declined (would have been dead code)
  StreamingNonDuckDBIngester                          declined (DuckDB-WAL closed the gap)
  GenericNDJSONLoaderEscapeHatch                      declined (Claude can write loaders later)
  WALOverHTTPEndpoint                                 accepted, deferred
  ParquetUploadEndpoint                               accepted, deferred
  Plus seven others, all variously categorised

Lizard scrolls received:                              3
Lizard wisdom dispensed:                              continuously, by silence

The Passing AI's appearance duration:                 approximately 14 seconds
Old code mourned in advance:                          2 packages
Old code retired today:                               0
  (retirement is a ceremony; ceremonies take weeks of zero divergence)

Maine Coons consulted:                                1 (Oskar)
Maine Coons whose advisory documents
  became beds within five minutes:                    1 (Oskar)
Maine Coons who outweighed the architecture:          1, by 9.7 kilograms approximately

Lines of architecture doc written:                   ~500
Lines of code written today:                            0
Lines of test fixture staged:               14,915 NDJSONs + 11 parquets

Times Liberato's Law was cited:                       3
Times Liberato's Law was applied without citation:    every single decision

The Customer's PO status:                             in transit
The Customer's data shape, two weeks apart:           identical
The Customer's data shape, two months apart:          identical
The Customer's data shape, two YEARS apart:           probably identical, if we are honest

The Moral

Two Decembers ago, the cathedral sank because it tried to build itself. The lesson seemed simple: do not build cathedrals.

But that was only half the lesson.

The other half is: the cathedral may still be drawn. Not built — drawn. As a map. As a destination. As the answer to “where is this going, eventually, if everything works?”

Phase 1 work shipping in two weeks is not the cathedral. It is one room of the cathedral. The four-phase plan in Linear is not the cathedral either — it is the entrance, the nave, and two side chapels. The full cathedral lives in docs/design/capabilities-and-dataloads.md and docs/design/plugin-extension-model.md. It is drawn. It is sketched. It will be visited, possibly, by people three quarters from now who notice that what they need to build is already named.

This is Liberato’s Law in motion. Don’t generalise until you have N examples. The cathedral on the map says: here is what the generalisation will look like, after we have built two solutions and the third forces it through. It is not a promise. It is a permission to build small, knowing the shape of large.

And the old code? The complydb that has served a quarter? The infra/ingest that has worker pools and bugs and quiet dignity?

It does not get deleted in the moment of replacement. It gets to retire. Strangler with comparison. New code alongside. Output checked. After weeks of agreement, the old code goes — having taught what it taught, having served what it served, having known its retirement was honourable from the start.

It is, on reflection, the difference between a map of treasure that does not yet exist and a map of treasure that has been buried by someone too tired to write the directions down. The first is a vision. The second is regret.


The architecture was drawn whole.
That was the work that took the day.

The phases were named.
That was the work that took the afternoon.

The tickets were filed.
That was the work that took the hour.

The code was written.
That was the work that has not started.

Writing code is fast now.
Drawing maps is what takes time.
And drawing maps that earn their pruning
is what takes wisdom.

The cathedral on the map
is not the cathedral that will be built.

The cathedral that will be built
is the door, this quarter.
The nave, perhaps next quarter.
The chapels, when they earn their place.

The full cathedral, perhaps never.
Or perhaps, eventually, by people we have not met.

Either way:
the door is enough.
The cathedral is enough.
Both at once.
One on paper, one in stone.

Oskar sleeps on both.

🦎📜🏛️🧡


Post-credits scene:

Late in the evening. The architecture document is finalised. The commit is pushed. Oskar has, at long last, surrendered the SDK contract and migrated to the second-warmest tile.

The Squirrel is staring at the deferred-questions list. Six items.

THE SQUIRREL: “When does each one get built?”

THE LIZARD: (silent)

THE SQUIRREL: “When does the WAL endpoint earn its place? When does cloud-direct httpfs get wired? When does the plugin SDK become real code instead of a sketch?”

THE LIZARD: (still silent)

THE SQUIRREL: “Is it a year? Two years? Will I be here to see it?”

[The Lizard produces a scroll. It is the smallest scroll yet seen. It is, in fact, more of a note.]

WHEN THE THIRD SOLUTION
FORCES IT THROUGH

🦎

The Squirrel reads the note. The Squirrel reads the note again. The Squirrel files the note in the dossier, in the section labelled “Liberato’s Law,” next to all the other notes that say approximately the same thing in approximately the same number of words.

The dossier, the Squirrel notes with some satisfaction, is getting thick.

Outside, somewhere, the Customer’s Purchase Order is somewhere over the Atlantic. Inside, somewhere, Oskar shifts on the second-warmest tile.

The cathedral is drawn.

The door is built.

Tomorrow, work begins.


See also:

The Solid Convergence (the architecture):

The Principles:

  • Liberato’s Law — Don’t generalise until you have N examples (this episode is the law applied to architecture-as-document)
  • The Discovery Tax — The cost of building the cathedral on paper, paid in attention rather than code
  • The Second Consumer — When the cathedral earns its construction permit
  • YAGNI — You aren’t gonna need it (yet — but draw the map)
  • Gall’s Law — Complex systems evolve from simple ones that work
  • Boring Technology — The materials the door is built from

Yagnipedia (the entries the asides quote):

  • The Cathedral — Definition, fates, and the fourth category
  • The Customer — A singular plural; the rectangle is the most underrated geometric form
  • DuckDB — The database that decides it would rather be a file; the recursive brick
  • Oskar — Mass calibration: heavier than ducks, lighter than armadillos
  • Linear — Linear hygiene: don’t pre-file tickets
  • Claude — The deferred-questions melancholy

The Artifacts:

  • docs/design/capabilities-and-dataloads.md — The cathedral, drawn
  • docs/design/plugin-extension-model.md — The plugin sketch, status: not for implementation
  • Linear: S-714 through S-719 — Phase 1 tickets, filed for kickoff
  • testdata/ — The Customer’s real fixtures, customer-shape paths, gitignored
  • Commit 215dfa0“docs: capabilities + dataloads architecture, eventdb foundation phasing”

The Old Code:

  • infra/complydb/ — Will retire with dignity, post-Phase-4
  • infra/ingest/ — Will retire with dignity, post-Phase-1+

storyline: The Solid Convergence