Seven rows, six questions, no identity merges
example.ts sends six Choice questions to jev-1.13.0 in one HTTP request, then joins the answers back onto seven invented contribution rows. Two rows contain exactly Contribution received from Mara Quill; both receive the same category judgment, while retaining their separate row IDs.
That reuse is the whole demonstration. Exact-key grouping is not proof of identity. The program classifies what a label says about a contribution; it does not decide whether two people are the same, split joint donors, resolve references, or merge records. It is neither the full article benchmark nor a production resolver.
Run without spending first
Requirements: a current Bun installation and these two files. There are no packages to install, repository imports, absolute paths, or Docker dependencies. Run the commands in the directory containing example.ts:
bun example.ts --dry-run > example-dry-run.jsonl
This requires no key and makes no network request. The JSONL request record contains the endpoint, exact serialized HTTP body, grouping counts, routing thresholds, and recorded pricing. With jq installed, inspect the body:
jq -r 'select(.event == "request") | .body' example-dry-run.jsonl
The question IDs are stable SHA-256 hashes of a version tag and the exact source label. No trimming, case folding, or fuzzy matching changes the grouping key. Instructions explicitly point to each unit's state path because question IDs themselves are not sent to Jev as instructions. The ID identifies this evidence representation, not a real-world donor; it is also not a privacy mechanism.
Make one real call
Set TYPESAFE_API_KEY in your environment through your normal secret-handling workflow. Then:
: "${TYPESAFE_API_KEY:?Set TYPESAFE_API_KEY before making the paid call}"
bun example.ts > example-run.jsonl
Authorization is sent only in the HTTP header, never in the logged request. The program makes one attempt, with a 30-second timeout covering the request and response body. It does not retry HTTP failures or follow redirects. Running the command again makes another paid attempt; there is no persistent cache. A timeout does not establish that the server did no work or incurred no charge.
The file preserves three records on success:
request: the exact request body and local policy.response: the unmodified response body as a JSON string, HTTP status, timestamp, and elapsed milliseconds. This is printed before validating the response, so a malformed answer remains inspectable.result: validated token usage, the recorded model-cost estimate, and every original row with its evidence ID, full Choice judgment, and typed routing decision.
jq 'select(.event == "result") | {usage, recorded_model_estimate, rows}' example-run.jsonl
The estimate is usage.input_tokens × $0.042 / 1,000,000; documented output-token pricing is zero. The code records the rate and documentation-check date, September 17, 2026. This is an estimate from reported usage, not an invoice or a benchmark result. On HTTP, transport, or validation failure, the process exits nonzero and emits no routing decisions. Inspect any saved response for usage; do not count a failed call as free.
What gets routed
The categories distinguish one person donating, an organization donating, people donating jointly, an explicitly unnamed donor, a recipient, and an unknown role. Recipient status takes precedence over entity type: a named fund receiving money is not thereby an organization donor. An unnamed contributor can be confidently classified as unnamed without acquiring an identity.
classified requires a non-unknown category, confidence at least 0.8, and selected-option probability at least 0.9. Otherwise the row becomes needs_review, with explicit reasons and the original probabilities intact. These are illustrative thresholds, not calibrated guarantees. Confidence summarizes the distribution; neither confidence nor a TypeScript type proves a judgment true.
The validator checks the model version, exact answer-ID coverage, Choice type and option, all probabilities, their sum, the winning option, confidence, and nonnegative integer token counts. It rejects invalid responses rather than filling missing answers.
For a tiny custom synthetic input, provide a JSON array whose objects contain exactly row_id and source_label:
[
{"row_id":"demo-1","source_label":"Joint contribution from Edda Lark and Oren Lark"},
{"row_id":"demo-2","source_label":"Joint contribution from Edda Lark and Oren Lark"}
]
Save it as synthetic-rows.json, then use either command:
bun example.ts --dry-run synthetic-rows.json
bun example.ts synthetic-rows.json > example-custom-run.jsonl
Limits are 16 KiB of input JSON, 1–12 rows, 512 UTF-8 bytes per label, and a 32 KiB serialized request. Row IDs must be unique, 1–64 ASCII letters, digits, underscores, or hyphens. Oversized inputs are rejected before inference, never truncated. The program cannot verify that supplied names are invented; do not feed it private records. Both input labels and raw answers are logged.
Where the article continues
In the full article's Jev-first pipeline, the corresponding uncertain judgments retain their source evidence and question IDs and go to targeted cheap reasoning codons under Hankweave. The pipeline composes their answers into case resolutions; unresolved or incomplete cases can then go to an adjudication codon. Those codons operate on richer evidence and a different contract, not just this category label.
This standalone program deliberately stops at needs_review. It does not launch Hankweave, call a reasoning model, or fabricate a review result. Its output illustrates the map-and-join boundary, not a drop-in input format for the benchmark. It computes no accuracy metric; elsewhere in the article, agreement with a reference must remain distinct from human-established truth.
API and pricing sources: HTTP contract, Choice, confidence, and model pricing.