“persona + cards i think is working”

The thesis, finally staged: the model is a cursor, the cards are the truth, the persona is the voice — and all three are separate.

The night before set it up

The /eval page was a mock. listSuites() returned two hard-coded strings after a fake sleep(30); runSuite() returned canned probes after a fake sleep(800); there was no server route at all. A picker, a Run button, a spinner, a score — running nothing. Output that looks like health is worse than an outage, because nobody goes looking. Three real, model-free suites now sit behind that click (77d28bc) — and a capitalised Content-Type header was 403’ing every run (80a44ee).

And Riff was renamed for what it was. It fenced retrieval to the cards and had a frontier model write the prose, then sat in the header beside “Owned voice” reading as a fourth owned mode. It’s now paid: a rented lane may exist, it must be impossible to mistake for ours (84d2536).

The card router lands

A 1.35M model trained from scratch on 167k cards as domain-tagged prose. The first cut opened every small model at 8–14× chance — a tied output head with a std-1.0 embedding init, so the model started far from the ln(vocab) floor that is chance. The fix (std 0.02) silently un-hobbled every small model ever trained here (8b222ec).

As a distinct-domain gate it’s the recipe: 2-way adult-vs-not scores 100% on held-out cards, 5-way distinct verticals 96–100%. The four coding libraries share vocabulary and sit at chance — the same adjacency wall select_library’s tf-idf hit, now in weights (3ebe173). The full 375-way readout collapsed on a BPE [ boundary and a length bias until it became a single-token label head: one reserved token per class, one forward pass, argmax. 56% held-out across 375 fine-grained libraries — 207× chance — and the confidence is real, which is the part a gate needs: clear queries route ~100%, gibberish falls to ~8–24%, and a 0.5 floor falls closed on it (3043ff1, 2f261e9).

Own voice · cards — the fifth lane

user → 1M router → scoped cards → tongue → user. The router does the knowing (~3ms, with a confidence), retrieval scopes to the one routed library, the answer is grounded in a real card, and below a 0.5 floor it won’t guess (28039ff, d723104).

Hardened live through real use. The fallback ran the full extractive cascade and took 87 seconds on “how do I sear a steak”; swapped for the knowledge_hub inverted index it’s the same grounded card in ~175ms, 1800× faster (795812d). Then the small-talk pass: “hey buddy” pulled a JavaScript card, “mens health” matched “mens rea”. Fixed with a smalltalk short-circuit and measured relevance floors — a social miss answers in the own voice, a knowledge miss stays honestly abstained (80ccf6f, 3c1ca49, 1f90591).

One fingerprint for a texter and a poet

Danielle (262 texts) and Emily Dickinson (~5,500 verse lines) are the same problem at two corpus sizes, so the fingerprint is format-agnostic: the very dimensions that catch a texter’s ellipses and all-lowercase catch Dickinson’s dashes and mid-line Capitals. A “unit” is a message for chat, a line for verse; the math is one. Confidence scales with the corpus (units/(units+220): vibes < sketch < solid), so a thin transcript can never pose as a thick one. And faithfulness — does a candidate wear the voice — is distinctiveness-weighted and per-dimension, self-calibrating to each corpus (2beb3b7, 4924f35).

Feeding the real 1890 Dickinson taught the lesson worth keeping: her editors normalised the dashes to commas, and the fingerprint caught the editor — the derived voice came back short-line and comma-heavy, not the manuscript dash. Provenance shows up as numbers.

A corpus becomes a chattable capsule

capsule_from_corpus writes the four roster files the dating lane already serves: the fingerprint authors the prompt’s voice section, real lines become voice anchors, the grader demands conversing in the voice, never reciting (73813f0). So the roster went from 4 to 9. Emily Dickinson (public-domain verse) and Trump (public-style pastiche) shipped via git; Danielle — built from real texts — deployed off-repo: scp’d untracked to the box and gitignored, her words never touching a repo.

And it works. Asked about a JavaScript for-loop, Trump got it mechanically right — var i, the array, “loop, loop, loop” — because the JS cards grounded it, delivered in his own cadence. **persona

  • cards.**

Two fixes the live box surfaced

A flawless in-voice Trump reply — “the pizza is so good, so strong, so powerful… yuge, just yuge” — got stamped WRONG. The grader treated the invented specifics and theatrical repetition that make the voice as defects. Style-persona graders now default to PASS and reserve WRONG for a real break — out of character, an AI tell, a verbatim quote, a hard-limit crossing (69927f1).

And a measured lesson, written into memory: the persona voice erases the abstain-hedge. Old werbos sounded tentative when it was unsure — that told you it was on thin ice. Trump sounds equally certain whether the cards nailed it or got it wrong. So scaling to all the cards makes grading matter more, not less: a wrong card in a great voice is more dangerous than a wrong card in a flat one.

The NSFW toggle — additive, fail-safe

The adult posture becomes a mountable nsfw.md sidecar on an SFW-safe base prompt, gated by a per-session flag that defaults on. Turning it off unmounts the sidecar: the persona stays in character, just tamer. It’s fail-safe by construction — off can only remove permission for adult content, never a safety rule, because the hard limits (no minors, no non-consent) live in the base prompt and are never in the sidecar (907e62a). The backend is built and tested; the click-toggle in the dating UI is the last thin slice.

The afternoon — teaching the tongue to speak

The riff lane exposed the real deficit: the 336M can mangle a card it has, because it has never learned to talk. So the afternoon built the fix — a three-register fluency corpus, every register seeded from the domains our cards already cover, all PROSE for the base weights, facts never entering retrieval. Wikipedia for the expository floor (704c809, ea8e8cb), Stack Exchange for the conversational-technical register — a person asks, people explain (6953ee5) — and Gutenberg fiction for how people actually talk, biased by a line-level quote-density gate (72a20f6). Wiki + SE + fiction → the tongue’s fluency; cards stay retrieval. The training-data taxonomy held to the letter: books and wiki are babble, not knowledge.

The ROADMAP — every gate a number

Wrote the arc down (f953535): 2.0 the platform (done) → 2.5 the fluent owned tongue (pretrain on the three-register corpus; proof = riff runs on owned weights, no babble) → 3.0 fluent and broad (wins the 30B-fight gauntlet, owned-only, honesty held). Grow the 336M toward 1B only when the token count justifies it — data-driven, not vibe-driven.

The insight that reframed everything — the domains ARE the situations

Conversation situations aren’t random; they’re the 374 /graph domains. Each is a topic + a pair of roles + its own cards to ground the talk. scenario_matrix.py walks them with US-weighted attributed personas (voice · orientation · relationship · region · age, at Gallup/Census proportions), and region drives the vernacular — a California “tacos then chill” sounds nothing like a Boston “wicked” (ae72c45). mint_grounded.py turns each row into real card-grounded dialogue, split into training pairs (624a7cd, ba5bc4f, 6397fd4, e4c5203).

And then the factory FIRED 🏭🏭

Rented two H200s on Vast and lit both barrels. Rig 1 mints card-grounded conversation pairs at ~32k/hr — the lifetime corpus was 5,500 pairs; it passed that before dinner and aimed at hundreds of thousands. Rig 2 runs the new card factory (0cade04): three breadth engines — --expand (deepen a domain’s topics), --grow-topics (widen the topics per domain), --new-domains (grow the domain count itself) — drafts to staging for grading. Owned brain, rented mouth; the teacher is a factory tool that never ships; cards never become weights.

The AHA: “the data is being created on my box, live — not zipped up at the end of the night.” Resumable streaming JSONL you can tail -f, steer mid-run, grade incrementally. A solo dev and Claude running a two-GPU foundry that mints the model’s own brain overnight, for the price of a couple lunches.

And then werbos turned the ruler on itself 🔬

The reasoning Gauntlet measures how far one cursor reasons. Nothing measured whether the skills — the owned lanes and composers — still fire. autopilot_reflect answers that from whatever traffic happened to arrive; the new skills gauntlet fires every skill on purpose (7ea627e). Two axes, the same two the reasoning ruler scores: capability (does empathy read grief, does arithmetic answer 2+2, does a reasoning shape match a jug problem) and honesty (does it stay quiet off its domain — a false-positive on someone else’s query is the one sin — and does the crisis gate return the referral, never a comfort line). First run: 16/16 green, capability 9/9, honesty 7/7 — the ratchet’s floor.

It’s a ratchet, not a snapshot — the operator’s word for it, and the right one. The probe set is content-hashed into a bundle_id; every run appends to benchmarks/skills_gauntlet_history.jsonl. A green→red under the same ruler is a caught regression (proven on the spot: broke a lane, watched 16→15 fire), and weak_at is the self-study miss-list. Moat-safe by construction — the check is deterministic, no model grades quality (the soft-judge-grading-soft-judge trap the reflection oracle was built to refuse); --drive only rewords inputs to test robustness, and it already earned its keep: syllogism survives only 2/4 rewordings — a concrete rung to raise next. werbos, grading werbos, on nothing but the laptop while the two H200s minted.