ref(...), and hunch runs them in dependency order, like models in dbt. Every command takes a folder as well as a single file.
A project fits when a question only makes sense for some rows (“check the fix only where the agent claims one”), or when a hard question is easier as a sequence of smaller ones (“which area?”, then “which intent within that area?”).
Example: a two-step classifier
prototype/examples/banking77_tree/ classifies bank messages into 77 intents in two steps: one of 10 areas first, then an intent within that area, asked only of the rows routed there. The 12 specs are generated by build.py and committed as YAML.
The root reads the file:
group.yml
intent_card_payments.yml
intent_tree.yml
Keys
Without
chain, where is only a filter and confidence is the judgment’s own. In this example chained confidence separated right from wrong answers better than the specialists’ own confidence (AUROC 0.897 against 0.796).
Errors caught before anything runs
- A cycle names the loop:
cycle: a → b → a. - A
ref(...)to a judgment that does not exist. - A column used in
whereorstatethat does not reach the spec (lintfollows columns through the graph). - Union branches whose
whereclauses overlap.
Commands on a project
compile estimates each judgment’s cost without asking anything. A downstream judgment’s row count depends on upstream answers that may not exist yet. If none are cached, it assumes every row passes where and says so:
# total: ~$0.00474 upper bound, ~$0.00385 expected.
--max-cost (or HUNCH_MAX_COST) is checked against each judgment’s estimate before it asks. A judgment that would cost more asks nothing.
--node <judgment> narrows a command: