Cascadia Retail is a fictional 24-store chain with an ordinary warehouse and two famous bad numbers. This case walks the whole arc — the company, the data, the ask, the design and its reasons, and the system live — and every number in it is recorded, never illustrated.
Cascadia Retail — the setup
Chapter 1 of the case demo: the company, the data they have, and what they asked for. Nothing here is about Columna yet — this is the situation any solution would face.
The company
Cascadia Retail runs 24 stores across four regions (north, south, east, west), selling about 600 products to a customer base of roughly 10,000 registered accounts. A small data team maintains a warehouse; a Sales Operations team lives in it.
The data they have
The warehouse is ordinary — which is to say, it has history. Fourteen tables:
The facts:
transactions— one row per sale line: customer, store, product, day, amount, units, units returned, a satisfaction score (often null), and the customer's region copied onto the row. ~20,000 rows over two years.eom_inventory— daily stock snapshots per store: store, day, level. ~17,000 rows.
The reference tables:
stores(24 — with region and opened_date),customers(~10,000 — with segment, region, signup date),products(600 — with base price),categories(12), andproduct_categories— a bridge, because a product can sit in up to three categories.calendar— two years of days mapped to week, month, quarter, year.
The rest — every warehouse has these:
- Four pre-built summary tables (
daily_revenue_summary,monthly_avg_order_value,monthly_unique_visitors,monthly_store_inventory) that someone made for a dashboard years ago. Convenient, and nobody is sure they're still right. - Two side tables from other teams (
support_tickets,engagement_scores— the latter covering only about half the customers). warehouse_notes— three rows of tribal knowledge, including: "summary tables are convenience copies; the base tables are authoritative."
The demo shows each table's schema and a few real rows before anything else happens — if you don't know the data, nothing downstream can make sense.
generated Fourteen tables, straight from the bundled
warehouse — the six that drive the story expanded, the rest in full (note
daily_revenue_summary's 716 rows against the calendar's 731):
transactions 19,995 rows
| txn_id | customer_id | store_id | product_id | day | amount | units | units_returned | satisfaction | customer_region |
|---|---|---|---|---|---|---|---|---|---|
| T00000015 | C003262 | S001 | P0512 | 2024-01-03 | 58.26 | 1 | None | 5.7 | north |
| T00000030 | C016296 | S001 | P0022 | 2024-01-05 | 218.18 | 12 | 0.0 | 8.2 | west |
| T00000045 | C010086 | S001 | P0511 | 2024-01-08 | 35.53 | 1 | 0.0 | None | east |
eom_inventory 16,839 rows
| store_id | day | level |
|---|---|---|
| S001 | 2024-01-01 | 5693.0 |
| S001 | 2024-01-02 | 5630.0 |
| S001 | 2024-01-03 | 5622.0 |
stores 24 rows
| store_id | name | region | opened_date |
|---|---|---|---|
| S001 | Store 001 | east | 2021-09-22 |
| S002 | Store 002 | south | 2021-09-22 |
| S003 | Store 003 | east | 2021-09-22 |
calendar 731 rows
| day | week | month | quarter | year |
|---|---|---|---|---|
| 2024-01-01 | 2024-W01 | 2024-01 | 2024Q1 | 2024 |
| 2024-01-02 | 2024-W01 | 2024-01 | 2024Q1 | 2024 |
| 2024-01-03 | 2024-W01 | 2024-01 | 2024Q1 | 2024 |
product_categories 870 rows
| product_id | category_id |
|---|---|
| P0001 | G07 |
| P0001 | G12 |
| P0002 | G09 |
daily_revenue_summary 716 rows
| day | revenue |
|---|---|
| 2024-01-01 | 2022.91 |
| 2024-01-02 | 1671.58 |
| 2024-01-03 | 2538.42 |
The other eight — references and the stale summaries the model won't use:
customers 10,157 rows customer_id, name, segment, region, signup_date
| customer_id | name | segment | region | signup_date |
|---|---|---|---|---|
| C000001 | Customer 000001 | premium | north | 2024-05-12 |
| C000006 | Customer 000006 | business | north | 2024-06-03 |
| C000007 | Customer 000007 | consumer | west | 2024-09-11 |
products 600 rows product_id, name, base_price
| product_id | name | base_price |
|---|---|---|
| P0001 | Product 0001 | 24.48 |
| P0002 | Product 0002 | 50.74 |
| P0003 | Product 0003 | 28.11 |
categories 12 rows category_id, name
| category_id | name |
|---|---|
| G01 | Category A |
| G02 | Category B |
| G03 | Category C |
monthly_avg_order_value 24 rows month, avg_order_value, n_txns
| month | avg_order_value | n_txns |
|---|---|---|
| 2024-01 | 139.91 | 619 |
| 2024-02 | 125.81 | 591 |
| 2024-03 | 127.25 | 648 |
monthly_unique_visitors 24 rows month, unique_visitors
| month | unique_visitors |
|---|---|
| 2024-01 | 617 |
| 2024-02 | 589 |
| 2024-03 | 646 |
monthly_store_inventory 554 rows store_id, month, total_inventory
| store_id | month | total_inventory |
|---|---|---|
| S001 | 2024-01 | 179656.0 |
| S001 | 2024-02 | 159713.0 |
| S001 | 2024-03 | 171408.0 |
support_tickets 500 rows ticket_id, customer_id, day, topic
| ticket_id | customer_id | day | topic |
|---|---|---|---|
| T00001 | C009003 | 2024-02-17 | return |
| T00002 | C005691 | 2024-03-10 | account |
| T00003 | C009177 | 2024-12-29 | shipping |
engagement_scores 5,028 rows customer_id, score
| customer_id | score |
|---|---|
| C000001 | 0.771 |
| C000007 | 0.989 |
| C000009 | 0.321 |
What Sales Ops asked for
Dana runs Sales Operations. Her team answers questions for regional managers all week, by hand, in SQL and spreadsheets. Her request, lightly edited:
"We want the team — and honestly, the managers themselves — to get answers from the AI assistant we already use, without waiting on us. But it has to be right, and it has to say what it's assuming. We've been burned."
The questions her team answers every week (this list is the requirement):
- Revenue and order count — by store, by region, by month, by quarter.
- Average order value, by month — and by store when a manager asks.
- Best- and worst-performing products this month; top stores per region.
- Return rate (units returned over units sold), by product and by month.
- End-of-month inventory position, per store.
- Unique customers who bought, by month and by region.
The two times they got burned (this is the trust bar):
- The inventory total. A deck went to the exec team with "total inventory by month" — daily snapshots summed across the month. The number was meaningless (thirty days of the same stock, added together), and nobody caught it until a warehouse manager laughed at it.
- The two revenues. Two decks in the same meeting showed different monthly revenue.
One had used
daily_revenue_summary; the other computed fromtransactions. They disagree — the summary is missing days — and it took an afternoon to find out which was right.
Who has to be served — and this matters as much as the questions:
Dana's team spans an analyst with eight years of context — she knows the summary
tables are stale, knows what level means, knows store S014 opened mid-year — and new
hires who know retail generally but none of this warehouse's folklore. Both must get
right answers: the veteran asking terse questions in her own shorthand, the new hire
asking vague ones without knowing what to ask. "If the right answer depends on knowing
our folklore," Dana says, "then the folklore has to live in the system, not in
Priya's head."
Her constraints:
- The assistant never gets raw table access. ("It will do what our interns did, faster.")
- Every answer states its basis — what was counted, over what population, with what caveats.
- If a question is ambiguous, it should come back as a question — not as a guess.
- If something can't be answered honestly, say so and say why.
What "done" looks like
A regional manager types "how did the west do last quarter?" into the assistant and gets a right answer with its assumptions attached. A new hire in week one gets the same right answer the eight-year veteran gets — and when their question is too vague, the assistant asks back instead of guessing. Dana's team stops being a query service. And the two failure modes above become impossible — not discouraged, impossible: the meaningless inventory total can't be produced without a warning, and the stale summary table isn't in the answering path at all.
Next chapter: how the data team scoped and designed the Manifold to meet this — the decisions, the naming, and what they deliberately left out.
Cascadia Retail — the solutioning
Chapter 2 of the case demo: how the data team went from Dana's request to a Manifold design. The decisions, the reasons, and what was deliberately left out.
Working backward from the questions
The team started from Dana's six questions and asked, for each: what data answers it, at what grain, along what paths? That trace decided almost everything:
| Dana's question | What it needs |
|---|---|
| 1. Revenue & orders by store/region/month/quarter | transaction facts; store, region, and calendar grains; a path from store to region and from day to the calendar |
| 2. Average order value | revenue ÷ orders — a defined ratio, one definition for everyone |
| 3. Best/worst products; top stores per region | the product grain; ordered, top-n answers |
| 4. Return rate by product and month | units sold and units returned, summed; their ratio |
| 5. End-of-month inventory position per store | the stock snapshots — position, not totals |
| 6. Unique customers who bought | a distinct count of customers, by month and region |
Two tables answer all six: transactions and eom_inventory. Everything else is
either a reference table serving the grains and paths, or out of scope.
What we verified before designing
A design is only as good as what you actually know about the data. The team checked; each finding became a decision:
eom_inventoryis misnamed — the data says daily. The name says end-of-month; the rows are one snapshot per store per day (~17,000 rows over two years). Almost certainly a fossil from when the feed was monthly. Decision: grain comes from the data, never from the name — the model treats it as the daily snapshot table it is.transactionsis a daily fact, and that's fine. Day grain, no timestamps — a daily rollup of an upstream transaction log the warehouse doesn't keep. A fact table summarizing a log is normal; the model just has to be honest that day is the finest time grain anyone can ask at.- The two facts have different grains. A transaction row is one sale line (customer × store × product × day); an inventory row is one snapshot (store × day). Different populations → they will be modeled as two separate populations, never silently mixed.
- The snapshots are a running level, not a flow. Summing them across days produces Dana's meaningless number. Decision: summing stock across time will be blocked by declaration — the first burn becomes impossible, not discouraged.
- The summary tables are stale.
daily_revenue_summaryhas 716 rows against 731 calendar days — fifteen days missing. That's the second burn, explained. Decision: summary tables are not sources. The base tables are authoritative (the warehouse's own notes agree). They stay in the warehouse; they don't enter the model. - Weeks don't nest in months. The team checked the calendar: ISO weeks straddle month boundaries. So the calendar rollup chain is day → month → quarter → year, and week hangs as its own path off day — it can't sit in the chain.
- A product can be in up to three categories. Any revenue-by-category rollup would triple-count. No question asks for it — but someone will. Decision: declare the relationship as explicitly many-to-many, so when the question comes, the refusal can name exactly why.
transactions.customer_regionis a denormalized copy. "By region" in Dana's questions means store geography (managers own stores). Decision: one region concept, reached from store via the store table; the copied column is ignored.units_returnedis null on early rows — returns tracking started partway through the history. Decision: nulls count as no-return, and the return-rate definition says so in its description (folklore into the system).- Stores opened on different dates — S014 mid-year. Snapshot rows before a store
existed would poison averages. Decision: the inventory population is carved by
day >= opened_date— Priya's knowledge, now a declared predicate.
The design
Two populations (universes):
One thing this Manifold deliberately does not carry: the team's data contract — "you can't return
more than you bought." An early draft declared it here, adjudicated like everything else. It was
retired by a ruling worth stating, because it is the document's admission test: everything a
Manifold's trial proves is a precondition of something it serves. The contract is true of this
warehouse — but nothing served depends on proving it, so it is not meaning; it is attestation, and it
lives upstream. What remains in the Manifold is exactly the set of claims the answers stand on.
UNIVERSE transaction = customer * store * product * day BASIS events
UNIVERSE inventory = store * day
WHERE day >= store.opened BASIS spine
(Since 0.12 the manifold declares a third — category_profile, the driver spine behind the category faces; it enters the narrative with the crossing.)
Universe names are singular concepts — a universe names what its population is
about, never describes the records or the grid. (Notice the quiet split: the physical
table is transactions, plural; the universe is transaction, singular. And the
inventory universe isn't named for its store×day grid — the grid is its shape, not
its meaning.) The universe definition — products × predicate × basis — is the scope
contract: the Manifold binds to this declared population, and stays stable no matter
what else the warehouse grows.
events says: a missing combination means nothing happened — an honest zero.
spine says: this is a grid that should be complete — a missing row is a gap, and
answers over gaps must say so.
The atlas — the grains and the paths between them:
LEVEL customer, store, product, day (base grains)
LEVEL region, category
LEVEL cal.week, cal.month, cal.quarter, cal.year
HIERARCHY location {
store -> region
}
HIERARCHY calendar {
day -> cal.month -> cal.quarter -> cal.year
day -> cal.week
}
RELATE product <-> category ("up to 3 categories per product")
One declaration form for all functional paths: a hierarchy is a named family of
them — a single hop (location), a chain, or a small branching structure (calendar
needs the branch, because weeks don't nest in months). Every declared path is a claim,
tested against the actual tables. Lineage names name meanings — location,
calendar — and a bar like BLOCKED { calendar } bars the whole lineage, week branch
included.
The measures — named in the team's own vocabulary, each with a one-line description (Dana's folklore rule: if a new hire can't understand the name from its description, the name isn't done). Note what you don't see below: table names, column names. The Manifold spec is purely logical — it's the document everyone reads, so nothing physical crosses into it. How each name attaches to the warehouse lives in a separate document: the physical→logical map.
The Manifold spec (what everyone sees):
MEASURE revenue ON transaction -- "sale amount, summed"
MEASURE orders ON transaction -- "count of sale lines"
MEASURE buyers ON transaction -- "distinct customers who bought"
MEASURE units_sold ON transaction -- "units sold"
MEASURE units_returned ON transaction
-- "units returned; nulls predate returns tracking and count as no return"
MEASURE stock ON inventory -- "the stock level snapshot"
FAMILY {
sum BLOCKED { calendar } -- "stock summed across time doesn't reconcile"
last ORDER day -- "position = the latest snapshot"
}
DERIVED aov = revenue / orders
DERIVED return_rate = units_returned / units_sold
-- the team's data contract, checked against the data, not hoped
The physical→logical map (the data team's document) — and notice its shape: many to one. A warehouse accumulates multiple physical incarnations of each concept — copies, denormalizations, summaries — and the map's job is to resolve each many down to one authoritative binding, with the rejects kept on the map, with reasons. (Dana's second burn was exactly an unresolved many-to-one: two incarnations of revenue, no declared winner.)
logical binds to other incarnations (rejected, why)
───────────────── ─────────────────────────── ────────────────────────────────────
transaction transactions
inventory eom_inventory (name is a fossil — grain is daily)
revenue sum(amount) daily_revenue_summary.revenue (stale)
orders count(*) monthly_avg_order_value.n_txns (stale)
buyers distinct(customer_id) monthly_unique_visitors (stale)
units_sold sum(units)
units_returned sum(units_returned)
stock level monthly_store_inventory (stale rollup)
region stores.region transactions.customer_region (copy);
customers.region (customer's, not store's)
store.opened stores.opened_date
units (row attr) units (same spelling — a coincidence the
map records and the spec never needs)
calendar paths calendar(day, ...) location path: stores(store_id, region)
So the solutioning produces two artifacts: the physical→logical map (many to one —
the survey of the territory, rejects and all) and the Manifold spec (purely logical —
the output everyone reads). And the wall between them is not an accident of tidiness —
the Manifold is a blast wall, purposely built. The spec is self-sufficient: every
name in it means something declared in it, so a reader — or an agent — who never
sees the map loses nothing but plumbing. The map is the only place the two worlds
touch. Even when a logical name happens to share its spelling with a physical column
(the row attribute units), the spec's units means the declared attribute; the
coincidence lives on the map. Two things follow, and both matter later. Dana's "no
raw access" constraint costs nothing to enforce — the assistant isn't forbidden
from the tables; from where it stands, the tables don't exist. And the warehouse can
be re-plumbed — tables renamed, feeds replaced, summaries deleted — without a word of
the spec changing: re-bind the map, re-run the trials, done.
Three renames from the physical layer, each with a reason: buyers (not "visitors" —
these are customers who bought, and that's what Dana's question 6 says); units_sold
(the column is just units; the measure says what it means); and stock for the
inventory measure (the source column is called level, which collides with the word
for grains — a new hire reading "level by month" learns nothing; "stock by month" is
self-explaining).
generated One authored graph, two projections — the logical Manifold spec everyone reads, and the many-to-one physical→logical map with its rejects kept. ✓ the wall holds
The Manifold spec logical — what everyone reads
revenuesale amount, summedorderscount of sale linesbuyersdistinct customers who boughtunits_soldunits soldunits_returnedunits returned; nulls predate returns tracking and count as no returnprioritythe category's assignment rank — 1 ranks first; drives the primary facealloc_weightthe category's relative allocation weight — normalized per product at the crossing; drives the split facestockthe stock level snapshotaov= revenue / ordersreturn_rate= units_returned / units_sold
The physical→logical map many-to-one — the plumbing
| logical | binds to | rejected (why) |
|---|---|---|
transaction | transactions | |
inventory | eom_inventory | eom_inventory name is a fossil — the rows are one snapshot per store per DAY, not month-end |
category_profile | category_attributes | |
revenue | sum(amount) | daily_revenue_summary.revenue a stale rollup; the base fact is authoritative |
orders | count(*) | monthly_avg_order_value.n_txns a stale rollup |
buyers | distinct(customer_id) | monthly_unique_visitors.visitors a stale rollup — and 'visitors' is not the same concept as buyers |
units_sold | sum(units) | |
units_returned | sum(units_returned) | |
priority | last(priority) | |
alloc_weight | last(alloc_weight) | |
stock | level | monthly_store_inventory.level a stale rollup |
store.opened | stores.opened_date | |
region | stores.region | transactions.customer_region a denormalized copy carried on the factcustomers.region the customer's home region, not the store's |
location paths | stores(store_id, region) | |
calendar paths | calendar(day, month); calendar(month, quarter); calendar(quarter, year); calendar(day, week) |
What we left out, and why
Scoping is mostly saying no, with reasons a reader can check:
- The four summary tables — never sources. They're stale, the base tables answer everything, and their only honest purpose — query speed — is the engine's cache's job, not a table's.
satisfaction— real data, no question asks for it. Available when one does.- Customer segment, customer-region analysis — same: in the warehouse, not in the questions.
engagement_scores— covers only ~half the customers; any customer-level answer from it would be quietly wrong for the other half. Until coverage is understood, it's out — and that reason is recorded, not just the decision.support_tickets— another team's domain; Sales Ops didn't ask.- Revenue by category — deliberately not offered: the many-to-many makes an honest single-count impossible, and the declared relationship exists so the refusal can say exactly that.
Next chapter: the Manifold goes live — every claim above gets checked against the actual data and comes back with a verdict, and then the questions get asked.
Cascadia Retail — live
Chapter 3 of the case demo: the Manifold goes live. Every claim from chapter 2 gets checked, the questions get asked, and Dana's "what done looks like" gets tested. Everything shown here is real output from the running system — recorded, never hand-edited.
First, the trials
A Manifold isn't accepted on the author's word. Every claim in the chapter-2 spec is checked against the actual warehouse before anything serves:
| Claim | Verdict |
|---|---|
location: store → region is functional (one region per store) |
corroborated — 24/24 stores, one region each |
calendar: day → month → quarter → year chains cleanly |
corroborated — 731/731 days, every hop |
calendar: day → week (the branch that can't chain) |
corroborated |
| product ↔ category is many-to-many | recorded — a declared relationship, on the record so refusals can name it; its multiplicity isn't yet a tried claim |
transaction BASIS events (absence = nothing happened) |
untestable — the author's call, on the record |
inventory BASIS spine (absence = a gap) |
untestable — same |
And one row from the draft of this table is deliberately gone: the opened-date carve
(day >= store.opened) is not a claim on trial — it's part of the population's
definition. Nothing outside it exists to the Manifold, so there is nothing to test;
a definition confines, a claim gets tried. (For the record: the raw feed happens to
contain no pre-open snapshots today anyway.)
Two things to notice. The vocabulary is honest about what data can do: checked claims are corroborated — the data supports them today; only mathematical facts earn verified. And the basis claims are untestable — no data can prove what a missing row means; that's a human's call, and the system records it as one instead of pretending otherwise. And the verdicts aren't documentation — they're load-bearing: if the data ever contradicts a claim, that claim stops serving until someone fixes the data or the declaration.
The Explorer
The claims are tried; the Manifold stands. Before using it, look at it: everything declared above is browsable. The Explorer renders the Manifold spec — the logical document, nothing physical — with every declaration wearing its verdict: the universes with their basis and what absence means, the atlas with its two hierarchies, each measure with its laws, each claim with its trial. Every fact carries the triad: defined as (the declaration), tested (the verdict), show me (a query to copy). A new hire's first hour lives here: it's the folklore, out of Priya's head, on a page.
THE UNIVERSE VISUAL · FIGURE 1
Cascadia — three universes
Universe-first, and multi-universe as foundational: each population is a first-class block holding its basis and its metric families. The edges carry the distinction — solid hops are functional (many-to-one) paths; the one dotted edge is the product↔category frontier, crossed only through its three declared faces. Labels are verbatim from describe.
The hover, shown as a static pair (in the shipped visual, hovering a family member paints the stacks by traversability — CSS-only, no JS). Here the first burn, taught: the same stock over the same calendar stack, two members.
Left out by design (the spec + the map hold the detail): logical attributes, the map's reject rows, operator properties, provenance. The visual holds the shape; a caption links the Manifold spec and the physical→logical map.
Browse the whole Manifold live — every declaration with its law, its verdict, and a query to try — at /explorer.
The questions, asked — what the manifold is FOR
The veteran's way. Priya types tersely, in the query language:
SELECT revenue, orders AT {region, cal.quarter}
→ serve: thirty-two rows, four regions × eight quarters — two years of history. Every answer arrives as a pair — the numbers, and the basis they stand on (population: transaction; paths: location, calendar — both verified).
The first burn, retried. A new analyst — this is week two for him — asks for "total inventory by month, per store":
SELECT stock.sum AT {store, cal.month}
→ serve, with a caveat that can't be missed: the per-month figures come back, and
with them: stock summed across the blocked calendar lineage — per-bucket totals do
not reconcile along this axis; for month-end position, use stock.last. The
meaningless exec-deck number now cannot be produced silently. He reads the caveat,
switches to stock.last, and gets the position Dana's question 5 actually wanted.
The burn didn't need a policy or a training. It needed a declaration.
The ambiguous ask. "What was the average monthly order value for the year?"
SELECT avg(aov) AT {cal.year}
→ clarify: averaged from which grain? The average of twelve monthly AOVs and the pooled AOV over all transactions are different numbers. The system lists the readings; the asker picks; the number is exact. A vague question came back as a question — Dana's constraint, working.
The question that comes back with its reason attached — and then gets answered. "Revenue by category, please." → clarify: product ↔ category is many-to-many; this aggregate is underdetermined. And the answer now offers a menu of declared, lawful crossings:
•
category.touch— revenue reaches every category a product sits in — deliberately multi-counted; totals exceed the grand total
Re-ask the honest way — SELECT revenue AT {category.touch} — and it serves, in
disclose: twelve category rows, with the arithmetic of the crossing stated on the
answer itself: multi-counted by construction across product↔category … totals exceed
the grand total (touch total $3,182,555.97 against the single-count grand total
of $2,212,391.86 — about 1.44×, which is exactly the bridge's average of 870
memberships over 600 products; the over-count IS the fan-out, and the answer says
so), plus the coverage line: 600/600 — every product carrying revenue is
categorized; no shortfall; the over-count is the only skew. Nobody gets a silently
inflated number; anyone can get the deliberate one, labeled. The someday question
arrived years early — and by launch, it had an answer as well as a reason.
And the second burn? Nothing to show — which is the point. The stale summary
tables aren't in the answering path at all; there is one revenue, it comes from the
authoritative binding on the map, and the two-decks meeting can't happen again.
generated The same asks the packaged
demo --play runs, in story order — each a real wire outcome:
SELECT avg(aov) AT {cal.year} The ambiguous ask
SELECT stock.last AT {customer} A true refuse (the wheel needs one)
SELECT stock.sum AT {store*cal.month} The first burn, retried
SELECT aov AT {cal.month} The well-posed sibling
The MCP server
The assistant doesn't get table access — Dana's constraint. It gets an MCP server over the Manifold, which exposes exactly three things:
describe— the whole Manifold, machine-readable: every name, description, law, and verdict. The assistant reads this first; it's how it knows whatbuyersmeans and thatstock.sumis blocked over time. And it is all the assistant can see — the Manifold is a blast wall by construction, so "no raw access" is architecture, not a policy anyone has to enforce.query— FrameQL in, the four-mood answer out: result plus disclosure, always.explain— a dry run: what a query would do — its canonical form, the paths it takes, the verdicts it relies on, the mood it would return — touching no data. The assistant checks before it runs.
And the server carries knowledge — the operating instructions the assistant is
given: the grammar; the standing laws (a clarify is the human's question, never the
assistant's guess — relay it; use the declared names — an answer that renames things
teaches folklore all over again); and the pointer to describe as the source of
truth. The veteran's context, packaged and transferable.
The assistant, in conversation — recorded
What follows is the actual recording: human turns scripted, agent turns live against the shipped model, MCP, and prompt — tool calls visible, nothing fabricated. Long result frames are abridged with a marked ellipsis; the complete recordings ship in the repo, every take preserved.
The regional manager (never wrote SQL in her life):
Manager: How did the west do last quarter? Assistant: (couldn't read that as a grounded reply — the agent may only surface figures from a query result. Try rephrasing your question.)
Behind that line, the recording shows the agent consulting describe_manifold and
drafting a careful clarifying question — which measure, which quarter (the demo's
world is frozen; the assistant has no "today," so "last quarter" has no referent).
The grounding guard, strict about what may surface, suppressed the draft. Ugly UX,
honest bones: the system would rather say nothing than guess.
Manager: West, Q4 2025. Assistant: Here is the answer: revenue: region="west" cal.quarter="2025Q4" = 31,468.78; region="north" cal.quarter="2025Q2" = 71,424.56; (… 30 more rows — the full region × quarter frame; abridged here, complete in the recording)
The scoped question resolves the honest way this language version allows: the agent
anchors AT {region*cal.quarter} and the answer is in the frame — present, grounded,
and carrying more rows than the question wanted. A native coordinate filter is the
road ahead (it's on the ledger); this is what truthful agent output looks like this
side of it.
The new hire, week one:
New hire: How are we doing on returns? Assistant: (consults
describe_measure,describe_manifold, checks the plan withexplain— would-be: serve — then queries) Here is the answer: return_rate: cal.quarter="2024Q1" = 0.0146 … cal.quarter="2025Q4" = 0.0160; units_returned and units_sold alongside (both years, by quarter; abridged) · disclosure [freshness, immaterial]: served from cache
New hire: By month, this year. Assistant: The engine served the return-rate trend by quarter, with returned and sold units alongside — the values are shown above. One heads-up on the span: this covers the full recorded range (both years, quarter by quarter), not just this year — so you're seeing the whole trend, not a single current figure. Want me to narrow it — by region or store, or a specific quarter — or is this the view you needed?
The span reconciliation is the prompt's LABEL THE SPAN law firing live. Two warts,
kept because they happened: the agent fetched the null-convention folklore but served
without relaying it this take (the SURFACE THE FOLKLORE law is a bias on a mind, not
a guarantee), and it answered "by month" with the quarterly view it already had. The
check-before-you-run explain call, the honest cache disclosure, and the offer to
narrow are the machinery working exactly as designed.
How these transcripts were made
Four takes, every one preserved in the repo, none hand-edited: take 1 surfaced two
agent-prompt gaps (folklore unrelayed; a span mislabeled) → two laws were ratified
into the prompt. Take 2 confirmed the first law and surfaced a third gap (the
agent's SQL reflex, WHERE region = 'west', isn't this language — a real
expressiveness gap, now on the ledger as the leading post-launch language increment)
→ a third law. Take 3 showed all three laws effective and the remaining limit
architectural (the frame-weight above). Take 4 ships — one re-roll after a
defective attempt, both preserved; warts documented, not retouched. A law is a bias
on a rented mind, not a guarantee — which is precisely why every claim in this system
is checked rather than trusted, minds included.
What done looked like — the honest scorecard
Chapter 1 set the bar. Where it stands, in recorded output: the two burns are impossible — the meaningless inventory total cannot pass silently and the stale summaries aren't in the answering path at all. One definition of return rate, declared once, served everywhere. Ambiguity doesn't produce confident wrong numbers — though this take shows the guard suppressing a good clarifying question rather than asking it, which is the right instinct wearing rough edges. The folklore lives in the system and is served on demand — and one live turn shows the assistant forgetting to volunteer it, which is why it lives in the system. A new hire in week one gets the same grounded numbers the veteran gets; the polish of the relay — the single clean row, the never-missed folklore — is the named, ledgered road ahead, not a promise.
The whole case — the warehouse, the map, the spec, and every transcript on this
page — ships in the demo. pip install columna, and rerun it yourself.