Which model should sort these complaints by product?
Each consumer-finance complaint goes to the product it is about. Eight options answered the same 5,117 held-out complaints; this page picks one and says how to switch to it safely.
What to do
It is within 3 points of the most accurate option, Qwen3-4B + LoRA, on these 5,117 held-out complaints (−2.0 points, paired 95% CI −2.9 to −1.2) and the cheapest option within that margin at 500,000 calls a month. Running it costs $1.20 per 1,000 calls, unverified price: $59.83 a month at 50,000 calls, $5,983 at 5 million. One-off: $750 (if ILLATE sets it up: ILLATE's fixed switch-to-Luna package on 9 Oct 2026, offered when Luna passes your test, covering the search over your labelled examples, the prompt and schema, the request changes and a shadow run. $0 in fees if your team builds it, plus that work). First year at 500,000 calls a month, as an assumption: $7,930 (12 months of running cost plus the one-off; section 02 has every option).
By volume. At 50,000 and 500,000 calls a month the pick is GPT-5.6 Luna (20 similar examples), at $59.83 and $598 a month. At 5 million it is Qwen3-4B + LoRA, at $815 a month against $5,983 for GPT-5.6 Luna (20 similar examples). Both are within the margin, so cost decides: they cost the same at about 681,000 calls a month. Below that, paying GPT-5.6 Luna (20 similar examples) per call costs less than keeping one Qwen3-4B + LoRA server on; above it, the server costs less. Qwen3-4B + LoRA is also 2.0 points more accurate (paired 95% CI +1.2 to +2.9). The price of GPT-5.6 Luna (20 similar examples) is unverified (section 02 names its source): at 500,000 calls a month it stays the pick only while its billed price is under about 1.4 times the one shown; above that, Qwen3-4B + LoRA costs less.
Where the 2.0 points go. Qwen3-4B + LoRA gets 104 more of the 5,117 held-out complaints right than GPT-5.6 Luna (20 similar examples), and 117 more on Credit reporting or other personal consumer reports alone (3,266 of them): more than the whole gap, so on the other categories taken together GPT-5.6 Luna (20 similar examples) gets more right. Section 03 has every category; name the ones that matter most to you and they become a gate.
The pick is a rented model, with no server to run. It earns ILLATE far less than building a model would: at most the fixed switch package, if you buy it. The provider can change or retire the model on its own schedule, so keep the harness in section 08 and re-run it on each replacement before switching.
What could change this pick. Scored on the 14 labels as filed instead of the 10 merged ones, the answer changes. TF-IDF + classifier comes first: TF-IDF + classifier 67.7%, Qwen3-4B + LoRA 67.0%, bge-base embeddings + classifier 64.3%, bge-small embeddings + classifier 63.7%, MiniLM embeddings + classifier 63.0%, GPT-5.6 Luna (20 similar examples) 62.3%, GPT-6 Luna (category list) 55.0%, GPT-5.6 Luna (category list) 51.2%. GPT-5.6 Luna (20 similar examples) is −5.4 points against TF-IDF + classifier (paired 95% CI −6.9 to −3.8), so the same rule and 3-point margin pick TF-IDF + classifier at every volume shown ($57.76 a month at 500,000 calls). The mapping was chosen after the answers were scored (section 10), so the recommendation above rests on a choice made after seeing the results. On 25 Aug 2023 the CFPB renamed three of its products, and the filing date isn't in the complaint text, so a model can only guess which of a product's two names was in use; for routing they are the same product.
GPT-6 Luna (category list) was tested here with one setup: the 14 product names as filed, no examples, reasoning none. Its best prompt in ILLATE's Banking77 bake-off, the 20 most similar training examples with a strict JSON-schema answer, finished 0.9 points behind ILLATE's fine-tuned model there: 93.1% against 94.0% (ILLATE's lead, paired 95% CI +0.1 to +1.7 points), up from 79.7% with the category list only, a bigger gain than GPT-5.6 Luna's there (85.4% to 93.8%) from a lower start. On CLINC150, where both started level with the category list (GPT-6 Luna 88.3%, GPT-5.6 Luna 88.4%), the same prompt gained them about the same (+6.1 and +6.3 points) and GPT-6 Luna again finished slightly lower (94.4% against 94.6%). A pre-registered run of that prompt on these complaints was not started: it did not fit the pre-registered spending cap for these runs. Its 20-complaint smoke test used about 5,425 input and 20 output tokens a call, against about 333 input tokens with the category list; prompt caching barely lowers that, because the examples change with every complaint. It needs about 1.4 more points for its whole paired interval to sit inside the 3-point margin. On these held-out complaints the same change of setup gained GPT-5.6 Luna 0.9 points, from 86.6% to 87.5% (paired 95% CI +0.1 to +1.7). A gain that size would leave it short of the margin; only the top of that interval would be enough, so the pick could still change. With that setup it would cost about $0.60 per 1,000 calls (estimated, unverified price): at 50,000 calls a month about $30.12 a month, against $59.83 for GPT-5.6 Luna (20 similar examples); at 500,000 calls a month about $301 a month, against $598 for GPT-5.6 Luna (20 similar examples). If it reached the margin, the same rule would pick it at those volumes. No run of the stronger setup for GPT-6 Luna (category list) is coming for this report: on your data, score it in the same run as GPT-5.6 Luna (20 similar examples). If it passes there, the pick is still a rented model, only a cheaper one.
At a 4-point margin, GPT-5.6 Luna (category list), TF-IDF + classifier and bge-small embeddings + classifier would pass too, and the cheapest would then depend on your volume (table below). The margin is your call: agree it before looking at a new run.
From 20 Oct 2026, before your current model stops on 23 Oct 2026, production moves to GPT-5.6 Luna (20 similar examples), the recommended option, or the needs_human_review queue (people triage every request: about 4,200 reviewer-hours a month at 500,000 calls, at 30 seconds an item) if its shadow gate hasn't passed by then (section 06).
Qwen3-4B + LoRA's scores on this page come from its saved answers (89.5%); served the way production would run it, it scored 89.1%. Against the served answers the other options are 1.6 to 3.4 points behind, not 2.0 to 3.9. At the agreed 3-point margin, MiniLM embeddings + classifier would be INCONCLUSIVE rather than FAIL. At a 4-point margin, bge-base embeddings + classifier would be PASS rather than INCONCLUSIVE; GPT-6 Luna (category list) would be PASS rather than INCONCLUSIVE. The pick at the agreed margin is the same.
The Luna costs on this page are the price file's per-token prices times 1.09. Our OpenAI bill for 8-9 Oct 2026 came to about 9% more than those prices for the same tokens, across both Lunas. The bill has no per-model split, so each Luna's own price is still unverified (each cost note in section 02 names the source). The 1.09 prices every input token at the full rate. If OpenAI discounted the tokens it cached, Luna's real per-token price is higher than shown, so treat these Luna costs as a floor. If your invoice shows Luna at k times the costs here, every Luna cost is k times higher and each volume below which Luna costs less falls to 1/k of the figure shown.
Scroll the table sideways for every column →
| If the agreed margin were | Options within it (PASS) | Cheapest at 50,000 calls a month | Cheapest at 500,000 calls a month | Cheapest at 5 million calls a month |
|---|---|---|---|---|
| 1 point | Qwen3-4B + LoRA | Qwen3-4B + LoRA$815 a month | Qwen3-4B + LoRA$815 a month | Qwen3-4B + LoRA$815 a month |
| 2 points | Qwen3-4B + LoRA | Qwen3-4B + LoRA$815 a month | Qwen3-4B + LoRA$815 a month | Qwen3-4B + LoRA$815 a month |
| 3 pointsused here | GPT-5.6 Luna (20 similar examples), Qwen3-4B + LoRA | GPT-5.6 Luna (20 similar examples)$59.83 a month | GPT-5.6 Luna (20 similar examples)$598 a month | Qwen3-4B + LoRA$815 a month |
| 4 points | GPT-5.6 Luna (category list), TF-IDF + classifier, bge-small embeddings + classifier, GPT-5.6 Luna (20 similar examples), Qwen3-4B + LoRA | GPT-5.6 Luna (category list)$4.29 a month | GPT-5.6 Luna (category list)$42.85 a month | TF-IDF + classifier$57.76 a month |
| 5 points | GPT-6 Luna (category list), GPT-5.6 Luna (category list), TF-IDF + classifier, bge-small embeddings + classifier, bge-base embeddings + classifier, MiniLM embeddings + classifier, GPT-5.6 Luna (20 similar examples), Qwen3-4B + LoRA | GPT-6 Luna (category list)$2.10 a month | GPT-6 Luna (category list)$21.04 a month | TF-IDF + classifier$57.76 a month |
The rule: the cheapest option whose whole paired 95% interval against the most accurate option sits above minus the margin, ranked on monthly cost at 500,000 calls, the middle of the volumes shown (the table shows where volume changes the answer). An option with no price is never called the cheapest.
Every option on the same items
Difference in accuracy from Qwen3-4B + LoRA, in percentage points, with the paired 95% interval. The shaded zone is within the margin.
Scroll the table sideways for every column →
| Option | Accuracy 95% CI | vs best, points paired 95% CI | Verdict | As filed 14 labels | Macro-F1 | Invalid / failed | Latency p50, p95 | Cost per 1,000 calls |
|---|---|---|---|---|---|---|---|---|
| Qwen3-4B + LoRA1fine-tuned by ILLATE on 17,905 complaints; a client keeps the weights · fine-tuned model you own, runs on a GPU | 89.5%88.7% to 90.3% | 0 | REFERENCE | 67.0% | 71.9% | 0 / 0 | 317 msp95 551 ms | $0.020at capacitymin $815/month |
| GPT-5.6 Luna (20 similar examples)2the 20 most similar training complaints as worked examples and a strict JSON-schema answer, reasoning none; pre-registered · prompted API model, rentedrecommended | 87.5%86.6% to 88.4% | −2.0−2.9 to −1.2 | PASSwithin the margin | 62.3% | 70.2% | 0 / 0 | 902 msp95 1,225 ms | $1.20unverified price |
| GPT-5.6 Luna (category list)3the 14 product names as filed, no examples, reasoning none · prompted API model, rented | 86.6%85.7% to 87.6% | −2.9−3.7 to −2.1 | INCONCLUSIVEundecided | 51.2% | 69.8% | 0 / 0 | 851 msp95 1,121 ms | $0.086unverified price |
| TF-IDF + classifier4trained on the same complaints · classifier you own, runs on a CPU | 86.6%85.7% to 87.5% | −3.0−3.8 to −2.1 | INCONCLUSIVEundecided | 67.7% | 61.5% | 0 / 0 | 1.0 msp95 1.2 ms | $0.000036at capacitymin $58/month |
| bge-small embeddings + classifier5trained on the same complaints · classifier you own, runs on a CPU | 86.4%85.5% to 87.3% | −3.1−3.9 to −2.3 | INCONCLUSIVEundecided | 63.7% | 62.6% | 0 / 0 | 232 msp95 504 ms | $0.0094at capacitymin $58/month |
| bge-base embeddings + classifier6trained on the same complaints · classifier you own, runs on a CPU | 86.2%85.2% to 87.1% | −3.3−4.1 to −2.6 | INCONCLUSIVEundecided | 64.3% | 64.7% | 0 / 0 | 507 msp95 1,116 ms | $0.022at capacitymin $58/month |
| GPT-6 Luna (category list)7the 14 product names as filed, no examples, reasoning none · prompted API model, rented | 86.0%85.1% to 87.0% | −3.5−4.4 to −2.6 | INCONCLUSIVEundecided | 55.0% | 68.2% | 2 / 00.04% of items | 944 msp95 1,867 ms | $0.042unverified price |
| MiniLM embeddings + classifier8trained on the same complaints · classifier you own, runs on a CPU | 85.7%84.7% to 86.6% | −3.9−4.7 to −3.05 | FAILoutside the margin | 63.0% | 63.3% | 0 / 0 | 97 msp95 156 ms | $0.0036at capacitymin $58/month |
- Qwen3-4B + LoRA (fine-tuned by ILLATE on 17,905 complaints; a client keeps the weights). Cost: modal-l4 at $0.80 an hour (https://modal.com/pricing ($0.000222 a second, $0.7992 an hour, rounded to $0.80); checked 8 Oct 2026), plus its container's 4 cores and 16 GiB at modal's $0.0000131 per core-second and $0.00000222 per GiB-second (https://modal.com/pricing; checked 8 Oct 2026): $0.3165 an hour, so $1.1165 an hour in all; one L4 GPU with 4 CPU cores and 16 GiB serves 26.34 requests a second (measured on these complaints at 64 requests in flight (p95 3,292 ms at that load), vLLM 0.31.0, 193 input tokens a call), planned at most 60% busy, so $0.020 per 1,000 calls at capacity. At least one is always on: $815 a month (730 hours); one carries up to about 41.5 million calls a month, and more are added above that. The container's 4 cores and 16 GiB are an assumption, ILLATE's planning size for a vLLM container, not measured on this run; Modal bills whichever is higher, what is requested or what is used. One-off: $3,000, if ILLATE builds it: ILLATE's fixed migration fee on 9 Oct 2026, nothing up front for the first three clients, and nothing owed unless the model meets the agreed margin. In-house instead: about 45 minutes on one H100 plus your engineers' time. Volume: below about 681,000 calls a month, one always-on server costs more than GPT-5.6 Luna (20 similar examples) at $1.20 per 1,000 calls, unverified price; below about 9.5 million calls a month, more than GPT-5.6 Luna (category list) at $0.086 per 1,000 calls, unverified price; below about 19.4 million calls a month, more than GPT-6 Luna (category list) at $0.042 per 1,000 calls, unverified price. Latency: one request in flight on one L4, 300 of these complaints, measured inside the server's container (no network); the saved answers' own timings are from batched offline generation and are not used. Invalid answers: constrained decoding: it cannot answer outside the label list, so zero invalid answers is by construction, not a measured quality.
- GPT-5.6 Luna (20 similar examples; the 20 most similar training complaints as worked examples and a strict JSON-schema answer, reasoning none; pre-registered). Cost: gpt-5.6-luna at $0.20 input and $1.20 output per 1M tokens (unverified: OpenAI's model documentation for gpt-5.6-luna, read from a public copy of OpenAI's docs; not yet checked on https://openai.com/api/pricing; read 8 Oct 2026), times the 5,367.8 input and 20.2 output tokens per call these answers used, times 1.09: our OpenAI bill for 8-9 Oct 2026 came to about 9% more than these prices for the same tokens (one factor for both Lunas; the bill has no per-model split), a floor: it priced cached tokens at the full input rate, and OpenAI may have discounted them; real-time, no caching or batch discount. In production each call also needs the complaint embedded and your labelled complaints searched for the 20 most similar: a small CPU cost, not counted here. One-off: $750, if ILLATE sets it up: ILLATE's fixed switch-to-Luna package on 9 Oct 2026, offered when Luna passes your test, covering the search over your labelled examples, the prompt and schema, the request changes and a shadow run. $0 in fees if your team builds it, plus that work. Latency: OpenAI API round trip from a Modal container, 4 requests in flight; finding the 20 similar complaints was done beforehand in one batch and is not in these times.
- GPT-5.6 Luna (category list; the 14 product names as filed, no examples, reasoning none). Cost: gpt-5.6-luna at $0.20 input and $1.20 output per 1M tokens (unverified: OpenAI's model documentation for gpt-5.6-luna, read from a public copy of OpenAI's docs; not yet checked on https://openai.com/api/pricing; read 8 Oct 2026), times the 333.5 input and 9.9 output tokens per call these answers used, times 1.09: our OpenAI bill for 8-9 Oct 2026 came to about 9% more than these prices for the same tokens (one factor for both Lunas; the bill has no per-model split), a floor: it priced cached tokens at the full input rate, and OpenAI may have discounted them; real-time, no caching or batch discount. One-off: no fee, the switch is a prompt and request change your team makes; ILLATE's switch-to-Luna package ($750 fixed on 9 Oct 2026, offered when Luna passes your test) sets Luna up with retrieved examples instead. Latency: OpenAI API round trip from a Modal container, 8 requests in flight, reasoning effort none.
- TF-IDF + classifier (trained on the same complaints). Cost: modal at $0.0000131 per core-second and $0.00000222 per GiB-second: $0.0791 an hour (https://modal.com/pricing; checked 8 Oct 2026); one CPU server (1 core, 4 GiB) serves 1,011.5 requests a second (one complaint at a time on one core, measured on 300 of these complaints), planned at most 60% busy, so $0.000036 per 1,000 calls at capacity. At least one is always on: $58 a month (730 hours); one carries up to about 1.6 billion calls a month, and more are added above that. One-off: no fee, built in-house: your team trains it on a CPU with the same harness. ILLATE has no fixed price for building one; your team's time is not counted. Volume: below about 48,300 calls a month, one always-on server costs more than GPT-5.6 Luna (20 similar examples) at $1.20 per 1,000 calls, unverified price; below about 674,000 calls a month, more than GPT-5.6 Luna (category list) at $0.086 per 1,000 calls, unverified price; below about 1.4 million calls a month, more than GPT-6 Luna (category list) at $0.042 per 1,000 calls, unverified price. Latency: one complaint at a time, in process, on one Modal CPU core (2 threads), no network; refitted with the saved run's settings; it agreed with the saved answers on 99.6% of test items.
- bge-small embeddings + classifier (trained on the same complaints). Cost: modal at $0.0000131 per core-second and $0.00000222 per GiB-second: $0.0791 an hour (https://modal.com/pricing; checked 8 Oct 2026); one CPU server (1 core, 4 GiB) serves 3.9 requests a second (one complaint at a time on one core, measured on 300 of these complaints), planned at most 60% busy, so $0.0094 per 1,000 calls at capacity. At least one is always on: $58 a month (730 hours); one carries up to about 6.1 million calls a month, and more are added above that. One-off: no fee, built in-house: your team trains it on a CPU with the same harness. ILLATE has no fixed price for building one; your team's time is not counted. Volume: below about 48,300 calls a month, one always-on server costs more than GPT-5.6 Luna (20 similar examples) at $1.20 per 1,000 calls, unverified price; below about 674,000 calls a month, more than GPT-5.6 Luna (category list) at $0.086 per 1,000 calls, unverified price; below about 1.4 million calls a month, more than GPT-6 Luna (category list) at $0.042 per 1,000 calls, unverified price. Latency: one complaint at a time, in process, on one Modal CPU core (2 threads), no network; encoder plus a linear classifier of the same shape, encoder max length 512 tokens.
- bge-base embeddings + classifier (trained on the same complaints). Cost: modal at $0.0000131 per core-second and $0.00000222 per GiB-second: $0.0791 an hour (https://modal.com/pricing; checked 8 Oct 2026); one CPU server (1 core, 4 GiB) serves 1.7 requests a second (one complaint at a time on one core, measured on 300 of these complaints), planned at most 60% busy, so $0.022 per 1,000 calls at capacity. At least one is always on: $58 a month (730 hours); one carries up to about 2.7 million calls a month, and more are added above that. One-off: no fee, built in-house: your team trains it on a CPU with the same harness. ILLATE has no fixed price for building one; your team's time is not counted. Volume: below about 48,300 calls a month, one always-on server costs more than GPT-5.6 Luna (20 similar examples) at $1.20 per 1,000 calls, unverified price; below about 674,000 calls a month, more than GPT-5.6 Luna (category list) at $0.086 per 1,000 calls, unverified price; below about 1.4 million calls a month, more than GPT-6 Luna (category list) at $0.042 per 1,000 calls, unverified price. Latency: one complaint at a time, in process, on one Modal CPU core (2 threads), no network; encoder plus a linear classifier of the same shape, encoder max length 512 tokens.
- GPT-6 Luna (category list; the 14 product names as filed, no examples, reasoning none). Cost: gpt-6-luna at $0.10 input and $0.50 output per 1M tokens (unverified: a third-party pricing article, not OpenAI; not yet checked on https://openai.com/api/pricing; read 4 Oct 2026), times the 333.5 input and 10.5 output tokens per call these answers used, times 1.09: our OpenAI bill for 8-9 Oct 2026 came to about 9% more than these prices for the same tokens (one factor for both Lunas; the bill has no per-model split), a floor: it priced cached tokens at the full input rate, and OpenAI may have discounted them; real-time, no caching or batch discount. One-off: no fee, the switch is a prompt and request change your team makes; ILLATE's switch-to-Luna package ($750 fixed on 9 Oct 2026, offered when Luna passes your test) sets Luna up with retrieved examples instead. Latency: OpenAI API round trip from a Modal container, 8 requests in flight, reasoning effort none.
- MiniLM embeddings + classifier (trained on the same complaints). Cost: modal at $0.0000131 per core-second and $0.00000222 per GiB-second: $0.0791 an hour (https://modal.com/pricing; checked 8 Oct 2026); one CPU server (1 core, 4 GiB) serves 10.2 requests a second (one complaint at a time on one core, measured on 300 of these complaints), planned at most 60% busy, so $0.0036 per 1,000 calls at capacity. At least one is always on: $58 a month (730 hours); one carries up to about 16.1 million calls a month, and more are added above that. One-off: no fee, built in-house: your team trains it on a CPU with the same harness. ILLATE has no fixed price for building one; your team's time is not counted. Volume: below about 48,300 calls a month, one always-on server costs more than GPT-5.6 Luna (20 similar examples) at $1.20 per 1,000 calls, unverified price; below about 674,000 calls a month, more than GPT-5.6 Luna (category list) at $0.086 per 1,000 calls, unverified price; below about 1.4 million calls a month, more than GPT-6 Luna (category list) at $0.042 per 1,000 calls, unverified price. Latency: one complaint at a time, in process, on one Modal CPU core (2 threads), no network; encoder plus a linear classifier of the same shape, encoder max length 256 tokens.
Accuracy intervals: 10,000 bootstrap resamples of the test items. Paired intervals resample the same items for both models, as illate parity does. Macro-F1 averages F1 over every category in the label list that has test items, so a category an option never predicts counts as zero. Invalid: an answer outside the label list. Failed: no answer after retries. Both count as wrong. As filed: the same answers scored on the 14 labels before the mapping in section 08.
What each option costs a month
Scroll the table sideways for every column →
| Option | 50,000 calls a month | 500,000 calls a month | 5 million calls a month |
|---|---|---|---|
| Qwen3-4B + LoRAfine-tuned by ILLATE on 17,905 complaints; a client keeps the weights · REFERENCE | $815$16.30 / 1,000 | $815$1.63 / 1,000 | $815$0.16 / 1,000 |
| GPT-5.6 Luna (20 similar examples)the 20 most similar training complaints as worked examples and a strict JSON-schema answer, reasoning none; pre-registered · PASS | $59.83$1.20 / 1,000 | $598$1.20 / 1,000 | $5,983$1.20 / 1,000 |
| GPT-5.6 Luna (category list)the 14 product names as filed, no examples, reasoning none · INCONCLUSIVE | $4.29$0.086 / 1,000 | $42.85$0.086 / 1,000 | $429$0.086 / 1,000 |
| TF-IDF + classifiertrained on the same complaints · INCONCLUSIVE | $57.76$1.16 / 1,000 | $57.76$0.12 / 1,000 | $57.76$0.012 / 1,000 |
| bge-small embeddings + classifiertrained on the same complaints · INCONCLUSIVE | $57.76$1.16 / 1,000 | $57.76$0.12 / 1,000 | $57.76$0.012 / 1,000 |
| bge-base embeddings + classifiertrained on the same complaints · INCONCLUSIVE | $57.76$1.16 / 1,000 | $57.76$0.12 / 1,000 | $108$0.022 / 1,000 |
| GPT-6 Luna (category list)the 14 product names as filed, no examples, reasoning none · INCONCLUSIVE | $2.10$0.042 / 1,000 | $21.04$0.042 / 1,000 | $210$0.042 / 1,000 |
| MiniLM embeddings + classifiertrained on the same complaints · FAIL | $57.76$1.16 / 1,000 | $57.76$0.12 / 1,000 | $57.76$0.012 / 1,000 |
Highlighted: the cheapest at that volume, whatever its accuracy. On a tie, the more accurate option, as in section 01: at 5 million calls a month TF-IDF + classifier, bge-small embeddings + classifier and MiniLM embeddings + classifier cost the same, so TF-IDF + classifier, the most accurate of them, is highlighted. The recommendation only considers options within the margin (section 01). Per-call options: price times the tokens their answers used, no batch or cache discount. Hosted options: at least one server always on, more when the volume needs them, planned at most 60% busy, at the throughput in the notes above. Running costs only: one-off costs to build or switch are in the next table.
First year, one-off costs included
Scroll the table sideways for every column →
| Option | 50,000 calls a month | 500,000 calls a month | 5 million calls a month |
|---|---|---|---|
| Qwen3-4B + LoRA$3,000 one-off · fine-tuned by ILLATE on 17,905 complaints; a client keeps the weights · REFERENCE | $12,781 | $12,781 | $12,781 |
| GPT-5.6 Luna (20 similar examples)$750 one-off · the 20 most similar training complaints as worked examples and a strict JSON-schema answer, reasoning none; pre-registered · PASS | $1,468 | $7,930 | $72,549 |
| GPT-5.6 Luna (category list)no one-off fee · the 14 product names as filed, no examples, reasoning none · INCONCLUSIVE | $51.42 | $514 | $5,142 |
| TF-IDF + classifierno one-off fee · trained on the same complaints · INCONCLUSIVE | $693 | $693 | $693 |
| bge-small embeddings + classifierno one-off fee · trained on the same complaints · INCONCLUSIVE | $693 | $693 | $693 |
| bge-base embeddings + classifierno one-off fee · trained on the same complaints · INCONCLUSIVE | $693 | $693 | $1,293 |
| GPT-6 Luna (category list)no one-off fee · the 14 product names as filed, no examples, reasoning none · INCONCLUSIVE | $25.25 | $253 | $2,525 |
| MiniLM embeddings + classifierno one-off fee · trained on the same complaints · FAIL | $693 | $693 | $693 |
An assumption, not a quote: 12 months of the running cost above plus each option's one-off cost to build or switch to it, as the One-off notes under the options table say (who does the work, at what price, and the alternative). Your own team's time is not counted for any option. Highlighted as above: at 5 million calls a month TF-IDF + classifier, bge-small embeddings + classifier and MiniLM embeddings + classifier cost the same, so TF-IDF + classifier, the most accurate of them, is highlighted.
Where the recommended option is weakest
Share of each category's test items that GPT-5.6 Luna (20 similar examples) labels correctly, for every category, weakest first, next to every other option.
Scroll the table sideways for every column →
| Category | Test items | GPT-5.6 Luna (20 similar examples) | Qwen3-4B + LoRA | GPT-5.6 Luna (category list) | TF-IDF + classifier | bge-small embeddings + classifier | bge-base embeddings + classifier | GPT-6 Luna (category list) | MiniLM embeddings + classifier |
|---|---|---|---|---|---|---|---|---|---|
| Debt or credit management | 5 | 0.0% | 0.0% | 20.0% | 0.0% | 0.0% | 0.0% | 0.0% | 0.0% |
| Payday loan, title loan, personal loan, or advance loan | 58 | 62.1% | 51.7% | 55.2% | 5.2% | 3.4% | 17.2% | 53.4% | 17.2% |
| Debt collection | 467 | 66.8% | 71.3% | 54.6% | 69.4% | 67.5% | 64.9% | 61.2% | 64.5% |
| Money transfer, virtual currency, or money service | 116 | 69.0% | 68.1% | 66.4% | 46.6% | 54.3% | 58.6% | 64.7% | 56.0% |
| Vehicle loan or lease | 102 | 78.4% | 71.6% | 82.4% | 47.1% | 70.6% | 69.6% | 83.3% | 68.6% |
| Credit card or prepaid card (merged) | 418 | 84.7% | 82.1% | 80.1% | 69.4% | 65.6% | 68.2% | 81.1% | 69.1% |
| Checking or savings account | 399 | 86.2% | 87.0% | 85.2% | 90.7% | 88.7% | 86.7% | 84.0% | 82.5% |
| Student loan | 84 | 91.7% | 91.7% | 95.2% | 85.7% | 88.1% | 88.1% | 96.4% | 90.5% |
| Credit reporting or other personal consumer reports | 3,266 | 91.9% | 95.4% | 92.9% | 94.9% | 94.5% | 94.1% | 91.1% | 93.9% |
| Mortgage | 202 | 96.0% | 90.1% | 97.0% | 87.6% | 88.6% | 89.6% | 96.0% | 87.1% |
What GPT-5.6 Luna (20 similar examples) gets wrong
Its most frequent mistakes, then the confusion matrix. Rows are the true category; each cell counts test items.
Scroll the table sideways for every column →
| True category | Labelled as | Items | Share of the true category |
|---|---|---|---|
| Debt collection | Credit reporting or other personal consumer reports | 106 | 22.7% |
| Credit reporting or other personal consumer reports | Debt collection | 104 | 3.2% |
| Credit reporting or other personal consumer reports | Credit card or prepaid card (merged) | 50 | 1.5% |
| Credit reporting or other personal consumer reports | Vehicle loan or lease | 44 | 1.3% |
| Credit card or prepaid card (merged) | Credit reporting or other personal consumer reports | 39 | 9.3% |
| Credit reporting or other personal consumer reports | Student loan | 27 | 0.8% |
| Checking or savings account | Money transfer, virtual currency, or money service | 26 | 6.5% |
| Money transfer, virtual currency, or money service | Checking or savings account | 24 | 20.7% |
Confusion matrix, every category
Scroll the table sideways for every column →
| True ↓ · labelled as → | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
|---|---|---|---|---|---|---|---|---|---|---|
| 1 · Checking or savings account | 344 | 17 | 4 | 1 | 1 | 26 | 5 | 1 | · | · |
| 2 · Credit card or prepaid card (merged) | 15 | 354 | 39 | 4 | · | 6 | · | · | · | · |
| 3 · Credit reporting or other personal consumer reports | 13 | 50 | 3,000 | 104 | 3 | 1 | 18 | 6 | 27 | 44 |
| 4 · Debt collection | 2 | 18 | 106 | 312 | 1 | 2 | 7 | 8 | 4 | 7 |
| 5 · Debt or credit management | · | 1 | 3 | 1 | 0 | · | · | · | · | · |
| 6 · Money transfer, virtual currency, or money service | 24 | 6 | 2 | 1 | 1 | 80 | 1 | · | · | 1 |
| 7 · Mortgage | 1 | 1 | 4 | · | · | · | 194 | · | · | 2 |
| 8 · Payday loan, title loan, personal loan, or advance loan | 2 | 10 | 6 | 1 | · | · | · | 36 | 1 | 2 |
| 9 · Student loan | · | · | 5 | 1 | · | · | · | 1 | 77 | · |
| 10 · Vehicle loan or lease | 1 | 1 | 15 | 3 | · | · | 2 | · | · | 80 |
Grey diagonal: correct. Shaded: mistakes, darker for more items. Column numbers match the row numbers. Cells are counts; each mistake's share of its true category is in the list above.
The categories with the fewest test items
Correct answers out of the test items in each category. With this few items one answer moves recall a lot, so the interval for GPT-5.6 Luna (20 similar examples) is shown too.
Scroll the table sideways for every column →
| Category | Test items | GPT-5.6 Luna (20 similar examples) | Qwen3-4B + LoRA | GPT-5.6 Luna (category list) | TF-IDF + classifier | bge-small embeddings + classifier | bge-base embeddings + classifier | GPT-6 Luna (category list) | MiniLM embeddings + classifier | 95% CI, GPT-5.6 Luna (20 similar examples) |
|---|---|---|---|---|---|---|---|---|---|---|
| Debt or credit management | 5 | 0/5 | 0/5 | 1/5 | 0/5 | 0/5 | 0/5 | 0/5 | 0/5 | 0.0% to 43.4% |
| Payday loan, title loan, personal loan, or advance loan | 58 | 36/58 | 30/58 | 32/58 | 3/58 | 2/58 | 10/58 | 31/58 | 10/58 | 49.2% to 73.4% |
| Student loan | 84 | 77/84 | 77/84 | 80/84 | 72/84 | 74/84 | 74/84 | 81/84 | 76/84 | 83.8% to 95.9% |
| Vehicle loan or lease | 102 | 80/102 | 73/102 | 84/102 | 48/102 | 72/102 | 71/102 | 85/102 | 70/102 | 69.5% to 85.3% |
| Money transfer, virtual currency, or money service | 116 | 80/116 | 79/116 | 77/116 | 54/116 | 63/116 | 68/116 | 75/116 | 65/116 | 60.1% to 76.7% |
Shadow first, then 5%, 25%, 100%
Dated to the shutdown, with a gate at each stage taken from the numbers above. Nothing moves to the next stage on a feeling.
Dates, from this report to 23 Oct 2026
- 9 Oct 2026Agree in writing: the 3-point margin, the label mapping in section 08, the interim model below, and who labels the shadow items.
- 11 Oct 2026Write the prompts and the request changes, set up any search for similar examples they use, score GPT-5.6 Luna (20 similar examples) and the stronger setup section 01 names for GPT-6 Luna (category list) on your held-out items, and re-run this report with those answers.
- 12 Oct 2026Shadow starts next to your current model (stage 1).
- 20 Oct 2026Production moves off the old model to the interim: GPT-5.6 Luna (20 similar examples), the recommended option, or the
needs_human_reviewqueue (people triage every request: about 4,200 reviewer-hours a month at 500,000 calls, at 30 seconds an item) if its shadow gate hasn't passed by then. Test the switch while the old model still answers. - 23 Oct 2026Fine-tunes of gpt-4.1-nano, o4-mini, gpt-3.5-turbo and gpt-4 stop answering. The interim serves production on and after this date until the gates below pass; shadow continues next to it.
- Then5%, 25% and 100% of live traffic, each when its gate passes: a gate is a check, not a date.
Labelling: the first gate needs 1,000 shadow items labelled by people. At 30 seconds an item (an assumption: time your reviewers on 20 items) that is about 8 reviewer-hours. Label them from shadow items your current model answered, before 20 Oct 2026: the first gate compares the new model with the answers production gave, and answers from the needs_human_review queue can't be compared (section 06, stage 1). Label a random sample of traffic, without showing either model's answer, so the comparison isn't tilted toward hard or easy cases.
Confidence and the review queue
No confidence scores were measured for GPT-5.6 Luna (20 similar examples) in this report. Measure them in shadow (illate defer picks a threshold on one labelled set and checks it on another) before the 5% stage; until then no answer carries a review flag.
Categories GPT-5.6 Luna (20 similar examples) gets right less than 50% of the time: Debt or credit management (0 of 5 right; mostly labelled Credit reporting or other personal consumer reports). Decide before the 5% stage whether any of these needs a rule.
Stages and gates
- 1. ShadowGPT-5.6 Luna (20 similar examples) answers every request, but only production's answer is used: your current model, and from 20 Oct 2026 the interim. People label a random sample.Gate to 5%on at least 1,000 labelled shadow items that a model answered in production (your current model before 20 Oct 2026),
illate parity --gold shadow-labels.jsonl --current production.jsonl --candidate new.jsonl --labels labels.json --mapping mapping.json --margin 0.03 --out parity-5pctsays PASS: paired accuracy on your reviewers' labels for the same items, the new model within the 3-point margin of what production served. Items theneeds_human_reviewqueue answered can't be in that comparison: a person labelled them, so production is right on them by definition. If production is on the queue before 1,000 model-answered items are labelled, this part of the gate is an absolute floor instead: the lower end of the new model's 95% accuracy interval on those labelled items (the candidate row of the same parity report) at or above 86.5%. Also: accuracy of at least 86.5% (Qwen3-4B + LoRA 89.5% here, minus the margin); no invalid answers (none were measured here; investigate any); p95 latency inside your budget (measured here: 1,225 ms). - 2. 5% of live trafficA random 5% of requests get the new answer: one category, or
defer(needs_human_review on this page) when its confidence is below the threshold you chose from the table above, and that item goes to a person from the start.Gate to 25%the share answereddeferis within a few points of the rate in the table; for each category with at least 50 labelled items pooled across weeks, the 95% Wilson interval of its recall reaches section 03's figure minus the margin (smaller categories are read by a person, not gated); no mistake pattern that section 04 doesn't show. - 3. 25% of live trafficThe same checks on a larger slice, for at least one full weekly cycle.Gate to 100%every earlier gate still holds on the pooled labels, and the rollback in section 07 has been tested once by flipping the switch and seeing traffic reach the fallback.
- 4. 100%Keep labelling a small random sample every week and re-run this report on it.Roll back (section 07) ifaccuracy pooled over four weeks falls below 86.5%; invalid answers rise above the gate; or p95 latency leaves your budget.
In the command: shadow-labels.jsonl holds your reviewers' labels, production.jsonl and new.jsonl each model's answers on the same ids, and labels.json and mapping.json are the label list and mapping in section 08. With --gold it compares accuracy on the labels; without it, illate parity would only measure agreement with production, mistakes included.
A rollback that still works after 23 Oct 2026
Fallback: a needs_human_review queue. The recommended option is itself the API model you would otherwise fall back to, so a rollback sends items to people instead. For a machine fallback, keep Qwen3-4B + LoRA ready: it is also within the margin.
The queue: items go to a needs_human_review queue and people triage them. Slower, and no machine label is applied: as accurate as your reviewers. At the 30 seconds an item assumed in section 06, sending all traffic there takes about 420 reviewer-hours a month at 50,000 calls, 4,200 at 500,000, 42,000 at 5 million.
Never the old fine-tune. Fine-tunes of gpt-4.1-nano, o4-mini, gpt-3.5-turbo and gpt-4 stop answering on 23 Oct 2026. A rollback plan that points at the model being replaced works until that day and fails on the first day you might need it.
When to roll back: a rollback trigger in section 06 firing, an earlier gate failing on live traffic (while production is the queue, the accuracy floor stands in for the paired comparison), a jump in invalid answers, or p95 latency leaving your budget. Rolling forward again repeats the stage that failed.
How to reproduce every number
Two ways: recompute the scores yourself from the published answers, or re-run the commands that produced this page. Same inputs give the same numbers: the bootstrap is seeded.
Check the numbers yourself
sample-decision-report-inputs.json holds the true label and every option's answer for all 5,117 items, as positions in the label list, with the label list and mapping and each option's settings, and the fixed text of the prompts named in section 02. It holds no example text and no raw model replies: an answer outside the label list is counted, not quoted. This recomputes every accuracy and paired interval in sections 01 and 02, the labels as filed and the answers as served included, with numpy alone, no ILLATE code:
import json
import numpy as np
b = json.load(open("sample-decision-report-inputs.json"))
def paired(y, a, c, n_boot=10_000, seed=2): # c minus a, as illate parity draws it
d = (y == c).astype(float) - (y == a).astype(float)
rng, n, means = np.random.default_rng(seed), len(d), []
chunk = max(1, 2_000_000 // n)
for s in range(0, n_boot, chunk):
means.append(d[rng.integers(0, n, (min(chunk, n_boot - s), n))].mean(axis=1))
lo, hi = np.quantile(np.concatenate(means), [0.025, 0.975])
return d.mean(), lo, hi
def table(title, mapping, answers, ref): # -1 is an answer outside the list: never right
name = [mapping.get(x, x) for x in b["labels"]] + ["(outside the list)"]
y = np.array([name[i] for i in b["gold"]])
ans = {k: np.array([name[i] for i in v]) for k, v in answers.items()}
print(f"# {title}: accuracy, then each option minus {ref}")
for k, a in ans.items():
diff, lo, hi = paired(y, ans[ref], a)
print(f"{k:55} {np.mean(y == a):.4f} {diff:+.4f} [{lo:+.4f}, {hi:+.4f}]")
table("section 02", b["mapping"], b["answers"], b["reference"])
if b["mapping"]: # section 01: the same rule on the labels as filed
table("as filed", {}, b["answers"], b["as_filed_reference"])
for k, v in b.get("served_answers", {}).items(): # section 01: one option as served
table(f"{k} as served", b["mapping"], {**b["answers"], k: v}, b["reference"])
for k, (a, c) in b.get("setup_gains", {}).items(): # section 01: what a setup added
table(f"{k} stronger setup", b["mapping"], {x: b["answers"][x] for x in (a, c)}, a)The commands that produced this page
illate is ILLATE's command-line harness; a client receives it with the weights and scripts. The answer files and measurements sit on ILLATE's Modal volume; every one is fingerprinted below, and the ones whose names start with sample-decision-report- are published next to this page.
modal run scripts/modal_bench_task.py # serving figures, measured on these complaints modal run scripts/modal_decision_report.py # mounts the illate-runs volume at /vol, writes the candidate list and mapping from MODELS and CFPB_MERGE in scripts/modal_bakeoff_data.py, then runs: illate decision-report --gold /root/data/cfpb-product/test.jsonl --labels /root/data/cfpb-product/labels.json --mapping /tmp/decision/sample-decision-report-mapping.json --candidates-file /tmp/decision/sample-decision-report-candidates.json --prices /root/data/prices/2026-10.yaml --shutdown 2026-10-23 --html /tmp/decision/report.html --json /tmp/decision/report.json --bundle /tmp/decision/sample-decision-report-inputs.json --bundle-attach 'luna category-list prompt=/tmp/decision/sample-decision-report-luna-prompt.txt' --input 'Luna category-list prompt=/tmp/decision/sample-decision-report-luna-prompt.txt' --input 'fine-tune serving measurements=/vol/bench/cfpb-product/bench.json' --input 'CPU timings=/vol/bench/cfpb-product/cpu.json' --input 'fine-tune training record=/vol/client-cfpb-product/lora/run.json' --input 'intake manifest (training count, label conflicts)=/vol/client-cfpb-product/manifest.json' --bundle-attach 'luna nearest20 prompt=/tmp/decision/sample-decision-report-luna-nearest20-prompt.txt' --input 'Luna 20-example prompt=/tmp/decision/sample-decision-report-luna-nearest20-prompt.txt' --input 'GPT-5.6 Luna 20-example run status=/vol/openai_fair_more/cfpb-product/gpt-5.6-luna/nearest20/run-status.json' --input 'GPT-6 Luna 20-example run status=/vol/openai_fair_more/cfpb-product/gpt-6-luna/nearest20/run-status.json' --input 'GPT-6 Luna 20-example smoke test=/vol/openai_fair_more/smoke/cfpb-product/gpt-6-luna/nearest20/test.preds.jsonl'
Every file read, with its SHA-256
Scroll the table sideways for every column →
| Input | File | Rows | SHA-256 |
|---|---|---|---|
| gold labels | /root/data/cfpb-product/test.jsonl | 5,117 | 96225227bea65dcbea4c31e0e736e068a0e91a7510892eb0f89846407f7537b6 |
| label list | /root/data/cfpb-product/labels.json | 39c82004ea2f20775b8a2f11c9b841b16c2b8acbda8bb57d1f3b52a75fcdb717 | |
| label mapping | /tmp/decision/sample-decision-report-mapping.json | f7747466bda03db9deea94352afb7950ed170807ac99ab9ba0e285ea14d84ff1 | |
| candidate list | /tmp/decision/sample-decision-report-candidates.json | 75e1d640292834ef0f6dcfcfaa1e3a1dc9a5e7ebf8240cf1371ee9c82a8e2ec9 | |
| price file | /root/data/prices/2026-10.yaml | 38cce9a330b41d9bfa08e1d9e00b35234664841d42d4a4c5d7b7d868361145cb | |
| Qwen3-4B + LoRA (fine-tuned by ILLATE on 17,905 complaints; a client keeps the weights) | /vol/client-cfpb-product/lora/test.preds.jsonl | 5,117 | 7d467110d13b74d83719a763293691c5d3defc86500b546801cd79ecef06e014 |
| bge-base embeddings + classifier (trained on the same complaints) | /vol/embed/cfpb-product/bge-base/test.preds.jsonl | 5,117 | 53425912186718c12d44fb54fce394b57fc6576ad3e856ed9a4219ce75bf9909 |
| bge-small embeddings + classifier (trained on the same complaints) | /vol/embed/cfpb-product/bge-small/test.preds.jsonl | 5,117 | 374af922265545dde075c2eb4e3eaa4dcfce5fd4eea185ceee5c426b1e9c7173 |
| MiniLM embeddings + classifier (trained on the same complaints) | /vol/embed/cfpb-product/minilm/test.preds.jsonl | 5,117 | 99255e870a838a961cd851abd272834e3124baa68036af2dc251789bd9636a4a |
| TF-IDF + classifier (trained on the same complaints) | /vol/client-cfpb-product/tfidf/test.preds.jsonl | 5,117 | e414a523bac62895ea0b500df66d676e0fd079a8bcdd74217490ba93b99e991d |
| GPT-5.6 Luna (category list; the 14 product names as filed, no examples, reasoning none) | /vol/openai_prompted/cfpb-product/gpt-5.6-luna/list-only/test.preds.jsonl | 5,117 | 40ef511a7f8c40d009bc6242c536826f7aa0da88d9b67d8cc61fc09ad8c209b9 |
| GPT-5.6 Luna (20 similar examples; the 20 most similar training complaints as worked examples and a strict JSON-schema answer, reasoning none; pre-registered) | /vol/openai_fair_more/cfpb-product/gpt-5.6-luna/nearest20/test.preds.jsonl | 5,117 | 685cdd880a708ae389bf60b5a24f9b62b4793b41071b1fc1e12ac320a133aebf |
| GPT-6 Luna (category list; the 14 product names as filed, no examples, reasoning none) | /vol/openai_prompted/cfpb-product/gpt-6-luna/list-only/test.preds.jsonl | 5,117 | c8dd5bc6d96523e99571cba47c9574d86c12dd2232523e11bdc5513ef4dfd6d4 |
| Qwen3-4B + LoRA (fine-tuned by ILLATE on 17,905 complaints; a client keeps the weights): answers as served | /vol/bench/cfpb-product/test.preds.jsonl | 5,117 | 50a8234acc7ab28333ca3fc6f20b2a88e61197133c750111aa09f4ddf2f97748 |
| Qwen3-4B + LoRA (fine-tuned by ILLATE on 17,905 complaints; a client keeps the weights): confidence analysis | /vol/bench/cfpb-product/defer-merged.json | 91adcbe232afaf3b81de9738fa2988a84a83bf762302ebd3813e7ec9c2103660 | |
| Qwen3-4B + LoRA (fine-tuned by ILLATE on 17,905 complaints; a client keeps the weights): answers with confidence | /vol/bench/cfpb-product/test.merged.preds.jsonl | 200be279aaa69deeeea7153de1f2514b77560908794d26f4fa01dd209dc55021 | |
| Luna category-list prompt | /tmp/decision/sample-decision-report-luna-prompt.txt | 92be55c4bac471f172fcc557801ca61d38ebf9cf7df52df2867e3ddc164f69e0 | |
| fine-tune serving measurements | /vol/bench/cfpb-product/bench.json | 306e7156a17787b6cffdfaf793c9a82d0feac88f3546691d972290c9e2fe6028 | |
| CPU timings | /vol/bench/cfpb-product/cpu.json | 6251ef052bf0b60b579439a00db816122c7a14c1f240545f3504bfe3fa635f35 | |
| fine-tune training record | /vol/client-cfpb-product/lora/run.json | 783732daaefc5d59c646628ce0dc48361b2a4d44d4ad061fa31da5fb25ea42f5 | |
| intake manifest (training count, label conflicts) | /vol/client-cfpb-product/manifest.json | c632657257ab1135955cb1281468f09c2ca119ae3486b74a199480152466a874 | |
| Luna 20-example prompt | /tmp/decision/sample-decision-report-luna-nearest20-prompt.txt | eebce4e75532f2dc100af7110c9f04aee54a96be47bf91f22b0ec18381023f2b | |
| GPT-5.6 Luna 20-example run status | /vol/openai_fair_more/cfpb-product/gpt-5.6-luna/nearest20/run-status.json | 6e4bd4e1912861caf76e00b5f35bd3e53f88609cb000d13cfce4fdcae2b7cc50 | |
| GPT-6 Luna 20-example run status | /vol/openai_fair_more/cfpb-product/gpt-6-luna/nearest20/run-status.json | 595fa4265dc7141d9ed6296e1898299fc5ff54b54ba497414861842c1b0ce2f1 | |
| GPT-6 Luna 20-example smoke test | /vol/openai_fair_more/smoke/cfpb-product/gpt-6-luna/nearest20/test.preds.jsonl | e3974b186b7aed30dadc0fc69f2da107b717ff32400c1bc3c0d45b2f71539470 |
Label mapping applied before scoring
Scroll the table sideways for every column →
| Label as given | Scored as |
|---|---|
| Credit reporting, credit repair services, or other personal consumer reports | Credit reporting or other personal consumer reports |
| Credit card or prepaid card | Credit card or prepaid card (merged) |
| Credit card | Credit card or prepaid card (merged) |
| Prepaid card | Credit card or prepaid card (merged) |
| Payday loan, title loan, or personal loan | Payday loan, title loan, personal loan, or advance loan |
Why: On 25 Aug 2023 the CFPB renamed three of its products, and the filing date isn't in the complaint text, so a model can only guess which of a product's two names was in use; for routing they are the same product.
Seeds: 0 for each option's interval, 2 for paired differences, 10,000 resamples. illate parity --mapping with the same mapping and label list prints the same paired interval for any pair of these answer files.
What happens to the data
- Sample: the complaints are public domain, from the US Consumer Financial Protection Bureau database. No client data is involved.
- The Luna answers in this sample came from ILLATE's own OpenAI account, which is fine for public data. On a client's data that column comes from a script the client runs with their own key.
In a client engagement
- This report holds counts, scores and category names only; no example text appears in it. The answers file next to it holds item ids, labels as positions in the label list and each option's settings, with the fixed text of the prompts; no example text and no raw model replies (an answer outside the label list is counted, not quoted).
- Your examples and labels test and train your model and nothing else. They are never pooled with other clients' data or used for anything sold to someone else.
- We never ask for your OpenAI, Anthropic or Google keys. API-model columns come from a script you run with your own key, or from answers your system already logged. When our model is unsure it returns defer (on this page: needs_human_review, the same thing), and your own code sends the item to a person or to your provider.
- We train only on labels a person or your records confirmed, never on raw GPT, Claude or Gemini answers: an API model's answers in this report are a comparison, not training data.
- Data in transit uses TLS. Stored data sits in encrypted volumes with access limited to the engineer on your project; for data that can't leave your environment, we work inside your cloud account instead.
- Sub-processors: Modal (GPU training and serving), Hugging Face (downloading open base models; it sees nothing of yours), Google Workspace (email and file transfer) and Anthropic (Claude, the AI coding assistant we run our scripts with: it reads their output, such as counts, scores and column names, and doesn't copy your examples into notes or messages).
- Training data is deleted within 30 days of the engagement ending, or sooner on request, with written confirmation. Weights are handed to you and deleted from our side if you don't host with us.
- We don't hold SOC 2 or ISO 27001. Until a DPA is signed we work only on de-identified data or inside your own cloud account.
The same commitments, and the full sub-processor table, are at illate.dev/security.
What this report doesn't show
- Luna's category-list runs were shown the 14 product names as filed, no examples, reasoning effort none. The pre-registered run of GPT-5.6 Luna with the 20 most similar training complaints is complete and scored on this page. The pre-registered run of GPT-6 Luna with the 20 most similar training complaints was not started: it did not fit the pre-registered spending cap for these runs. ILLATE's runs with one example of every category were stopped part-way on 8 Oct (GPT-5.6 Luna after 484 of 5,117 complaints and GPT-6 Luna after 203 of 5,117 complaints) and not resumed, so they are not scored.
- Every option answered with the 14 product names as filed; the scores merge renamed products into 10 (section 08). We chose that merge after seeing the confusions, so treat it as a diagnosis, not a pre-registered result.
- The fine-tuned model and the four classifiers (three embeddings classifiers and TF-IDF) learned from 17,905 training complaints from the same file. The category-list Luna runs saw none of them; the 20-example runs saw the 20 most similar of them in each prompt.
- The fine-tune's accuracy comes from its saved answers (batched generation on the training GPU). Its latency, throughput and confidence come from serving it with vLLM on one L4: served, it scored 89.1% and agreed with the saved answers on 98.4% of test items after the merge. Expect the served figure in production; section 01 says which verdicts change against it.
- The CPU options were timed one complaint at a time on one Modal CPU core with 4 GiB; serving several cores or batching would be faster, and was not measured.
- There is no current model here: on public data the yardstick is the most accurate option. A client's report compares against the answers their current model gave.
- Intake found 178 texts that appear with more than one label as filed; label noise like that caps the accuracy any model can reach.
- The verdict is on overall accuracy over 5,117 held-out items with a 3-point margin. Per-class recall (section 03) is shown, not gated here; name the categories that matter most and they become a gate.
- Unverified prices: GPT-5.6 Luna (category list); GPT-5.6 Luna (20 similar examples); GPT-6 Luna (category list). Their source is in each cost note in section 02; they have not been checked on the provider's own pricing page. Their costs are scaled to match a real bill; each cost note says by how much and what that bill covers. Re-check them before this goes into a contract.
- First-year costs add each option's one-off cost to twelve months of running cost. That is an assumption about who builds or switches to each option and at what price (section 02's notes), not a quote; your own team's time is not counted.
- No monthly volume was given, so the recommendation is ranked at 500,000 calls a month; the tables in sections 01 and 02 show the answer at 50,000, 500,000, 5 million calls a month. Give yours and it is ranked there.
- Latency is what was measured per request where the run happened (notes under the table in section 02). Add your own network round trip.
- Scored after mapping 14 labels into 10 (section 08). A different mapping gives different numbers; the As filed column in section 02 shows the scores without it. Without it, the same rule picks TF-IDF + classifier, not GPT-5.6 Luna (20 similar examples) (section 01).
- Rare categories have few test items, so their recall is uncertain (section 05).