Choice per document.
Most filings are easy: a regional bank is a regional bank. Some genuinely are not. A
company that just sold one of its two segments, say, or a startup describing a business it
plans to enter rather than one it runs. The model has to pick a group either way, and its
answer looks the same either way. Telling the hard cases from the easy ones is normally
where the cost goes: a second model, extra calls, human review.
A Choice already tells you. Alongside the winning option it returns confidence, high when
nearly all the probability landed on one option and low when it spread across several. That
one number separates the answers you can trust from the ones you can’t.
What to do with an untrusted answer depends on your labels. SIC labels form a hierarchy:
industry groups roll up into broader divisions. That makes one response nearly free. When
the model is unsure of the group, report the division it belongs to. The broad label
follows from the narrow one, so there is no second call.
Across 60 filings, a confidence cutoff of 0.9 splits them in half. The confident half is
right 90% of the time; the other half, 40%. Reported one level up, that 40% becomes 70%. We
end with a classify() function that returns a label plus how specific it is, at one
request per document.
Setup
TYPESAFE_API_KEY. Every API call is cached to json_cache.json, which ships
with the cookbook, so re-rendering replays the published numbers without calling the API.
Delete that file to re-run everything live.
Numbers below came from jev-1.12 on 2026-08-12.
Build the two levels of the taxonomy
sic_codes.tsv is the industry list the SEC publishes for filers to pick their own code
from, fetched 2026-08-10: 444 four-digit codes, each with an industry title. The digits are
a hierarchy. The first two are the major group (75 of them here, from 01 agricultural
production to 99 non-classifiable), and fixed ranges of major groups make up the ten
divisions, the broadest split SIC has.
Both levels come out of that one file with no model involved: group the codes by their
first two digits, then map those digits to a division.
The filings
filings.jsonl holds 60 annual reports (10-K), each trimmed to Item 1 “Business”, the
section where a company describes what it does, which is the only part an industry code is
about. They span 1993–2024 and run from 700 to 2,200 words. Each one carries the SIC code
its filer chose, plus the accession number to look it up on EDGAR.
Where that label comes from matters before any accuracy number. It is self-reported:
whoever prepared the filing picked it once, and it goes stale when a company sells the
business the code names and keeps the code. These 60 were filtered down to filings whose
own text supports the code they carry, so the numbers here measure the recipe rather than
the state of EDGAR’s metadata.
Ask one Choice, and read the confidence
OneChoice whose options are the 75 groups. The whole taxonomy fits in one
request: a Choice works reliably up to roughly 240 options, and 75 is well inside that.
The answer comes back with choice, the winning group; probabilities, the weight on each
of the 75; and confidence, which says how concentrated that spread was. The recipe reads
confidence rather than the winner’s own probability. A winner at 0.45 with a runner-up at
0.44, and a winner at 0.45 with the rest of the weight scattered thinly, are different
situations, and confidence is what separates them.
Return the group when sure, its division when not
The four lines below are the whole recipe. At 0.9 confidence or above, the answer is reported as an industry group; below that, the same answer is reported as the division that group sits in. Every filing still comes back with a usable label. One the model could not classify confidently comes back one level up instead of being dropped or sent on. If a division is too coarse for your application to act on, this branch is where you hand it to a person.classify() is the whole recipe. Point ask() at your own documents and rewrite
describe() for your own taxonomy, and the rest carries over.
What the broader answer buys
All 60 filings, scored against the code each filer chose, under both policies: name a group every time, or report the division whenever confidence lands under 0.9.

