Measuring TypeSafe's Jev before wiring it in — it can tag an article, but not judge a translation
TypeSafe's Jev scored AUC 0.97 and stayed calibrated picking this blog's tags, but only 0.57 to 0.63 judging translated prose, so now it suggests draft tags.

On this page
Introduction
I had heard that TypeSafe’s Jev could sit between Claude Code and its tools and pick which ones to use, and I wanted to know whether it had a place in this blog’s pipeline. Jev returns no text, only a probability per question, and the costliest judgment here is an Opus agent reading every translation for sentences that sound translated.
So I measured Jev against labels on two candidate jobs before wiring it into anything. On picking an article’s tags it scored AUC 0.97 and its probabilities held up; on judging translated prose it scored 0.57 to 0.63, barely better than chance.
/blog new now asks Jev to pick a finished draft’s tags, using a threshold read off that measurement rather than chosen by feel, and translation review stays with the reviewer.
What Jev is
Jev takes one piece of state and a set of named, typed questions, and returns one typed answer per question: never a sentence. TypeSafe calls it a System One model. There are three question types:
choice, a pick among fixed options.score, one level from a low-to-high scale you define, up to 10 levels.noul, a yes/no question answered with the probability of yes.
The context window is 32,000 tokens, and OpenRouter notes that the probabilities vary somewhat from call to call.
OpenRouter’s own worked example asks all three types about one support ticket in a single request:
choice, a level for score, a probability of yes for noul. The values are from OpenRouter’s example.The first request: textbook translationese at 0.56
This is the first request I sent, through OpenRouter’s TypeSafe-compatible endpoint, with one noul asking whether a sentence reads as translated and one meaningless choice as a control:
{ "model": "~typesafe/jev-latest", "state": { "language": "Japanese", "sentence": "このアプローチを使用することによって、私たちはパフォーマンスを改善することができます。" }, "questions": { "a": { "type": "noul", "instructions": "Does this sentence read as translated from English rather than written natively?", "criteria": { "true": "Translationese", "false": "Natural native prose" } }, "b": { "type": "choice", "instructions": "pick", "criteria": { "x": "one", "y": "two" } } }}The response carried only numbers for each question (probabilities, plus how concentrated they are for the choice) and no text:
{ "model": "typesafe/jev-1.13-20260917", "answers": { "a": { "type": "noul", "noul": 0.56 }, "b": { "type": "choice", "choice": "x", "probabilities": { "x": 0.72, "y": 0.28 }, "confidence": 0.44 } }, "usage": { "input_tokens": 404, "output_tokens": 47, "cost": 0.000016968 }}A noul returns only the probability of yes. A choice returns a probability for each option (probabilities, summing to 1), the most probable option (choice), and confidence, which says how concentrated those probabilities are: 1 means all of it on one option, 0 means spread evenly across them.
Input costs $0.042 per million tokens and output is free, so the request above cost less than two thousandths of a cent. Several questions about the same state share one request, so later, when picking tags, one call per article covered every tag in the registry.
The sentence in that request is textbook translationese, a stack of 〜することによって and 〜することができます that no native writer would produce, but Jev put the chance that it reads as translated at only 0.56. The meaningless control choice drew a more decided 0.72 against 0.28. On this example, Jev could not tell whether a sentence reads as translated.
Calibration and AUC, checked against labels
A model is calibrated when its numbers mean what they say: across many answers given 0.8, about 80% turn out true. TypeSafe trains Jev for this. Calibration is a claim about a population of answers, so it can only be checked against a population of labeled examples.
Two numbers summarise such a check, and both appear in the results below:
- ECE, expected calibration error. Group the answers into ten probability buckets, compare each bucket’s average stated probability with how often its items were actually positive, and average the gaps. 0 is perfect.
- AUC, area under the curve, measures ranking. Sort the items by Jev’s score: AUC is the share of yes–no pairs where the actually-yes item ranks first, so 0.97 means 97%. At 1.0 a cutoff splits yes from no perfectly, at 0.5 no cutoff can, and at 0 the order is exactly reversed.
Neither number transfers from TypeSafe’s data to anyone else’s. Alex Molas makes the argument that calibration is a property of the data distribution as much as of the model, so the same probabilities can be calibrated on TypeSafe’s training data and wrong on yours. Every number in this article comes from this blog’s own labels.
First candidate: translation fluency review
Every Japanese and Traditional Chinese translation on this blog is read by a translation-native-reviewer agent, which runs on Opus and returns each passage that reads as translated with a replacement for it. Claude Code proposed putting Jev in front of it as a screen: score every line, and send the reviewer only the doubtful ones.
Git history held rule sweeps, not judgments
The obvious labels were the lines I had already rewritten. A translation line replaced in a commit that left the English source alone looked like a fluency judgment, so the first extraction took the pre-edit text of every such line as “rejected” and the untouched lines in the same files as “kept”.
It produced 592 rejected zh-TW lines, and reading them showed what they were. Most were glossary sweeps applied across the corpus, such as 工作流程 becoming workflow. Dropping changes where a term only switched script left 225; dropping changes where the new side was a glossary rendering, such as 智能體 becoming AI 代理, left 34.
Even the remaining 34 were mostly the em-dash budget, the zh-TW spacing rule and terminology. This repository squash-merges, so the draft a reviewer corrected inside a pull request never reaches history, and what history keeps is the rule sweeps that ran later. Japanese had 6 rejected lines in total.
A Jev run against those labels came back at AUC 0.54 for zh-TW. That says nothing about Jev, because the labels were not about fluency.
Labels from a reviewer that reads every line
Claude Code proposed taking labels from the reviewer, and I chose that route with a 10-file pilot. The reviewer reads the target file end to end before it opens the English source, so every line it does not flag has been read and passed. Its kept lines are real negatives, which is the half that git history could never supply.
I ran it on 10 published translations, five Japanese and five Traditional Chinese, from 10 different articles. A small script, fluency-record.ts, parses each report’s NOW: lines and matches them to the file’s prose lines:
INpnpm fluency:record --reviewer src/content/blog/<slug>/ja.mdx --report report.txtOUTreviewer <slug> ja: 41 prose lines, 11 rejectedThe ten reports came to 613 prose lines, 144 rejected and 469 kept. The same step now runs inside /blog publish before any finding is applied, and inside /blog polish after I finish reading a translation line by line, so the label set keeps growing and will eventually hold my judgments beside the reviewer’s.
Jev could not tell translated prose from native
Each line went to Jev on its own, as one noul:
const QUESTION = { type: "noul", instructions: "Would a native technical blogger writing in this language rewrite this passage because it reads as translated from English rather than written natively?", criteria: { true: "It reads as translated: English word order or sentence structure carried over, calques of English idioms, stiff or unnatural phrasing, or wording a native writer would not choose.", false: "It reads as written natively in this language. Technical terms, product names and code identifiers left in English do not count against it.", },};Against the reviewer’s labels:
| Lines | Rejected | AUC | ECE | |
|---|---|---|---|---|
| Japanese | 295 | 68 (23%) | 0.627 | 0.267 |
| Traditional Chinese | 318 | 76 (24%) | 0.573 | 0.275 |
Jev placed all 613 lines between 0.2 and 0.8, nearly all between 0.3 and 0.7. In Japanese the rejection rate does climb, from 16% of the lines in the 30–40% bucket to 41% in the 60–70% bucket. In Traditional Chinese the climb is nearly flat. Stated probabilities averaged around 50% against a real rejection rate under 25%.
Jev cannot take work off the reviewer. Say we want to miss at most 5% of the lines the reviewer would reject. Sort the lines by Jev’s score and move the cutoff down until it covers 95% of those rejections: it ends up at 0.34 in Japanese and 0.40 in Traditional Chinese.
By then most lines sit above it, so only 6% to 7% are left below it to skip review.
Jev saw each line alone, and that is the likeliest reason. Many of the reviewer’s findings exist only across sentences: a missing connective between two lines, a pronoun whose referent is in the previous sentence, three short sentences that should have been one.
Second candidate: tags, where the labels already existed
Claude Code proposed tagging next, because the labels were free. Every published article already carries tags I chose from a closed registry of 56, so a tag the article has is a positive and a tag it lacks is a negative.
One request per article asks one noul per registry tag, with the title and the first 12,000 characters of the body as the state:
instructions: `Is "${label}" one of the main subjects of this technical blog article, such that a reader browsing the "${label}" tag would expect to find it?`,The first article I tried carried git and developer-tooling. Jev returned git at 0.98, developer-tooling at 0.95 and github at 0.46, then nothing above 0.23, in 1.2 seconds for $0.0002. Across all 65 published articles the run cost $0.014.
Across 3,640 article × tag pairs it scored AUC 0.970 with ECE 0.049.
At both ends, where nearly all its answers fell, the numbers meant what they said: 89% of the pairs above 0.9 were real tags, and under 0.5% of the 2,884 pairs below 0.1 were.
My own tagging could have been wrong too, so I checked the 30 pairs where Jev and I disagreed most and fixed 11 tags across 10 articles. Re-scored against the corrected tags, AUC rose to 0.977 and the share of real tags above 0.9 to 95%.
Tag suggestions in /blog new
/blog new now leaves the tags to pnpm tags:suggest <slug> instead of the interview. Once the draft is written, the command scores it against every registry tag and offers each tag at 0.5 or above for me to accept or refuse. Jev only scores existing tags, so the skill then asks whether the article needs a new one.
The threshold comes off the tag measurement: of all the pairs at 0.5 or above, two thirds were real tags, rising to 95% above 0.9. The command also flags any existing tag below 0.16, where only 3% of pairs were real tags, useful when re-checking a published article. On the newest published article, already tagged, it printed:
INpnpm tags:suggest terraform-rebuild-console-aws-account-prod-spec-parity-oidcOUTterraform-rebuild-console-aws-account-prod-spec-parity-oidc: 3 tag(s) now: terraform, aws, github-actions 0.98 terraform 0.97 aws 0.28 github-actions
Jev would add (p ≥ 0.5): 0.79 opensearch 0.76 bedrock 0.75 automation 0.61 developer-tooling 0.57 agentcore 0.54 generative-ai
Jev doubts (p < 0.16): nothingA suggestion at 0.54 sits in the 0.5–0.6 bucket, where only 30% of pairs were real tags, which is why each one is a question rather than an edit. Without an OPENROUTER_API_KEY the command prints skipped and exits 0, and the tags are picked from the registry by hand instead.
Summary
Jev answers typed questions about one input with probabilities and no text, which makes it cheap enough to ask every tag in a registry about every article in one call each. Whether those probabilities mean anything depends on the job, and the only way to find out was to label examples and compare.
On a narrow question whose answer is in the input, picking an article’s tags, it ranked at AUC 0.977 and stayed calibrated, so it now suggests tags in /blog new with thresholds read off that measurement.
On an open-ended judgment, whether a sentence reads as translated, it ranked at 0.57 to 0.63 and gave nearly every line the same middling number, so translation review stays with the reviewer. The hardest part of both measurements was the labels, and git history could not provide them.
References
- What Is Jev? TypeSafe’s decision model explained for developers (OpenRouter)
- How to use Jev confidence scores, including thresholds checked against your own labels (Flavio Copes)
- Jev can’t be calibrated: why calibration belongs to your data distribution (Alex Molas)
- Just Ask Jev: Reinforcement Learning for Calibrated Decisions as a Zero-Shot Detector of AI Alignment Failures (arXiv)

