DocsUnderstand4 min read

Scale: options, size and speed#

This page tells you how big a question can get, how big its table gets, and what to change when it grows. "The table" is shad0w's small learned model; "options" are the answers a question can choose from.

Short answers:

Measured#

Synthetic traffic, so only the option count changes: each option has its own distinctive words, the LLM stand-in is perfectly consistent, and the same certifier runs everywhere. Measured on 12th Gen Intel(R) Core(TM) i7-1255U (12 threads), Linux-7.0.11-76070011-generic-x86_64-with-glibc2.39, 2026-10-08.

options logged answers size budget patterns kept table size training p50 per decision certified share agreement
10 400 none 2,267 0.03 MB 4 s 10.2 µs 90.0% 97.5%
50 2,000 none 8,693 0.46 MB 27 s 7.1 µs 100.0% 98.3%
150 6,000 none 24,026 3.62 MB 5 min 7.2 µs 94.4% 93.6%
150 6,000 1 MB 6,216 1.00 MB 6 min 7.6 µs 94.4% 93.7%
500 15,000 4 MB 8,322 4.97 MB 21 min 10.7 µs 57.3% 80.2%

Synthetic traffic with one consistent teacher; α = 5%. Training time is wall clock on the machine below. The 500-option row: measured before the 0.3.1 size-budget fix (the K x K matrix was not counted), so it overshoots its 4 MB budget. Source: results/b9_scale.json.

What the columns mean:

What it shows:

How the size adds up#

A table file holds:

Part Bytes
header 20
per pattern 4 (key) + 1 per option
per option 8 (scale and bias)
option × option matrix (used for the robustness radius) 4 × options²

The last part matters only for very large questions. At 1,024 options it alone is about 4.2 million bytes, so a max_mb budget must be larger than that. shad0w always keeps at least 1,000 patterns, whatever the budget.

Does the table grow over time?#

No. Each train() builds a new table from the log and replaces the old one. Its size follows the vocabulary of your logged traffic and the number of options, not how long you have been running.

Size grows when:

It levels off once the vocabulary settles, and max_mb caps it either way.

The log does keep growing: one line per LLM answer. Rotate or trim it as you would any log. A few tens of thousands of recent answers per question are plenty to train on.

Recommendations#

Options per question Suggested set-up
up to ~100 defaults; tables are small
~100–400 max_mb between 1 and 4; log several thousand answers before expecting a large certified share
~400–1,024 max_mb between 4 and 16; train on a machine with a few GB of RAM; expect training to take tens of minutes
more than 1,024 split into two questions: coarse first (team), then fine (intent within that team)

A two-level split often certifies more than one huge question. The coarse question has few options and certifies early. Each fine question only has to tell a few dozen intents apart.

import shad0w

team = shad0w.decision("team", options=["billing", "cards", "transfers"], max_mb=1)
cards = shad0w.decision("cards_intent", options=["lost_card", "card_arrival", "pin_blocked"], max_mb=1)
# route with team(text) first, then ask the matching fine question

Memory#

Training holds an options × patterns weight matrix in memory. Above about 10 million weights, shad0w keeps a shorter optimiser history. With a max_mb budget far below the vocabulary, it first keeps only the most frequent patterns, then fits. Both keep memory bounded on a laptop. Serving needs only the table itself.

Many questions#

Each question has its own table and its own certificate. Ten questions of 50 options each are ten small, fast tables, not one large one. Pass one shad0w.Metrics() to all of them to see them on one dashboard (observability).