judge() callers can use it at the same time.
Where it lives
In order:HUNCH_STORE, if set.- The nearest
.hunch/store.sqlitein the spec’s folder or any folder above it. - Otherwise a new
.hunch/store.sqliteat the root of the git repository, or in the spec’s folder outside a repository.
HUNCH_STORE to the existing store.
Keep .hunch/ out of git: about 80 MB per 100,000 rows, and it holds your rows’ text.
The answer cache
answers is content-addressed: each answer is keyed by a hash of exactly what was asked.
- Same row, question and model anywhere (batch,
judge(), server): cache hit. - New key: a change to
instructions,criteria, option order, model, or any state column’s text. - Not in the key:
act,gold,escalate,tests,where, the spec’s name andsource.
noul is p(yes).
Judgment tables
hunch run writes one table per judgment, named after it, replaced in one transaction; a failed run leaves the previous table. Columns: the answer columns, plus:
Under
--model, the table name gets the engine as a suffix (intent__deepseek_deepseek_flash), leaving the spec’s own table untouched.
Runs and lineage
spec_hashcovers what the judgment asks, noton_changeorsource;on_change: freezecompares it with the last complete run’s.statusiscomplete, orfailed: <error>.shash: hash of the row’s state.new_rows_onlyreuses an answer only when row id andshashboth match./v1/driftand the runs page read label mixes from_hunch_row_answers.
Traffic
judge(..., log=True) and judge(..., shadow=...) keep each row in traffic (judgment, rhash, row, n, first_at, last_at), redacted by the live spec’s rules; a repeat increments n. --traffic exports it to .hunch/traffic/<judgment>.csv and runs on that.
Querying it
Plain SQLite. Which engine answered each row of the triage example, and when:hunch.results returns a judgment’s table as a list of dicts.