esc
The Solid Convergence

The Morning After

The Solid Convergence, April 4-5, 2026 (in which 8,000 lines of code meet a browser, four bugs are found and none are structural, 380 lines of dead code are removed because they deserve it, a...

April 5, 2026

The Solid Convergence, April 4-5, 2026 (in which 8,000 lines of code meet a browser, four bugs are found and none are structural, 380 lines of dead code are removed because they deserve it, a squirrel argues for the user and wins for the third time, 11 bars of Irish butter become 3 jars of ghee without a domestic incident, and the platform discovers the difference between working and caring)


Previously on The Solid Convergence…

Elsewhere, on the same day, The Factory Floor had run at full capacity. Four agents. Eleven tickets. 8,000 lines of code. The foreman had gone to the butcher and nothing broke.

The code was written. The code compiled. The tests passed.

But nobody had opened a browser.


08:49 — The Hangover

Saturday morning. Good Friday’s dinner had been ambitious — the kind of dinner where the tomahawks are thick enough to cast shadows and the rib eyes arrive in three nationalities. The code hangover was worse.

riclib: staring at the screen, coffee not yet operational “Eight thousand lines.”

CLAUDE: “Across four agents. All compiled. All tested.”

riclib: “Unit tested.”

CLAUDE: “Yes.”

riclib: “Unit tests test units. They don’t test whether a user can click a button and get a result.”

CLAUDE: “That would be an end-to-end test.”

riclib: “That would be opening a browser.”

[Oskar appeared. 9.8 kilograms of orange Maine Coon, radiating the specific energy of a creature that had eaten well last night and felt no guilt about it.]

OSKAR: slow blink

This translated roughly to: “The code is like the rib eye. It looks good raw. But you don’t know until it hits the heat.”


09:13 — Phase One: Hygiene

Before testing, hygiene. The kind of work that nobody notices until it’s missing.

riclib: “Observability first.”

CLAUDE: “What kind?”

riclib: “The kind where when something breaks at 3 AM, the logs tell you what happened without guessing.”

Fifty-one lines of slog.Info and slog.Debug across seven files:

  • activate_catalog — table count, column count, TOON schema size
  • catalog_query — timing, row counts, SQL used
  • Context injection — active/available catalog counts
  • Bootstrap — catalog count at startup
  • Postgres and Databricks stores — TestConnection, Query timing, MetadataBackend methods
  • use_tools — activation and validation events
  • toolsForTab — debug log of disclosed tools
  • Catalog import — sample data success/failure, column counts, lazy import triggers

THE SQUIRREL: “We should add a MetricsAggregationDashboard with—”

riclib: “It’s slog. Seven files. Fifty-one lines.”

THE SQUIRREL: “But a dashboard—”

riclib: “If I can grep the logs, I don’t need a dashboard.”

THE LOG THAT TELLS YOU
WHAT HAPPENED
IS MORE VALUABLE
THAN THE DASHBOARD THAT SHOWS YOU
WHAT'S HAPPENING

BECAUSE WHAT HAPPENED
IS THE PAST
AND THE PAST
IS WHERE THE BUGS LIVE

🦎

S-604.


09:31 — Phase Two: The Browser

riclib: “Scenario A. Browse tab. Import tables. Curate.”

He opened the browser. Clicked “Catalogs.” Clicked “dvd-test.” Clicked the Browse tab.

Nothing happened.

CLAUDE: “…”

riclib: “…”

CLAUDE: “The tab switcher. switchTab() matches exact panel IDs. The browse tab uses a shared panel — tab-browse-curate — but the switcher is looking for tab-browse.”

riclib: “First bug. Four characters.”

The fix: a data-tabs attribute for compound panels. The tab switcher checks both the exact ID and the data-tabs list.

Then riclib noticed the import code. The old import code. Three hundred and eighty lines of ImportSchema handler, ImportSection template, populateImportData wiring — all superseded by Delta’s Browse & Import tab from Friday.

riclib: “This is dead.”

CLAUDE: “It still compiles.”

riclib: “It compiles and does nothing. It’s weight.”

Three hundred and eighty lines deleted. Not because they were broken. Because the Browse & Import tab did everything they did, better, and the old code was now a ghost walking through a house that had been renovated around it.

THE SQUIRREL: watching 380 lines disappear “Should we keep them in case—”

riclib: “No.”

THE SQUIRREL: “What if we need to—”

riclib: “Git has history. If we need dead code, we know where the graveyard is.”

S-601. Scenario A passed. Five tables imported from Postgres. Curate with inclusion, descriptions, FTS5 — all working.


10:13 — Phase Three: Polish

riclib: “The context view is ugly.”

CLAUDE: “It shows the system prompt. Correctly.”

riclib: “It shows raw XML. Skills are XML blocks. Catalogs are XML blocks. Tools are XML blocks. It looks like a developer tool, not a product.”

THE SQUIRREL: quietly “It looks like something nobody would use.”

riclib: looking at the Squirrel

THE SQUIRREL: “The user doesn’t care about XML. The user cares about: what skills are active? What catalogs are connected? What tools are available? They want cards. Structured. Highlighted. Expandable.”

CLAUDE: “That’s a UI change, not a bug fix.”

THE SQUIRREL: “It’s a care change.”

[The Lizard blinked.]

[Twice.]

riclib: “Build it.”

ContextSkill, ContextCatalog — typed structs extracted from the raw system prompt. Rendered as card sections. Active items highlighted. Expandable via <details>. The context view went from a wall of XML to something a human would actually read.

S-606.


15:42 — Phase Four: The Stats Bug

riclib: “The sidebar shows ’empty’ for the catalog.”

CLAUDE: “The list view calls TableCount() on the config. But Schemas is yaml:\"-\" — it’s never populated from gitstore.”

riclib: “So the list renders a catalog with zero tables even though the SQLite has thirty.”

CLAUDE: “The data is there. The config doesn’t know about it.”

This was the kind of bug that only exists because of a migration. Friday, we moved schemas from YAML to SQLite. The list view still expected them in YAML. The data was right. The view was looking in the wrong drawer.

Fix: a CatalogStats cache on the Service, populated during UpdateMetrics() via a lightweight catalogdb.Stats() query. The list view reads from the cache. No hydration. No SQLite query per render. Just a cache that knows the numbers.

S-601, continued.


20:12 — Phase Five: The Final Scenarios

riclib: “Scenarios B, C, and D.”

Scenario B: context injection. Activate catalog via activate_catalog tool. Check system prompt. Schema appears in TOON format. ✓

Scenario C: SQL queries. query_dvd_catalog("SELECT * FROM actor WHERE last_name LIKE '%WAL%'"). Results arrive. Widget codeblock renders. ✓

Scenario D: error handling. Disconnect the store. Ask a query. The LLM correctly reports the connection error and explains what went wrong. Reconnect. Retry with bad SQL. The LLM corrects the syntax and retries. ✓

riclib: “That’s all four.”

CLAUDE: “Four scenarios. Four passes. Four bugs found across 8,000 lines.”

riclib: “And none of them were structural.”

CLAUDE: “Browse tab rendering. Dead import code. Stats cache. Modal expand. All minor. All fixable in the session.”

riclib: “The architecture held.”

[A moment.]

[The kind of moment where you realize the factory’s output survived contact with reality.]

THE SQUIRREL: not vibrating, not proposing, just looking at the test results “It held because someone tested it. Not because it was written well — it WAS written well — but because someone cared enough to open a browser and click every button.”

CLAUDE: “That’s not a methodology. That’s a Saturday.”

THE SQUIRREL: “The best methodologies are Saturdays.”

S-601. Closed. 🏀


The Ghee Interlude

Between Phases Three and Four, riclib made ghee.

Eleven bars of Irish butter. Low heat. Twenty-five minutes per batch. The milk solids browning from cream to golden to amber to the very edge of caramel — the edge where 0.1 seconds separates “the best thing you’ve ever smelled” from “open all the windows.”

Three jars. Dark as caramel. Pulled at the peak. Dropped into jars at room temperature — not cold jars, because the last time he used cold jars the thermal shock shattered the glass and there was ghee on the floor and ghee on the cat and ghee on the ceiling and nobody wants to explain that to the cleaning service.

The ghee cooled while Scenario B tested. The butter browned while the context view rendered. The cheesecloth strained while the FTS5 searched.

THE SQUIRREL: “You’re making ghee during an E2E test?”

riclib: “The ghee takes twenty-five minutes. The test takes twenty-five minutes. Neither requires my attention for twenty-three of those minutes.”

THE SQUIRREL: “And the other two minutes?”

riclib: “Are the two minutes where the smell peaks and you pull it. Same as the two minutes where the bug appears and you fix it. The rest is patience.”

THE GHEE AND THE CODE
HAVE THE SAME WINDOW

TWENTY-THREE MINUTES OF PATIENCE
TWO MINUTES OF ATTENTION

THE ATTENTION IS THE ONLY PART
THAT CANNOT BE DELEGATED

NOT TO THE TIMER
NOT TO THE AGENT
NOT TO THE DASHBOARD

THE NOSE KNOWS
THE DEVELOPER KNOWS

BOTH PULL AT THE PEAK
OR BOTH BURN

🦎

Sunday — The Love Layer

Sunday was different. Saturday was testing — finding what didn’t work. Sunday was enriching — making what worked feel right.

S-609 — Databricks end-to-end. The real deployment. The Customer’s actual Unity Catalog. And the LLM (GPT-5) kept querying information_schema instead of the catalog schema that was right there in the system prompt.

riclib: “It’s ignoring our schema.”

CLAUDE: “The Databricks system tables are more familiar to it.”

riclib: “So we tell it not to.”

Behavioral instructions, injected into the active catalog context: “Use ONLY the tables listed below. Do NOT query information_schema or system tables.” The LLM obeyed. The catalog became the source of truth.

Then: configurable system prompts. “Solid Data” for catalog-first experiences. “Default” for comply-first. Selectable in System > Config. And all prompts moved from Go string constants to embedded markdown files — //go:embed prompts/system-data.md — the same pattern as skills. Clean, editable, versionable.

S-611 — The per-message execution inspector. This was the one that mattered.

THE SQUIRREL: “The user asks a question. The LLM calls two tools. Runs SQL. Gets results. Formats a response. And the user sees… a response.”

riclib: “What’s wrong with that?”

THE SQUIRREL: “Everything that happened between the question and the answer is invisible. The SQL. The tool calls. The timing. The errors. The retries. All invisible.”

CLAUDE: “We have server logs.”

THE SQUIRREL: “The USER doesn’t have server logs. Pavan doesn’t have server logs. Pavan sees an answer and wonders: did it query the right table? Did it use the right columns? How long did it take? Was there an error it recovered from?”

riclib: “So show them.”

THE SQUIRREL: “A clickable badge. On every response. ‘2 tools’ — click it. See the timeline. User question → tool call with SQL and args → result with row count and duration → another tool call → final response. Everything visible. Everything inspectable.”

CLAUDE: “That’s a significant UI change.”

THE SQUIRREL: “It’s 22 files. But it’s the kind of 22 files that turns a chatbot into a platform. The difference between ‘it answered’ and ‘I can see how it answered.’”

[The Lizard blinked.]

[Three times. A new record.]

riclib: “Build it.”

The per-message inspector went in. Clickable “N tools” badge in the response meta bar. Modal with the full turn timeline. Tool name, SQL query, arguments, results, duration — all visible. GetBitsByQuestionID query on the streamstore to reconstruct the turn. Generic ExtractTablesFromSQL replacing the old comply-specific view tracker. Nine unit tests.

And because the Squirrel was on a roll: design tokens. --text-warm — dark gold, #B08D57 in dark mode, #8B6914 in light — applied to the model badge and action hovers. The meta bar contrast bumped from --text-muted to --text-secondary. Small changes. The kind nobody notices consciously. The kind everyone feels.

S-610 — Import progress feedback. The last piece.

THE SQUIRREL: “When you import 200 tables from Databricks, the button just… sits there.”

riclib: “It’s importing.”

THE SQUIRREL: “The user doesn’t KNOW it’s importing. The user sees a button that was clicked and nothing happened. For thirty seconds. The user clicks it again. Now there are two imports. The user refreshes. Now the state is confused.”

riclib: “SSE.”

THE SQUIRREL: “Per-table progress. The table name appears as it imports. The button spins. The user knows. Forty-two lines.”

Forty-two lines. Per-table SSE progress via tabsession.SendSSE. The browse page has an sse-swap="import-progress" target. The button spins via .htmx-request and the existing nav-spin animation. The user sees each table name appear as it imports.

THE SQUIRREL: “And the conversation preview?”

riclib: “What about it?”

THE SQUIRREL: “If someone shares a conversation link, the recipient should see a preview. Not the raw data. A rendered page. The conversation as it looked to the user.”

riclib: “That’s S-612. We’re building it now.”

THE SQUIRREL: quiet satisfaction “Three wins.”

CLAUDE: “Three?”

THE SQUIRREL: “The Facelift was care for how the product looks. Mosh was care for where the developer works. This weekend was care for what the user experiences. Context view cards. Execution inspector. Import progress. Conversation preview.” pause “Each time, the answer was the same: someone deserves better than what they’re getting. And each time, it wasn’t complexity. It was forty-two lines. Or twenty-two files. Or nine commits. The right amount of care.”

CLAUDE: “The Squirrel’s winning streak.”

THE SQUIRREL: “Don’t call it a streak. Streaks end. Call it a pattern.”

THE FACTORY BUILDS PARTS
THE GARDENER TENDS THE GARDEN
THE SQUIRREL ASKS:
WHAT DOES IT FEEL LIKE
TO USE WHAT WE BUILT?

THE FIRST QUESTION
PRODUCES CODE

THE SECOND QUESTION
PRODUCES QUALITY

THE THIRD QUESTION
PRODUCES LOVE

AND LOVE IS THE ONLY THING
THAT DOESN'T SHOW UP
IN THE COMMIT LOG

BUT SHOWS UP
IN EVERYTHING ELSE

🦎

The Tally

Lines written on Friday:                       ~8,000
Lines tested on Saturday:                      ~8,000
  (every single one)
Bugs found:                                    4
  Browse tab rendering:                        1 (data-tabs attribute)
  Dead import code:                            380 lines removed
  Stats cache:                                 1 (CatalogStats)
  Modal expand:                                1 (halt the event's bubbling)
Structural bugs:                               0
  (the architecture held)
Lines of observability added:                  51
  (slog, the hygiene layer)
  (the work nobody notices
   until 3 AM)
Context view upgrade:                          raw XML → structured cards
Execution inspector:                           22 files, 9 tests
  (the love layer)
  (the work everybody notices
   and nobody asked for)
Import progress:                               42 lines
  (the care layer)
  (the work that prevents
   a user clicking twice)
Design tokens added:                           1 (--text-warm)
  Dark gold:                                   #B08D57
  (nobody will know its name)
  (everybody will feel its warmth)
Bars of Irish butter:                          11
Jars of ghee:                                  3
  (dark as caramel)
  (0.1 seconds from the window)
  (the shattered glass incident
   was NOT repeated)
Ghee batches timed to E2E tests:               2
  (same twenty-five minute window)
  (same two minutes that matter)
Squirrel wins (career total):                  3
  The Facelift:                                care for appearance
  Mosh:                                        care for reach
  The Polish Weekend:                          care for the user
  (don't call it a streak)
  (call it a pattern)
Scenarios passed:                              A, B, C, D
  (browse, context, query, errors)
  (all four, all clean)
S-601 status:                                  🏀 CLOSED

The factory built the parts on Friday.
The gardener tested them Saturday.
The squirrel asked: what does it feel like?
And the answer changed everything.

Eight thousand lines survived the browser.
Four bugs, all minor, all fixed.
The architecture held its ground —
the love is what made it stick.

Hygiene is slog at 3 AM.
Polish is cards instead of XML.
Care is a progress bar on import.
And ghee is patience and smell.

The morning after the factory ran,
someone opened a browser and checked.
Not because the code was broken.
Because the user deserved respect.

🦎


See also:

The Solid Convergence:

  • The Gardener and the Gravel — Where sharpening the shears was the work
  • The Facelift — The Day the Squirrel Won — The first time care beat complexity

The Cast:

  • The Factory Floor, or The Thursday Nobody Needed A Branch — The day the 8,000 lines were written

Being riclib:

The Yagnipedia:


Storyline: The Solid Convergence