Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
70 commits
Select commit Hold shift + click to select a range
2226252
feat(eval): flag arms items at the ceiling or floor with no headroom
napetrov Oct 29, 2026
87335ba
fix(eval): compare the unrounded headroom mean to the ceiling
napetrov Oct 29, 2026
0965221
fix(headroom): flag means exactly at a threshold despite float rounding
napetrov Oct 29, 2026
df78ff5
fix(headroom): refuse unknown no-skill arms, count distinct runs
napetrov Oct 29, 2026
050de2e
fix(headroom): reps follow the no-skill arm, unscored arms skip the f…
napetrov Oct 29, 2026
38d219c
docs(eval): document the headroom threshold range checks
antonwolfy Oct 29, 2026
536a3b7
Merge branch 'main' of https://github.com/intel/dokimi into feat/eval…
napetrov Oct 29, 2026
d5113e0
Address review: pin the baseline term of the floor test
napetrov Oct 29, 2026
15695ac
Address review: drive non-default thresholds through the headroom com…
napetrov Oct 29, 2026
4bbc04a
Address review: run the headroom command through the real parser
napetrov Oct 29, 2026
329baac
Address review: pin each summary counter with a mixed item set
napetrov Oct 29, 2026
19b25df
Address review: pin the item order of the headroom result
napetrov Oct 29, 2026
8e5245e
Address review: match the threshold refusals and pin their boundaries
napetrov Oct 29, 2026
544394e
Address review: cover empty and unjudged headroom input
napetrov Oct 29, 2026
fe66ffc
Address review: pin a given no-skill arm on the success path
napetrov Oct 29, 2026
95f84dd
Thread: IC_kwDOVBg7g88AAAABgreQtQ: already fixed in 544394ef
napetrov Oct 29, 2026
e5faa92
fix(headroom): exit 2 on an input nested too deeply to read
napetrov Oct 30, 2026
37cd2c8
fix(headroom): --min-reps refuses 0 with the usage message
napetrov Oct 30, 2026
744e1ca
fix(headroom): keep a non-ASCII digit question id instead of refusing it
napetrov Oct 30, 2026
b3a0b78
fix(headroom): refuse -o naming one of the input runs
napetrov Oct 30, 2026
49a4d54
fix(headroom): count a re-serialized copy of a run once
napetrov Oct 30, 2026
340879b
fix(headroom): summarize the unscored-arm note per arm
napetrov Oct 30, 2026
2c22659
fix(headroom): a floor needs the no-skill arm scored on the item
napetrov Oct 30, 2026
aa8c3ad
fix(headroom): refuse a file where no run scored the no-skill arm
napetrov Oct 30, 2026
f4328af
Merge remote-tracking branch 'intel/main' into pr279-1029
napetrov Oct 30, 2026
3df832a
docs(headroom): a repeat is skipped by JSON content, not by bytes
napetrov Oct 30, 2026
95642eb
docs(headroom): keep the tolerance comment to two lines
napetrov Oct 30, 2026
2563839
docs(headroom): a floor needs the no-skill arm scored
antonwolfy Oct 30, 2026
9a191ba
docs(headroom): list the other exit-2 cases and the score scale
antonwolfy Oct 30, 2026
108ad9f
Merge remote-tracking branch 'intel/main' into pr279-1029
napetrov Oct 30, 2026
7b69f5a
test(cli): allowlist the four eval headroom flags with reasons
napetrov Oct 30, 2026
f259a4f
fix(headroom): the -o guard survives an unresolvable path; floor word…
napetrov Oct 30, 2026
9872a50
docs(cli): regenerate the CLI snapshot for eval headroom
napetrov Oct 30, 2026
df428e3
fix(headroom): refuse a positive ceiling or floor below one score step
napetrov Oct 30, 2026
1e164b8
fix(headroom): guard the .rejected sibling of -o, sort long digit ids…
napetrov Oct 30, 2026
6a1e7f2
docs(headroom): state the threshold ranges the code accepts
napetrov Oct 30, 2026
dfd6946
test(headroom): pin the -o guard against a dotdot spelling of an input
napetrov Oct 30, 2026
5902eda
fix(headroom): refuse a directory as -o with exit 2, not a ValueError
napetrov Oct 30, 2026
438c642
fix(headroom): refuse a directory spelled with a trailing slash as -o
napetrov Oct 30, 2026
ebe6575
fix(headroom): refuse "newdir/." and an unstat-able -o without a crash
napetrov Oct 30, 2026
d56fd0d
fix(headroom): name the -o refusal as "not a file name" and pin the c…
napetrov Oct 30, 2026
8118952
docs(headroom): the provisional rule counts reps across files; name t…
napetrov Oct 30, 2026
6eea8e2
style(test): keep the directory-output test comment to two lines
napetrov Oct 30, 2026
c0fbf44
Merge remote-tracking branch 'intel/main' into tidy279-eval
napetrov Oct 31, 2026
6399536
feat(eval): eval headroom takes the registry's flag names and a route…
napetrov Oct 31, 2026
58891e3
fix(eval): an empty --out is refused, not skipped
napetrov Oct 31, 2026
156c82d
fix(eval): a failed write of --out exits 1, not 2
napetrov Oct 31, 2026
096503d
Merge remote-tracking branch 'intel/main' into tidy279-eval
napetrov Oct 31, 2026
6c29745
chore(cli): regenerate the CLI snapshot after merging main
napetrov Oct 31, 2026
b971c61
fix(runs): list headroom.v1 in the runs kinds table
napetrov Oct 31, 2026
97f0f7a
fix(eval): exit 2 when eval headroom cannot write --out
xaleryb Oct 31, 2026
976f06a
fix(eval): refuse eval headroom inputs of different configurations
xaleryb Oct 31, 2026
aa49e53
fix(eval): refuse an arms input whose run_config is not an object
napetrov Oct 31, 2026
eabdcda
fix(eval): exit 2 when a top-level arms or run_config has the wrong s…
napetrov Oct 31, 2026
6ea6c6b
Merge remote-tracking branch 'intel/main' into tidy279-eval
napetrov Oct 31, 2026
1494b6c
docs(eval): say which top-level shapes the headroom check refuses and…
napetrov Oct 31, 2026
c574718
fix(eval): refuse a judge_context mix and non-string arm names in hea…
napetrov Oct 31, 2026
6699e21
fix(headroom): refuse inputs that give one question id different ques…
napetrov Nov 1, 2026
02d5d91
fix(headroom): refuse pooled runs that differ in scorer, grounding or…
napetrov Nov 1, 2026
d363baf
docs(eval): give the 1e-6 minimum in the headroom threshold ranges
antonwolfy Nov 1, 2026
998f1f5
fix(headroom): refuse legacy and rescored runs that differ, and malfo…
napetrov Nov 1, 2026
7d38dd1
style(headroom): shorten the _fmt comment to the two-line limit
napetrov Nov 1, 2026
61b942d
docs(headroom): say up to nine decimals, as _fmt floors them
napetrov Nov 1, 2026
3c0ff3a
test(headroom): pin that _fmt floors at the ninth decimal
antonwolfy Nov 1, 2026
6258e3a
fix(headroom): a mean 1e-9 from a threshold is not read as at it
napetrov Nov 1, 2026
87f1c50
Merge intel/main into pr279-land1031
napetrov Nov 1, 2026
84e7888
Merge remote-tracking branch 'intel/main' into pr279-land1031
napetrov Nov 2, 2026
649b56b
fix(headroom): compare thresholds exactly; empty arms list counts as …
napetrov Nov 2, 2026
c31a660
test(headroom): split test_headroom.py under the 1000-line test cap
napetrov Nov 2, 2026
973a112
fix(headroom): table floors the displayed score from its exact decimal
napetrov Nov 2, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
### Added

- **`eval headroom` flags arms items with no headroom** — reads one or more `arms.v1` files of the same question set and flags an item as a `ceiling` when the no-skill arm's mean is at least `--ceiling` (default 0.9, on 0-1), or as a `floor` when the no-skill arm was scored, every arm that a run scored has a mean at most `--floor` (default 0), and at least one arm other than the no-skill arm scored. An item with fewer than `--min-reps` runs (default 3) scoring its no-skill arm is `provisional`. The human table goes to stdout; `--out` writes a `headroom.v1` artifact with every item. The flags change no score. Inputs that are not repetitions of one configuration (model, judge, run config other than the seed, harness, arms or library differ) exit 2. Pooling also refuses a file scored by `eval reference` next to a judged one, an arm whose profile prompt digest changed, and a question judged grounded in one file and ungrounded in another.
46 changes: 46 additions & 0 deletions dokimi/docs/evaluating-treatments.md
Original file line number Diff line number Diff line change
Expand Up @@ -724,6 +724,52 @@ Two gates are deliberately statistical rather than absolute:
those questions. It pools questions; a mean of per-cell means differs slightly
when the sets have different sizes — say which one a report uses.

## Headroom: items a comparison cannot learn from

A skill cannot raise an item the no-skill arm already answers, and an item no arm
answers points at the question or its grader, not at the skill. `eval headroom` flags
both, from one or more arms files of the same question set (one file per repetition):

```bash
python cli.py eval headroom run1/arms.json run2/arms.json run3/arms.json \
--baseline-arm baseline --ceiling 0.9 --floor 0 --min-reps 3 --out headroom.json
```

- **ceiling**: the no-skill arm's mean over the runs is at least `--ceiling` (0-1; the
0-100 aggregate divided by 100). Default 0.9.
- **floor**: the no-skill arm was scored, every arm that a run scored has a mean at most
`--floor`, and at least one arm other than the no-skill arm scored. Default 0. An arm no run scored is
left out of this test and listed in the item's `unscored_arms`; the no-skill arm alone at zero
is not a floor.
- **provisional**: fewer than `--min-reps` runs scored the item with its no-skill arm (the
reps are those runs). Default 3. A file gives each item zero or one rep (zero when its
no-skill arm was not scored in that file), so one file alone makes every item provisional at the
default of 3; the reps of several files add up.

A run is one file. A file repeated on the command line, or holding the same JSON content as
an earlier one (whitespace and key order do not count), is skipped with a note, so it does
not add a rep. Numbers are compared as numbers: `95.0` and `95` are the same content. A question id repeated within one
file is an error (exit 2): it would count as two runs.

The table always goes to stdout: the flagged and provisional items, with the no-skill arm
in its own column, a note naming any arm no run scored, and the counts. The JSON goes to
`--out` only, as a `headroom.v1` artifact with every item; if that file cannot be written the
command prints `Error: cannot write ...` on stderr and exits 2, after the table. Scores are compared unrounded
and shown rounded down to up to nine decimal places, so 0.89996 prints as 0.89996 and a value just under a threshold never
prints as the threshold. Without `--baseline-arm`, the runs must
declare the same baseline; the default is that baseline. The runs must also be repetitions of one
configuration: a file whose model, judge, run config (the seed aside), harness, arms or library
differs from the first file's exits 2. So does a file scored by `eval reference` next to a judged one, an arm whose
recorded profile prompt digest differs between files (an edited profile keeps its name), and a question
id judged grounded in one file and ungrounded in another (a file with no `grounded_questions` count is not
compared). With `--baseline-arm`, the arm must
be one the runs list (exit 2 otherwise, naming the arms that exist), and the declared
baselines are not checked. A threshold out of range exits 2: `--ceiling` in [1e-6, 1],
`--floor` 0 or in [1e-6, ceiling), `--min-reps` at least 1. A positive threshold may be finer than one score step. It also exits 2 when no run scored the
no-skill arm, or when `--out` is one of the input files (or its `.rejected` sibling), or names a directory or a path ending in a separator. Scores are read as the 0-100
aggregate divided by 100 and are not range-checked. Only arms runs are read. The flags are descriptive: they do not
change any score or any gate.
Comment thread
antonwolfy marked this conversation as resolved.
Resolved

## Scope and caveats

- **Three levels of fidelity for skills/MCP.** (1) `skill:` / `mcp:` inject
Expand Down
121 changes: 121 additions & 0 deletions dokimi/docs/reference/cli-interface.json
Original file line number Diff line number Diff line change
Expand Up @@ -4489,6 +4489,126 @@
"subcommand_required": null,
"subcommands": {}
},
"headroom": {
"allow_abbrev": true,
"params": [
{
"action": "_StoreAction",
"choices": null,
"const": null,
"default": null,
"group_key": null,
"group_required": null,
"hidden": false,
"is_flag": false,
"key": "arms",
"kind": "argument",
"nargs": "+",
"position": 0,
"required": true,
"type": null
},
{
"action": "_StoreAction",
"choices": null,
"const": null,
"default": null,
"group_key": null,
"group_required": null,
"hidden": false,
"is_flag": false,
"key": "--baseline-arm",
"kind": "option",
"nargs": null,
"position": null,
"required": false,
"type": null
},
{
"action": "_StoreAction",
"choices": null,
"const": null,
"default": 0.9,
"group_key": null,
"group_required": null,
"hidden": false,
"is_flag": false,
"key": "--ceiling",
"kind": "option",
"nargs": null,
"position": null,
"required": false,
"type": "float"
},
{
"action": "_StoreAction",
"choices": null,
"const": null,
"default": 0.0,
"group_key": null,
"group_required": null,
"hidden": false,
"is_flag": false,
"key": "--floor",
"kind": "option",
"nargs": null,
"position": null,
"required": false,
"type": "float"
},
{
"action": "_HelpAction",
"choices": null,
"const": null,
"default": "==SUPPRESS==",
"group_key": null,
"group_required": null,
"hidden": false,
"is_flag": true,
"key": "--help/-h",
"kind": "option",
"nargs": 0,
"position": null,
"required": false,
"type": null
},
{
"action": "_StoreAction",
"choices": null,
"const": null,
"default": 3,
"group_key": null,
"group_required": null,
"hidden": false,
"is_flag": false,
"key": "--min-reps",
"kind": "option",
"nargs": null,
"position": null,
"required": false,
"type": "dokimi.cli.build_parser.<locals>.positive_int#faf57db5ff9f"
},
{
"action": "_StoreAction",
"choices": null,
"const": null,
"default": null,
"group_key": null,
"group_required": null,
"hidden": false,
"is_flag": false,
"key": "--out",
"kind": "option",
"nargs": null,
"position": null,
"required": false,
"type": null
}
],
"path": "dokimi eval headroom",
"subcommand_required": null,
"subcommands": {}
},
"judge-validity": {
"allow_abbrev": true,
"params": [
Expand Down Expand Up @@ -13148,6 +13268,7 @@
"'eval_coverage'",
"'explore_runs'",
"'guidance_reach'",
"'headroom'",
"'matrix_rollup'",
"'need_graph'",
"'novelty'",
Expand Down
1 change: 1 addition & 0 deletions dokimi/dokimi/artifacts.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@
"repo_budget": "repo_budget.v1",
"effective_instructions": "effective_instructions.v1",
"task_inspect": "task_inspect.v1",
"headroom": "headroom.v1",
"redteam": "redteam.v1",
"cli_routes": "cli_routes.v1",
"need_graph": "need_graph.v1",
Expand Down
1 change: 1 addition & 0 deletions dokimi/dokimi/cli_routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ class Tombstone:
Leaf(("eval", "pairwise"), PAID),
Leaf(("eval", "reference"), PAID),
Leaf(("eval", "native-import"), FREE),
Leaf(("eval", "headroom"), FREE),
Leaf(("eval", "redteam"), PAID),
Leaf(("eval", "panel-score"), PAID),
Leaf(("dataset", "export"), FREE),
Expand Down
4 changes: 4 additions & 0 deletions dokimi/dokimi/commands/evaluate.py
Original file line number Diff line number Diff line change
Expand Up @@ -580,6 +580,10 @@ def register(sub, positive_int) -> None:

answer_formats.register_eval(eval_sub, positive_int) # eval reference, eval native-import

from dokimi.commands import headroom

headroom.register_eval(eval_sub, positive_int) # eval headroom

from dokimi.commands import redteam

redteam.register_eval(eval_sub) # eval redteam
Expand Down
Loading
Loading