Two arcs today, and a stoned idea that turned out load-bearing.

The one mode

The chat’s three A/B pills collapsed to a single 1chat — one honest-and-fun mode, no toggles. The pieces that make it trustworthy landed underneath. A miss is no longer a dead end: when the owned cascade can’t ground a question but holds cards for the subject, it appends a labelled offer of the real cards (“I can’t verify that live, but I know Cabo San Lucas — want the rundown?”), delivered on a yes, cited. An ambiguous compute request now asks instead of guessing. “Show me the code” surfaces the exact program the previous compose ran — the answer and its proof are the same execution-verified object. And a neutral public house voice split off from the intimate operator voice, so a demo visitor never hears “let me check with Jason.”

Three moat leaks caught live and sealed: session-memory echoing turns back as facts, an orphaned “yes” grounding on a random card, and a variable that shadowed the code lane and crashed every code-gen. All fixed, all with a test.

The intent hierarchy

The operator’s inverted-Maslow insight: a person poking a chatbot lives at the top of the hierarchy (play, curiosity), rarely the bottom (crisis). So routing defaults to play, and every descent to a heavier lane must clear a confidence — and confidence is contextual, a running distress trajectory over the conversation, not a per-prompt keyword.

The crisis gate proves it. Explicit self-harm → the full 988 referral, always. Ambiguous (“i want to end it”) → the trajectory decides: a dark arc escalates to 988, a light or benign one (“end this level”) gets a soft check-in or nothing. It runs before retrieval, so a crisis can never fall to a Design-Thinking library card again. Crisis surface went 1/5 → ~5/5, live, including the multi-turn escalation (hopeless → worthless → “end it” → 988 by turn two). The same principle then fixed advice: “going to Hawaii, what should I do?” defaults to play (riff improvises real activities), while “should I quit my job?” descends to the decision framework. One contextual signal, a whole class of over-escalation bugs gone.

The facts ladder’s last rung

Deterministic broad fact-QA turned out genuinely brittle — the owned quorum engine is precise on who-won and what-is, but abstains on the long tail (how-many, when, a specific value), and two attempts to extend it deterministically produced confident off-topic answers. So the call: rent the extraction, under three hard guarantees that keep honest-abstain intact. The owned collectors fetch the sources (the full Wikipedia article now, so a height or a date below the lead is in scope, plus live news); a rented cursor reads only those pages, forbidden outside knowledge and required to return an exact ABSTAIN sentinel when the sources don’t answer — so a made-up subject or a wrong-sense article still abstains rather than fabricates. Every answer is labelled web-sourced and cited. Collect stays owned; only the read is rented, behind an opt-in flag. Verified live: the Eiffel Tower is 330 m, the Berlin Wall fell 9 Nov 1989, seven continents — all cited; the made-up subject and a suboptimal article both abstain. The coverage gaps are honest misses, never lies — which is the whole point.

The chat grows a memory

The second half turned HAIRLy on whole conversations, and each pass revealed the next layer. Multi-turn HAIRLy became runnable — a session-continuous driver plus a converse command — and its first run caught a stack of continuity bugs, fixed in order.

A sentiment misfire: “how’s the wine down there?” got “that’s a bummer” — bare “down” read the directional word as the emotional one. Then the foundation: the session store was process-global (one conversation for the whole daemon); now it’s keyed per caller, which fixes real multi-turn memory and closes a latent cross-caller leak. On top of that, a bare follow-up (“what should I pack?”) re-attaches to the live subject instead of grounding a random card; “going to Mexico” stopped assuming Cabo; the subject upgrades broad→specific once you name the place; session-memory stopped echoing your own statements back; and a repeated offer collapses to a terse nudge.

Then the play lane. Most trip chat has no cards behind it, so it lives in the riff — which had no memory: “going to Hawaii, what should I do?” riffed great, but “what food near Kaanapali?” dead-abstained. The riff lane got its own thread, so a follow-up continues the labelled riff instead of falling flat. And deixis: “weather down there?” now binds “there” to the active subject before grounding.

The real fix for that last one, though, wasn’t more routing — it was reaching for an API. Weather isn’t in the cards; it’s behind a service. So a weather question now hits a free live-weather tool and answers with the real current conditions, cited. Verified end to end: “how’s the weather down there?” in a Hawaii chat → “Kaanapali Beach: patchy rain, 77°F, humidity 79%”, cited, in six seconds. --net defaults on now — local-first is about your data, not blocking egress — so the whole list of read-only APIs is usable. This weather lane is the first; every other API slots in the same way: one detector, one fetch, one cite.