← Writing

Core Swap · Part 2 of 5

Claim Check

Brief

Four cores could be run on recorded programs. Fourteen ways forward could not, from staying on alacritty and catching pictures myself to writing Terminal Delight’s own core, so six research agents wrote each one up: 420 values, each copied with the source passage it came from. Ranking on that much confident text inherits every overstatement in it. So Jev, a model that answers narrow typed questions with a probability attached, read the 315 facts that came with a quote and said whether each passage states what the agent wrote. Twenty-nine passages stated it outright. Most of the rest quoted the premise the agent had reasoned from.

Jev also read each core’s interface against thirteen things Terminal Delight’s code needs, and plain code did the ranking: wezterm-term 0.72, rio-vt 0.69. Before that, a harness caught Jev misreading how wezterm-term passes replies back. Six claims were checked against something more direct than the writing, and three were overruled, one of them Jev’s own reading.

Story tells it from a fact-checker’s desk. Technical has both Jev specs, the noise between identical runs, the ranking and what every call cost.

Portfolio

Story

The fact-checker’s desk

Terminal Delight, the terminal I’m building, needed a new emulator core, the library that turns a program’s output into the grid a terminal draws, because the core it had been using threw away the pictures programs send. Four candidate cores had already been run on recorded picture programs. Running only reaches so far. The full list of ways forward had fourteen entries: staying on alacritty’s core and catching pictures before it drops them, patching its parser, moving to another core written in Rust, crossing into C for Ghostty’s core or libvterm, writing Terminal Delight’s own, and two projects worth learning from rather than adopting. Six research agents took a cluster each and filled in thirty fields per entry, from licence and maintainers to which picture features the core implements. Any value taken from a source had to carry the passage it came from, word for word, and a merge script refused one that didn’t.

That made 420 values and a great deal of confident writing, and a ranking built on it would inherit every overstatement it held. So before anything was ranked, the pile went to a fact-checker, the way a magazine piece does before it runs: someone reads it with the sources open and asks of every claim whether the source says it. The fact-checker was Jev, a model from TypeSafe that answers narrow, typed questions with a probability attached instead of with prose. For each of the 315 facts that came with a quote, it was asked whether the quote states the fact, states part of it, implies it, says nothing about it, or contradicts it.

Twenty-nine came back stated outright. Most of the rest were conclusions: the quote was accurate and the conclusion reasonable, but the source didn’t say it. An agent quoted a line of source code or documentation and wrote down what follows from it, which is useful work and a different thing from a quotation. An earlier version of the check had no answer for that and filed them under “says nothing”. The third version gave them one of their own, and 29 facts took it. The agent assembling the research then labelled forty facts by hand without seeing Jev’s answers. Every time Jev said a quote states its fact, the label agreed. Jev said “contradicts” seventeen times, and reading all seventeen turned up no real contradiction, so that answer now sends a fact to a person instead of counting against a road.

A second check read each core’s interface against thirteen things Terminal Delight’s code needs, from reading one cell to handing a program’s replies back to it. For each, does the core provide it, provide it with work, not provide it, or does the evidence not say? Where a core had a harness, the fact-checker could be checked in turn, and once the harness won. Jev read wezterm-term, WezTerm’s core, as having no way to pass replies back, from research saying it has no reply event, only a writer it’s handed. The harness had caught its replies in exactly that writer.

Asking the same questions twice of the same evidence also changed a few answers in every hundred. With the top two roads a few hundredths apart, one run couldn’t carry the order, so every answer came from three runs, and a split with no majority was recorded as unknown. Unknown stayed out of the arithmetic instead of counting as zero.

The ranking was ordinary code over the stored answers, with weights that could change without asking Jev again. wezterm-term came first at 0.72, rio-vt, the core inside the Rio terminal, second at 0.69, and libghostty-vt, Ghostty’s, third at 0.62. Staying on alacritty scored 0.51, and most of that gap was pictures.

A fact-checker can confirm that a writer quoted a source correctly. It can’t say whether the source is right. Six claims could be checked against something more direct than the writing, and three were overruled: research said libghostty-vt would leave the cursor a row too low after a picture, and in the harness it landed where kitty’s rule says; a parser change an earlier brief called declined had lapsed after a friendly review, which the pull request’s later comments show; and Jev’s reading of wezterm-term. The ranking was the best the reading could do, and it rested on weights the agent assembling it had chosen.

I’d love to work with you. See the portfolio, or get in touch.

Portfolio

Technical

Two narrow questions, and code that ranks

The bake-off ran four cores. The research covered fourteen subjects, and for the other ten the evidence was what agents wrote. This part is how that writing was checked before code ranked it. Jev answered two narrow questions and never ranked anything, and the ranking changed twice while it was being built: once when a harness contradicted Jev, and once when repeated runs showed a single run couldn’t carry the order.

The research

A research-delight plan named fourteen subjects and thirty fields each, and marked every field as needing a source, a source or a flag, or derived by code. Six agents gathered in parallel, one per cluster. A value taken from a source carries a verbatim quote of at most 400 characters and says whether the agent measured or inferred it, and a merge script refused any value that broke the rule. Three rounds ran; the third added nothing new. That gave 420 values, 315 of them checkable against a quote.1

Where Jev sits

The request was to research the options, analyse them across many dimensions and rank them. Run through a should-jev pass, two of those steps are judgments about meaning that code can’t make exactly, and those are the only places Jev appears. The ranking step was rewritten: instead of asking which road is better, each core is asked about once and code compares the stored answers, so a change of weights re-ranks everything without another call.

claim-check: does the quote state the fact?

One request per fact, two questions: a Choice over states, states part, implies, silent and contradicts, and a Noul asking whether the quote describes something else. Code does what code can: whether the headline’s numbers appear in the quote, and whether the source is primary.2

VersionStatesImpliesStates partSilentTo a personNo verdict
11—22—180112
234—69112100—
32929639896—

Version 1 judged whole values, and a composite value read as half-stated; a number check that returned nothing left 112 facts without a verdict. Version 2 judged the headline, and most of its 112 silent answers were quotes of the premise the agent reasoned from, so version 3 gave that case its own answer. Forty facts were then labelled by hand, eight per answer, without seeing Jev’s: 24 matched exactly. When Jev said states, the label agreed 8 times in 8. It said contradicts 17 times, and reading all 17 found no real contradiction, which is why the verdict sends that answer to a person. The labels are the assembling agent’s, one labeller.3

core-fit: what each core offers Terminal Delight

One request per core asks thirteen Choice questions over its checked evidence (provides, provides with work, does not, evidence silent), weighted 3 for a must-have, 2 for important and 1 for nice; a second request asks how settled its API is. A silent, contested or low-confidence answer routes to unknown, which the ranking leaves out instead of scoring as zero. For the four cores the harnesses touched, 44 answers can be checked against what the code does.4

Version 1 got 4 of those 44 wrong. Rewording two needs into the vocabulary the evidence uses, adding each harness’s observations to its core’s evidence, and routing near-ties to unknown left none wrong and 4 unknown. rio-vt’s pictures are one of the four: asked 13 times from identical evidence, Jev put does not on top 11 times and never gave either answer more than 0.59. Adding one sentence from rio-vt’s source, that each image’s pixels are public, moved does not to 0.01. The need asks for an image, its position, its size and its pixels, and the evidence showed three of the four.4

Before wezterm-term had a harness, Jev read its reply channel as absent, from research that said it has no reply event, only a writer it is handed. The harness caught its Kitty OK and device-attributes replies in that writer, and with the observation in its evidence all three runs said provides. A repeat on unchanged input then changed 13 of 182 answers on cores whose evidence hadn’t moved. Identical runs differ on 3.6 to 6.6% of answers, and a question-order reversal run earlier to test for anchoring had changed 4.4%, inside that noise. The run of record is the majority of three runs per answer; 181 of 196 were unanimous. 42 of 44 traps held across both specs, and the two that sprang need a date window and outside knowledge.4

Reading against running

Six claims met something more direct than the writing, five of them a harness or the code, one the pull request’s own thread. Two held and three were overruled.1

ClaimFromRunning it
wezterm-term has no placeholder supportresearchheld: the placeholder characters printed as text
rio-vt exposes where each picture sitsresearch; Jev split near evenlyheld: every picture read from its public maps
libghostty-vt 0.2.1 moves the cursor a row further than kittyresearchoverruled: its cursor matched rio-vt’s in all seven recordings
vte’s maintainer declined a parser hook for picturesan earlier briefoverruled: the later review read “seems fine to me”, then the pull request lapsed
wezterm-term cannot pass its replies backJevoverruled: the harness caught them
the build each road asks fora keyword rule in the ranking codeit read “no C compiler, cmake” as needing CMake and misread 3 of 12

The ranking

Code scores each road on eight weighted dimensions: Kitty coverage today (3), fit from core-fit (3), how much Terminal Delight writes (2.5, an estimate), API stability from core-fit (2), maintainers (1.5), build (1.5), VT features (1) and other picture protocols (0.5). Unknowns are excluded. The bake-off and parse-speed columns are shown and not weighted, because a weighted column measured for a third of the field lets the other two-thirds skip it. Builds are read by hand since the keyword rule misfired.5

RoadScoreFirst in 10,000 random weightings
wezterm-term0.7274%
rio-vt0.6925%
libghostty-vt0.62under 1%
libghostty-vt beside alacritty, for pictures only0.550%
alacritty, with Terminal Delight reading pictures itself0.51under 1%

A rule written before asking any model (licence, then Kitty coverage, then build, then release activity) puts libghostty-vt first on its 14 of 14 Kitty features. With Jev’s two dimensions weighted zero, wezterm-term still leads, 0.74 to 0.70, so Jev’s answers narrow the lead without deciding it. Weighting the two measured columns brings the leaders within 0.001. Every Jev call behind all of this, across eleven runs, cost $0.063 for 1,137 requests and 3,234 questions.56

The ranking couldn’t see one thing that mattered to Terminal Delight. Its session host parses every terminal and sends a window a snapshot of the screen when it attaches, and with its use_serde feature wezterm-term’s lines serialize with their pictures, where rio-vt’s snapshot leaves them out. The recommendation at this point was a spike: each of the two as the host’s core, a window replaying it, pictures compared.

What would falsify this

Two claims could fail. That the order doesn’t depend on Jev: it holds with Jev’s dimensions weighted zero, but it rests on weights and rewrite estimates the assembling agent chose, and anyone setting either differently can reverse it. That running caught what reading missed: the harnesses ran each core outside Terminal Delight, and a core that behaves differently inside its host would mean they measured the wrong thing.

I’d love to work with you. See the portfolio, or get in touch.

Portfolio

Sources

  1. The research plan, the six agents’ parts and the merged rounds — round-1 parts A to D, the merged result of each round, and every value’s source and quote in terminal-core-candidates.html.
  2. claim-check: the spec, its traps and all three runs — Version counts are the verdicts in each run’s records under jev/runs, with every request’s receipt beside them.
  3. Forty hand labels for claim-check version 3 — Eight facts per answer, labelled by the agent assembling the research without seeing Jev’s answers.
  4. core-fit: its runs, ground truth and noise — Ground truth for 44 answers in jev/labels, written from Terminal Delight’s use of alacritty and the four harnesses. Run-to-run changes in jev/jitter.json; the three-run majority in jev/runs; the rio-vt experiment in ablate_rio.py and repeat_rio.py.
  5. The matrix, the random weightings and the re-rank without Jev — 10,000 Dirichlet draws over the eight weights, seed 20260925; results in jev/matrix.json and jev/what-if.json. The weights and rewrite sizes were the assembling agent’s first guess.
  6. What every Jev call cost — Summed from the usage OpenRouter returned on each request, across eleven runs on typesafe/jev-1.13. Trap probes write no receipts and are not included.