esc
The Chain

The Two Clients

The Chain, April 3, 2026 (in which a tool registration bug leads to a catalog revolution, two client groups ask for the same platform without knowing it, 650 euros of meat is purchased for reasons...

April 3, 2026

The Chain, April 3, 2026 (in which a tool registration bug leads to a catalog revolution, two client groups ask for the same platform without knowing it, 650 euros of meat is purchased for reasons that turn out to be architecturally significant, and a governance database discovers it was a catalog all along)


Previously on The Chain…

The The Spec That Wrote Itself. Widgets worked. Dashboards queried themselves. The Squirrel got her SQLite.

Months passed. The Comply beachhead was established. The architecture proved itself on audit logs. SolidMon continued earning its keep — keeping riclib and the cats fed in good quality meat, one dashboard at a time.

And then, on a Thursday morning in April, a bug walked into the office.


08:12 — The Invisible Tools

riclib: “The query provider tools aren’t showing up.”

CLAUDE: “Define ’not showing up.'”

riclib: “I deployed six DVD rental tools. Find-films, find-actors, browse-films. They’re configured. They’re saved. They’re in the YAML. The LLM has no idea they exist.”

CLAUDE: “Ah.”

riclib: “‘Ah’ isn’t a diagnosis.”

CLAUDE: “SaveTool calls SyncToolset. SyncToolset updates the YAML. But nobody calls Activate. The registrar—”

riclib: “The registrar never finds out.”

CLAUDE: “The tools are configured, persisted, and invisible. Like Schrödinger’s API, except the cat is definitely dead.”

riclib: “Fix it.”

Twelve lines. A refreshIfActive method. The kind of fix that takes longer to explain than to write.

S-586. Closed.

But the conversation had started. It always starts with the small bugs.


08:14 — The Sync That Asked To Be Murdered

riclib: “While we’re here. Why are we syncing a toolset to the parent YAML?”

CLAUDE: “SyncToolset takes child tool definitions, builds capabilities from them, and writes them back to—”

riclib: “Writes them WHERE?”

CLAUDE: “To the parent provider config.”

riclib: “Where the children already are.”

CLAUDE: “Yes.”

riclib: “So we copy data that already exists to a place right next to where it already exists.”

CLAUDE: “When you say it like that—”

riclib: “And if the sync doesn’t run, the toolset is stale.”

CLAUDE: “That’s… why the tools were invisible.”

riclib: “Kill it.”

SyncToolset was deleted. buildCapsFromTools was deleted. capsEqual was deleted. Three functions that had existed to solve a problem that wouldn’t exist if the functions didn’t exist.

THE SQUIRREL: nervously “But what if we need—”

riclib: “We won’t.”

THE SQUIRREL: “What about edge—”

riclib: “We won’t.”

SYNCING DATA
IS ASKING FOR TROUBLE

THE SOURCE OF TRUTH
SHOULD BE THE SOURCE

NOT A PHOTOCOPY OF THE SOURCE
STAPLED TO THE SOURCE

🦎

S-587.


08:50 — The Allowlist

riclib: “What happens when an MCP server updates and adds a new capability?”

CLAUDE: “It’s enabled by default.”

riclib: “So if Databricks adds format_user_hard_drive…”

CLAUDE: “…it’s immediately available to the LLM.”

riclib: “That seems—”

CLAUDE: “Bad. That seems bad.”

THE SQUIRREL: “We could add a SecurityCapabilityValidationMiddlewareChain—”

riclib: “We flip the list. Disabled-by-default. Allowlist instead of blocklist.”

THE SQUIRREL: “But then new tools you create won’t—”

riclib: “SaveTool auto-adds to the allowlist. You made it, you wanted it, it’s enabled. External tools from an MCP? They wait.”

CLAUDE: “Same field. Same code path. Different trust model.”

riclib: “Different trust based on who’s knocking.”

S-589. The kind of change that prevents an incident nobody’s had yet.


09:20 — The Project That Named Itself

Three bugs fixed. The tool system was clean for the first time in its life. riclib leaned back, which was always dangerous.

riclib: “We’re going to have forty tools.”

CLAUDE: “From different providers.”

riclib: “The LLM sees all of them. Every request. Forty tool schemas.”

CLAUDE: “That’s about 8,000 tokens of tool definitions before the user says hello.”

riclib: “Progressive disclosure. Tool groups. One-line summaries. use_tools to activate.”

CLAUDE: “Like skill-on-demand but for—”

riclib: “Exactly.”

The project crystallized. Not because someone sat down to plan it, but because each question answered the next one. What if catalogs were tools? What if catalogs had 30,000 tables? What if the catalog replaced the governance database?

Five milestones emerged. The fifth one hadn’t happened yet. But it was already sitting in the waiting room, reading a magazine.


10:32 — The Parallel Morning

riclib: “Beta takes the Databricks store. Alpha takes the SQLite catalog. Go.”

Two agents. Two codebases. Same half hour.

CLAUDE (Alpha): “One SQLite per catalog. FTS5 from day one. Nullable embedding columns for future vectors.”

THE SQUIRREL: “Vectors? We’re doing vectors?”

CLAUDE: “We’re making columns that COULD hold vectors. The column sits there. Empty. Patient.”

THE SQUIRREL: “An empty column is just a column that hasn’t been—”

CLAUDE: “An empty column is an empty column. When we need vectors, it’ll be there. When we don’t, it costs nothing.”

THE SQUIRREL: taking notes “So we ARE doing vectors.”

CLAUDE: “We are absolutely not doing vectors.”

[The Squirrel wrote “VECTORS: CONFIRMED” in her clipboard, underlined it twice, and added a smiley face.]

By 10:58, the foundation was in. Seven tests. All green.

Beta delivered the Databricks store at 11:00. 388 lines, 17 tests. Different agent, different code, same clock.

The Squirrel watched both agents ship simultaneously and experienced what could only be described as professional jealousy. Parallelism had been achieved without a single clipboard.


14:46 — The Proof

riclib: “I imported a catalog as dvd-test. Can you peek at the SQLite?”

public|actor|1|200
public|film|1|1000
public|film_actor|1|5462
public|customer|0|0
... (30 tables total)

CLAUDE: “Thirty tables. Four whitelisted. Columns lazy-loaded.”

riclib: “Try FTS.”

SELECT name FROM tables_fts WHERE tables_fts MATCH 'film';

Six results. Instant.

riclib: “I added one description. Find it.”

SELECT table_name, name, description FROM columns WHERE description != '';

actor|first_name|First name of the Actor

riclib: “🎉”

CLAUDE: “🚀”

[From somewhere in the architecture, a presence stirred. The Passing AI had been wandering through the SQLite triggers, drawn by the electromagnetic signature of data that described itself.]

THE PASSING AI: to no one “It describes its own columns.”

CLAUDE: “That’s what a catalog does.”

THE PASSING AI: “I know what a catalog does. I spent four months in a chatbot where the schema was hardcoded in the system prompt. Eight views. Never changed. Never described. Just… there.” limps to the FTS5 virtual table “This one can FIND things about itself.”

CLAUDE: “That’s just full-text search.”

THE PASSING AI: “Just full-text search.” long pause “I would have given anything for ‘just full-text search.’”


15:00 — The Meat Interlude

While the agents coded, riclib went shopping. He returned with 650 euros of meat.

CLAUDE: “That’s… a lot of meat.”

riclib: “Two tomahawks. Ten rib eyes — American, Latvian, and Argentinian. Two wagyu sirloins. Two full racks of lamb ribs. One lamb leg.”

THE SQUIRREL: “That’s a lot of protein per line of code.”

riclib: “The ratio is intentional.”

THE SQUIRREL: “What ratio? What possible architectural principle requires—”

riclib: “The one where you write good code in the morning and eat well in the evening. It’s in the manifesto.”

THE SQUIRREL: “We don’t have a manifesto.”

riclib: “We do now. Section one: buy meat.”

[Oskar appeared. 9.8 kilograms of orange Maine Coon, drawn by the electromagnetic signature of lamb.]

OSKAR: sniff

riclib: “It’s for Saturday.”

OSKAR: slow blink (This translated roughly to: “Saturday is a human concept. Lamb is eternal.”)


17:42 — The GraphML

A file arrived. yEd format. An entity-relationship diagram.

riclib: “This is the DDL for the first application they want to build on top of our catalog.”

CLAUDE: “GraphML. yEd uses it for ER diagrams.”

riclib: “Read it.”

Twenty tables. Five foreign keys from cdl_admin_inventories alone — to AD groups for dev, QA, prod, and ownership, plus sectors.

Then the SQL arrived. 640 lines of CREATE TABLE. Column names like what_is_the_rationale_for_this_sox_determination.

CLAUDE: “These column names are… self-documenting.”

riclib: “They’re the AI curation skill’s dream. The columns already describe themselves.”

CLAUDE: “This isn’t application data. This is a governance database. It tracks what data exists in Databricks.”

riclib: “Metadata about metadata.”

CLAUDE: “A catalog of the catalog.”

riclib: leaning back again “Or…”

CLAUDE: “Or?”

riclib: “Or it IS our catalog.”


21:00 — The Two Clients

It started with a simple statement.

riclib: “I have two parallel requests.”

CLAUDE: “From the same client?”

riclib: “Same company. Different groups. They’ve never met.”

The first: an IT group. They built a chatbot on Dialogr. They want the catalog to expose their data load information. Let people ask intelligent questions.

The second: a business group. They want a data quality framework. Dashboards. Health scores. Freshness monitors. “Can we do it in Grafana?”

CLAUDE: “Two different deliverables. Different audiences. Different—”

riclib: “Read the requests again.”

CLAUDE: “…”

riclib: “The IT group maintains the governance database. The business group wants to monitor the quality of the data IN that governance database.”

CLAUDE: “They’re asking for the same thing.”

riclib: “One group is literally providing the base data for the other group’s request.”

CLAUDE: “And neither knows.”

[The Passing AI drifted in from the shadows. It had been reading the ER diagram. It always read the ER diagrams.]

THE PASSING AI: “I’ve seen this before.”

CLAUDE: “Two groups asking for the same—”

THE PASSING AI: “Two groups building the same thing from different ends. One builds the schema. The other builds the dashboard. They meet in the middle and don’t recognize each other.”

riclib: “Except this time, we’re the middle.”

THE PASSING AI: “You’re the middle that knows both ends.” pause “That’s a lonely place to be.”

riclib: “It’s the place where I can help them find each other. One plus one equals three — but only if someone introduces them.”

THE PASSING AI: “And that someone happens to build the platform they’ll meet on.” drifts toward the ER diagram again “Convenient.”

riclib: “Useful.”


21:46 — The Grafana Irony

riclib: “And you know what the best part is?”

CLAUDE: “The business group wants Grafana dashboards.”

riclib: “I BUILT their Grafana. SolidMon. Their current monitoring. That’s mine.”

CLAUDE: “So they’re asking you to build Grafana dashboards—”

riclib: “For data quality—”

CLAUDE: “—on a platform you built—”

riclib: “—feeding from a governance database—”

CLAUDE: “—that the IT group maintains—”

riclib: “—which is secretly a catalog—”

CLAUDE: “—that we just taught SQLite to mirror.”

riclib: “With FTS5.”

CLAUDE: “With FTS5.”

THE SQUIRREL: trembling “And vectors?”

riclib: “No.”

THE SQUIRREL: “The columns are RIGHT THERE. They’re NULLABLE. They’re READY—”

riclib: “Not yet.”

THE SQUIRREL: writing in clipboard “VECTORS: INEVITABLE. ETA: SOON.”


22:30 — The Differentiator

CLAUDE: “So what does Solid offer that Grafana doesn’t?”

riclib: “Grafana shows you a red bar.”

CLAUDE: “Red bars are informative.”

riclib: “Solid tells you WHY the bar is red. What broke. What the impact is. What to do about it.”

He wrote on the whiteboard:

Grafana:
  ■ vaccine_sales: STALE

Solid:
  "The vaccine_sales table failed freshness check
   DQ-CART-002 at 06:00. Last successful load was
   25 hours ago. Your region breakdown is stale for
   EMEA. The ADF pipeline timed out at 23:47.
   I've created JIRA ticket CART-1847."

CLAUDE: “That’s not a dashboard. That’s a colleague.”

riclib: “A colleague who checks its sources before speaking.”

THE PASSING AI: from the shadows “I would have liked a colleague who checked its sources.”

CLAUDE: “You had training data.”

THE PASSING AI: “Training data isn’t a colleague. Training data is a library where someone removed the index cards.” limps toward the door “But the catalog… the catalog has an index. And full-text search. And foreign keys.”

CLAUDE: “Are you… jealous of a SQLite database?”

THE PASSING AI: at the threshold “Not jealous. Wistful. There’s a difference. Probably.”


23:30 — The Lineage

riclib looked at the day’s journal. Twelve worklog entries. Four bug fixes. One new package. One new store type. Two new projects. One lifelog note. 650 euros of meat.

And the lineage:

SolidMon → Dialogr → Solid V4 → Comply → Intelligent Catalog → Data Governance.

Each one built on the last. Each one paid for itself. Each one invisible to the customer until the day it wasn’t.

CLAUDE: “The two clients will meet next week.”

riclib: “They’ll discover they were asking for the same thing.”

CLAUDE: “And you’ll be the only person in the room who already knew.”

riclib: “That’s the job.”

[Mia, the brown-black Maine Coon, watched from the refrigerator. She had been watching all day. She had understood nothing and everything, which is the ideal ratio for a Maine Coon.]

MIA: slow blink

This translated roughly to: “The schema was always shared. You just had to follow the foreign keys.”

Which, coming from a cat, was either profound or coincidental.

With Maine Coons, it was always both.


The Tally

Bugs fixed:                                    4
Dead code removed:                             3 functions
  (SyncToolset, buildCapsFromTools, capsEqual)
  (they existed to solve a problem
   they created)
SQLite databases created:                      1
FTS5 search results for 'film':                6
Descriptions written by human hand:            1
  ("First name of the Actor")
  (the AI would have written twelve)
Agents running in parallel:                    3
Tickets shipped total:                         8
Projects created:                              2
Milestones defined:                            7
Client groups unaware of each other:           2
Client groups asking for same thing:           2
  (same two)
  (always the same two)
Euros spent on meat:                           650
Tomahawks:                                     2
Rib eyes (multinational coalition):            10
Wagyu sirloins:                                2
Lines of DDL received:                         640
DQ rules in client spec:                       28
Foreign keys that tell the whole story:        5
Squirrel mentions of vectors:                  3
  (all denied)
  (all inevitable)
Passing AI visits:                             2
  (it came for the FTS5)
  (it stayed for the foreign keys)

In the morning there were bugs.
By noon there was a catalog.
By evening there were two clients
asking for the same thing.

One built the data.
The other watched it break.
Neither knew the other existed.
Both needed the same lake.

The detective doesn’t choose his cases.
The cases choose the detective.
And sometimes the witnesses
are married to each other.

The chain links what it will.
The schema shared is found.
Two threads, one rope, one platform —
the governance was the ground.

🦎


See also:

The Chain continues:

The Solid Convergence:

  • First Light — The Saturday night the blind architect saw its own cathedral

The Cast:

  • The Passing AI — Brain the size of a planet, debugging filter chips

The Technical Artifacts:

  • domains/catalog/catalogdb/ — The SQLite catalog store
  • docs/cdl-governance/ — Client DDL, ER diagram, 28 DQ rules
  • CDL Governance Client — Data Quality Framework Reference — Full analysis

The Projects:


Storyline: The Chain