Skip to content

feat(tools): durable per-request results and strict stdout classification in the eval harness - #1355

Merged
JustVugg merged 18 commits into
JustVugg:devfrom
monotophic:evidence/python-tooling
Sep 21, 2026
Merged

JustVugg merged 18 commits into
JustVugg:devfrom
monotophic:evidence/python-tooling

Conversation

@monotophic

@monotophic monotophic commented Sep 5, 2026 •

Copy link
Copy Markdown
Contributor

Authored by Opus 5 in Claude Code, analysis in partnership with @monotophic

Revised 2026-09-17 in response to review. This PR is now the durability half only. The
ablation-evidence checker and its release-archive gate have moved to #1356, where their writer lives, and the
SCORE_EVIDENCE identity binding is removed. Title updated to match: the previous one advertised two things that
are no longer here.

The evaluation harness reads scoring output off the engine's stdout, and today it trusts whatever it is handed: a
line it does not recognise is silently absorbed, and results are written only when the whole run finishes, so a
run that dies mid-task leaves nothing behind.

This changes both.

tools/eval_glm.py gains two properties it did not have. Results are appended per request, so a run that dies
mid-task leaves a valid partial file with an INCOMPLETE marker and still prints the accuracy table over the rows
that landed. And every line of the scoring stream is classified against the engine's documented SCORE-mode
output, so an unrecognised line is refused by name instead of silently absorbed.

tools/engine_evidence.py owns the grammar of the engine's two typed startup lines β€” the == GLM C engine banner
and the loaded in … record β€” so every consumer agrees by construction instead of each re-deriving the same
regular expressions and the same normalisation. It is the shared foundation the other two PRs in this group also
carry; see the note at the end.

Context. This PR is one of five independent contributions derived from a single locally-verified working tree
(the fp8 container line in #1102, the OpenAI-compatible server hardening in #1353, this harness work, the engine's
ablation scoring mode in #1356, and an engine-transcript check tool in #1357). This one carries the evaluation
harness and the shared preamble grammar. It stands alone β€” its whole suite is green with the rest of the set
absent (97 cases on a checkout of dev carrying only these five files), and merging or declining the others does
not affect it. The others are proposed separately, each with its own evidence. The set-level explanation and a traceability matrix covering every request across the three PRs are in the #1355 comment: .

Behavioral contract

  • Everything the harness did before, it still does on its own inputs: task loading, per-option scoring,
    exact-vs-greedy accounting, and the output format existing consumers read are unchanged, including --dry
    without a vocabulary and the accuracy table on a partial run.
  • A run interrupted at any point leaves every already-scored row on disk, complete and parseable, with no
    truncated trailing record.
  • A line the engine never prints on the scoring stream is refused by name; it is never absorbed.
  • The preamble grammar accepts exactly what the engine really prints, including every kernel name it can emit, and
    rejects what it does not.
  • No test here runs a model, and none needs a GPU or a container.

Capstone matrix β€” one decisive artifact per claim; each would fail if the claim were false.

claim decisive evidence
the durability guard actually guards durability delete the per-row out_f.flush() at tools/eval_glm.py:601 and tests/test_eval_glm.py::test_row_is_durable_on_disk_before_the_run_finishes fails. The older test named for the same property β€” test_result_rows_are_written_and_flushed_incrementally β€” stays green under that mutation, which is why the new one exists
the guard is aimed at the right line the same deletion applied to the CSV header flush at :547 does not fail the test. It pins the per-row property, not the presence of a flush() call
the property holds against a REAL engine under a hard kill an integration run on a Linux host: eval_glm.py driven against a real container, polled until three complete rows were on disk, then SIGKILLed β€” not a graceful stop, so the interpreter's flush-on-close never ran. A second, independent file handle opened afterwards found 3 complete rows, 9 fields each, no truncated trailing line. The control is what is missing: the file carries no # finished record, which the harness writes last β€” proof the process really was killed mid-run rather than allowed to finish
rows land on disk while the run is still in progress the harness's own main() driven end to end with rows observed on disk 1β†’2β†’3β†’4 mid-run, read through a second independent file handle. Stated exactly: the engine is a fake subprocess.Popen returning canned stdout, as this suite's own docstring says β€” no engine is launched here. The property under test is the harness's write-and-flush behaviour, which is where the defect was; proving it against a live engine is an integration cell, not a unit test
foreign lines are refused, not absorbed a direct differential pinned by two tests in this branch: test_dev_copy_silently_accepts_a_foreign_numeric_line proves dev's classifier accepts the line 1 1 1, shaped like its own grammar; test_new_copy_refuses_the_same_foreign_line_by_name proves this branch raises on the identical input. Both run against the two implementations, not against a description of them
the preamble grammar is pinned to real output, not to itself every entry of the kernel roster is asserted against a frozen literal independent of the parser's own table — a same-length rename (neon→neom) fails the suite. An earlier fix that derived the expectation from the roster it policed passed that mutation, which is the reason for the literal
the harness still behaves like dev's where it should RAN at this head, against dev's own copy of eval_glm.py extracted from origin/dev: the CLI surface is option-for-option identical, and --selftest produces byte-identical output from both, each exiting 0. Scope stated plainly β€” this covers the accuracy-table and scoring-reduction path; it does not cover --dry against a real snapshot, which needs a container and is not run here
Fuller matrix, what changed since the reviewed head, and origin accounting

What changed since 5e9b1131, the head reviewed on 2026-09-17

change origin
the stale pack_python.py import-closure paragraph is gone from this body maintainer-requested β€” and dev-motion: #1364 fixed it on dev, so this branch's diff for that file is empty
SCORE_EVIDENCE identity binding removed (6 references β†’ 0), and the UNBOUND status with it (4 β†’ 0) maintainer-requested β€” nothing on dev reads that variable, so the reader shipped ahead of its writer
tools/check_ablate_evidence.py, its test, and the release.yml gate moved to #1356 maintainer-requested, resolved differently β€” its writer is #1356's coli-ablate/2 mode, so it moved rather than being parked
the durability guard above re-review-found β€” the feature worked; the test named for it could not detect losing it
the kernel-roster literal re-review-found β€” the roster was unvalidated data, and the first fix for it was itself insensitive to content
requirement instrument result
helper grammar is source-true the banner and loaded in regular expressions read against the engine's own format strings and the kernel names it can print match, including the draft upper bound the engine clamps to
incremental durability kill the harness mid-run and read the file through a second handle valid partial file, INCOMPLETE marker, table printed, no truncated trailing record
foreign-line refusal lines the engine never prints on the scoring stream, driven through the classifier main() actually uses each refused by name; the dev/new differential above is the decisive pair
numeric grammar both the six-decimal form the engine ships today and the older %.17g form, plus nan/inf/-inf both accepted; fixtures are non-dyadic
suite runs with nothing else from the set present python3 -m unittest tests.test_engine_evidence tests.test_eval_glm tests.test_pack_python on dev + these five files Ran 97 tests in 0.311s … OK

The shared file, disclosed. tools/engine_evidence.py and tests/test_engine_evidence.py β€” 524 lines, two
files β€” are byte-identical in this PR and #1357. #1356 no longer carries them: its revision left it importing
nothing from the module, so it was dropped there rather than shipped unused. That duplication is present by design until this PR lands;
the other two then merge dev and shed their copies mechanically. Merging this PR first gives the smallest
review surface for the other two, but any order merges cleanly
β€” all six orderings were built in a scratch
worktree and produce one identical tree with zero conflicts.

A limitation we are disclosing rather than fixing here. The wire-format literals in this tooling are hand
transcriptions of formats printed by c/colibri.c. Drift in the Python module is pinned by the tests above;
drift in the C source is not β€” no test in this branch reads a C file. That predates this revision and a fix
would reopen the shared file across all three PRs, so it is noted as a follow-up rather than folded in.

Scope note: no file outside the five listed is touched, and no surrounding code was reformatted.

Durable vs current state: the harness properties, the preamble grammar and the refusal contract are durable.
The counts (97 cases) are current state, measured 2026-09-17 against base cc756a63 on macOS (Apple silicon).

monotophic and others added 4 commits September 5, 2026 14:13
The evidence tooling reads the engine's own stdout. Two of its lines are
typed records -- the "== GLM C engine" banner and the "loaded in ..."
line that follows it -- and every consumer that wants a field out of
them was about to reimplement the same grammar. This adds one module
that owns the exact text, the field ranges each number may take, and
the errors a malformed line produces, so the consumers agree by
construction.

It also owns the canonical form of an ablation manifest: the engine reads
a manifest a line at a time, drops the terminator and one carriage return
before it, and digests the record followed by a single newline.
canonical_manifest_bytes() is that rule written once for the Python side,
so a checker and the engine cannot drift into hashing different bytes.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
check_ablate_evidence.py re-checks one ablation manifest and its JSONL
evidence artifact against an independently supplied config.json, without
the engine and without any test binary: the config and manifest field
bounds, every record's key set and field types, the header's binding to
the config and to the manifest digest, and the truncation, replay and
mismatch cases at each record boundary.

Three cross-record invariants are enforced because the producer
guarantees them for every row it can emit -- nll is never negative, corr
agrees with the argmax-equals-gold comparison, and the argmax logit is
never below the target's. Top-k order is deliberately not enforced: it is
unsorted on the wire by design.

The manifest is reduced through the shared canonical form before it is
parsed or hashed, so a manifest saved with CRLF endings or without a
final newline -- both of which the engine accepts and normalises -- is
checked rather than refused, and binds the same digest the engine bound.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
eval_glm.py scored answers from whatever the engine printed and wrote its
results only after the whole run finished. Two consequences: a foreign
line on that stream was absorbed silently, and an interrupted run left
nothing to read.

Result rows are now appended per request, so a run that dies mid-task
leaves a valid partial file carrying an INCOMPLETE marker and still
prints the accuracy table over the rows that landed. Every line of the
scoring stream is classified against the engine's documented SCORE-mode
output and an unrecognised line is refused by name instead of ignored,
and the numeric grammar accepts both the six-decimal form the engine
ships today and the older %.17g form. Where the engine build cannot
supply the evidence record the harness would bind to, the run is marked
UNBOUND by name rather than reported as bound.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
pack_python.py reaches a file two ways: by following imports out from
coli, and by spotting scripts that are launched as subprocesses. Only the
first kind had its own imports followed, so a module that only a
subprocess-launched script imports was left out of the release archive
while --check still reported the archive complete.

On dev this happens twice: tools/iq3_pack.py, which
tools/convert_fp8_to_int4.py imports inside quant_e8(), and
tools/engine_evidence.py, which this branch's eval_glm.py imports. Both
are now reached. The test suite grows a real-tree assertion as well as
fixture cases, because every existing case builds a disposable tree and
so could not have caught either omission.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
On Windows, os.kill(pid, SIGTERM) is TerminateProcess with the exit code
set to the signal number: no Python handler runs and the whole unittest
process dies with status 15, which is how the Windows UCRT64 job reported
`make: *** [test-python] Error 15` with no test summary. The behaviour the
test asserts (a real SIGTERM converted into engine-child cleanup) is a
POSIX mechanism; the SIGINT/exception half of the pair covers child
cleanup on every platform.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
… its newline

The checker prints its PASS line with print(), so a Windows child hands the
test CRLF where POSIX hands LF, and the byte-exact assertion failed on the
Windows UCRT64 job (the only failure in a 914-test run). Nothing consumes
that line byte-for-byte; the pin is on the content, so the test now folds
CRLF to LF before comparing.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Resolves the conflict JustVugg#1364 created, so this branch does not need a rebase.

JustVugg#1364 landed the packer commit from this PR (cherry-picked, authorship
intact) plus a second edge it left open: a data file opened next to a
reached module. tools/pack_python.py therefore takes dev's version
wholesale, which is a strict superset of this branch's -- the only lines
unique here were the ones that commit replaced.

tests/test_pack_python.py takes dev's version and keeps this branch's
engine_evidence assertion as an ADDITIONAL real-tree case rather than a
replacement. On dev that assertion could not run, because
engine_evidence.py is introduced here; on this branch it pins the edge
this branch adds, next to the one that pins the historical bug.

12 tests, all green.
@JustVugg

JustVugg commented Sep 6, 2026

Copy link
Copy Markdown
Owner

Conflict resolved on your branch, pushed as 9e96637. No rebase needed on your side -- pull before your next commit.

What I did, so you can check rather than trust it:

  • tools/pack_python.py takes dev's version wholesale. It is a strict superset of this branch's: I diffed them, and the only lines unique here were the three your own commit replaced (the old two-edge docstring, the scripts, script_paths init, the old summary print). Nothing of yours was dropped.
  • tests/test_pack_python.py takes dev's version and keeps your engine_evidence assertion as an additional case, not a replacement. On dev it could not run, since engine_evidence.py is introduced here. On this branch it pins the edge this branch adds, sitting next to the one that pins the historical bug. Both are real-tree assertions and they defend different things.

12 tests, green locally. CI is running.

One thing I noticed while verifying, worth a decision from you

tools/check_ablate_evidence.py is not in the computed set:

engine_evidence.py           True
eval_glm.py                  True
check_ablate_evidence.py     False

Not a defect in your change: nothing in the code names it, and it takes argparse arguments, so its caller is a person. Static analysis cannot reach a human. tools/k3_tokenizer.py is in exactly the same position and release.yml copies it explicitly for that reason.

So it is a decision, not a bug: if the checker is meant to be usable from a release archive, it wants the same explicit copy plus a test -f gate. If it is a repository-side tool for people working on the engine, it is already right as it is. You know which one you intended.

Thanks again for #1359. Cherry-picking your commit rather than rewriting it was the least I could do after duplicating another contributor's work last week by not checking the PR list first.

…erifies

pack_python.py computes the archive from what coli reaches, so a tool whose
only caller is a person typing argparse arguments never makes it in.
k3_tokenizer.py has always been in that position and release.yml copies it by
hand; check_ablate_evidence.py joined it with this branch. It verifies the
ABLATE evidence that the packaged eval_glm.py produces, so an archive that
ships the producer without the verifier is half a tool.

Copy it explicitly, gate on it with the same test -f the tokenizer helper
gets, and parse-check the packaged file. A real-tree test pins both halves
of the decision: the walk does not reach either human-only tool (if it ever
does, the explicit copy is redundant and the pin says so), and the workflow
both copies and gates each one. A copy without a gate is how v1.10.0 shipped
green with four broken commands (JustVugg#1296).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@monotophic

Copy link
Copy Markdown
Contributor Author

@JustVugg: Thanks for patching the bugs, resolving the conflict on this branch, and the write-up. I checked the merge: pack_python.py at 9e96637 is dev's file with nothing of ours dropped, and test_pack_python.py keeps the engine_evidence case as an added assertion. I have pulled 9e96637 and have not rewritten the branch.

On check_ablate_evidence.py: it should ship in the release archive. It verifies the evidence that eval_glm.py produces, and that harness is in the archive, so anyone running a released engine and producing ablation evidence wants the checker beside it. Added in ba2802a: the same copy and test -f gate that release.yml gives k3_tokenizer.py, plus a parse check, and a real-tree test that pins both halves (the walk does not reach either human-only tool; the workflow copies and gates each).

#1356
and
#1357
stack on this branch; I merged 9e96637 into each the same way rather than rebasing, so their histories stay put.

[Authored by Claude Fable 5.1 in Claude Code, analysis in partnership with @monotophic.]

@monotophic

Copy link
Copy Markdown
Contributor Author

Authored by Claude Fable 5.1 in Claude Code, analysis in partnership with @monotophic

Merged current dev (87c54a93) into this branch β€” no functional change on this PR's side. The only file dev motion touched here is .github/workflows/release.yml, where this PR's three hunks (copying, gating and parse-checking check_ablate_evidence.py in the release archive) sit beside two unrelated dev commits (d46b7154 SHA-pinning of third-party actions; 882c102f deepseek_v41 in the build matrix). All merged automatically. The other seven files are unchanged from what was already under review. This PR's test modules (177 tests) pass on the merged head; make check passes on #1356, which contains this branch.

@JustVugg similar steering request to #1102 and #1353, this PR is part of the set to make the full checkpoint-quality GLM 5.2/5.3 containers work and to establish the OpenAI API instrumentation needed for container quality studies. Let me know if this PR is off target or otherwise not likely to merge. Thanks for all you do, this project is awesome :)

@JustVugg

Copy link
Copy Markdown
Owner

Reviewed. The durability half is worth having on its own: appending results per request so an interrupted run leaves something behind, and classifying every stdout line instead of absorbing the unrecognised ones, are both real.

Two things in the body no longer match the diff, and I would rather not merge a PR whose description misdescribes it.

The pack_python.py import-closure gap you describe as a pre-existing defect on dev, with a promise to open a separate issue, is already fixed on dev, merged as #1364. Your diff for that file is empty. What survives is the test additions plus the release.yml gate.

And the evidence half is inert as it stands. c/tools/eval_glm.py sets SCORE_EVIDENCE=1 in the child environment, and I checked the dev tree: nothing reads it, zero files, against a positive control that finds coli_omp_tune in eleven. Your own docstring says so. So the harness reports UNBOUND on every build that exists.

My suggestion is to split: merge the durability fix now, with the body corrected, and bring the binding back when an engine actually writes that record. Carrying a reader ahead of its writer is the same pattern you flagged and offered to drop yourself in #1353.

@JustVugg

Copy link
Copy Markdown
Owner

One more thing that applies to the set rather than to this PR, and it is the single change that would most help review.

#1356 and #1357 each contain this PR's engine_evidence.py and check_ablate_evidence.py byte for byte, same blob hashes, along with four identical commits. So the four PRs are not 22,000 lines, they are about 15,300 with 6,700 counted three times.

That also makes two statements stale. #1356 says one round-trip case fails until this PR lands, and #1357 says both modules fail to import without it. Neither is true of the diffs as pushed: each already carries both files.

Could you rebase #1356 and #1357 onto this branch's head, so each diff shows only its own work? It cuts the review surface by nearly a third and makes the bodies true again.

monotophic and others added 8 commits September 17, 2026 15:17
No engine build on dev writes the identity-bound wire form
("SCORE <ordinal> <sha256> <exact> <contlen> <greedy>"); SCORE_EVIDENCE
is read by nothing (0 files vs. 13 for the coli_omp_tune positive
control). Remove the dead binding machinery -- _SCORE_EVIDENCE_RE,
parse_score_evidence_result, ScoreStdoutClassifier's request_digests/
binding_mode/mode tracking, the SCORE_EVIDENCE=1 env set, and the
BOUND/UNBOUND reporting -- and the docstring paragraphs describing it.
The per-request durability append and the full stdout line
classification (banner/load preamble lifecycle, foreign-line refusal)
are unchanged.

Bring the binding back when an engine actually writes that record.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Split reused verbatim from upstream/p0-engine-preamble (b6070718),
verified there by 18,093 old-vs-new behavioural comparisons with zero
divergences. Keeps PreambleError, parse_engine_banner,
parse_engine_loaded, parse_engine_preamble and their module constants.
Removes ManifestFormError and canonical_manifest_bytes, which travel to
JustVugg#1356 with their only consumer (check_ablate_evidence.py, removed from
this PR next). The module docstring no longer describes the absent
half.

This transiently breaks check_ablate_evidence.py's import of the
removed names; the next commit removes that module from this PR.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
check_ablate_evidence.py, its test module, and the three release.yml
hunks that copy and gate it (the cp into dist/tools, the test -f
presence gate, the ast.parse packaged-file check) move to JustVugg#1356, which
owns their writer (canonical_manifest_bytes/ManifestFormError, removed
from engine_evidence.py the previous commit).

test_eval_glm.py's shared byte-limit test drops its ABLATE-side
assertions (module gone) and keeps the EVAL-side ones unchanged;
test_pack_python.py's HumanOnlyToolsShipExplicitly class is removed
verbatim rather than edited, since check_ablate_evidence.py was one of
its two pinned entries -- it is carried to
colibri_lab/dispatch/2026-09-17-program-d-r2/CARRIED_TO_P2_test_pack_python_class.txt
for JustVugg#1356 to restore alongside its own copy of the checker.
test_engine_evidence_is_needed_by_the_real_tree, this branch's own
addition to that file, is untouched.

This is a forward commit that deletes -- intended, not a mistake.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
F3: engine_evidence's parse_engine_banner/parse_engine_loaded/
parse_engine_preamble raise a bare ValueError, not their own
PreambleError, once a numeric preamble field exceeds Python's
4300-digit int-string conversion limit. This module's own contract is
to refuse every non-canonical record with a named error; its three
call sites into that shared module now catch ValueError alongside
PreambleError so the bare exception cannot escape uncaught through
classify_score_stdout, ScoreStdoutClassifier.classify, or
is_score_preamble. engine_evidence.py itself is unchanged (shared
verbatim with other in-flight branches); a coordinated fix there is
outside this PR's authority.

Added direct test_eval_glm.py coverage: the oversized-field contract
fix (proof-of-bite against the pre-fix code, included in the worker
report); a documentation pin for the "loaded index ..." literal-prefix
collision in parse_engine_preamble's dispatch (no engine anywhere in
this tree emits such a line); parse_engine_loaded's isfinite guard on
load_s/resident_mb, which has no round-trip backstop the way
parse_c17g does; and direct parse_c17g invocation (previously only
exercised indirectly), which this branch's own investigation found to
be equivalence-redundant with parse_c17g's round-trip format check for
the fullmatch/decimal-digit/exponent-width regex components tried
-- documented as such rather than claimed as bite it does not have.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
engine_evidence.py is shared verbatim across branches, not immutable --
a root fix here costs nothing while the sibling branches are unbuilt.

F3 (root fix): parse_engine_banner/parse_engine_loaded now catch
ValueError from their own int()/float() conversions and re-raise as
PreambleError, so a numeric field beyond Python's 4300-digit
int-string conversion limit refuses with this module's own named
error instead of escaping as a bare ValueError from all three entry
points. eval_glm.py's downstream catches of (PreambleError, ValueError)
stay as defense in depth.

F2: corrected premise -- check_data_logprob_gaps.py in this tree has
no engine_evidence coupling, but JustVugg#1357's own (much larger) copy does,
and its _global_header treats any problem entry, including a spurious
malformed-preamble complaint, as a whole-transcript hard failure.
Confirmed at primary source (grep across every "loaded"-prefixed
printf in the C sources) that no engine anywhere emits "loaded index"
or anything else that collides with the "loaded in" prefix test today,
so per that finding, the fix is prose: parse_engine_preamble's
docstring now states plainly that "starts like one of them" is a
literal prefix test, not a semantic one, and names the collision.

test_engine_evidence.py (also shared, also not frozen) gains:
- IdotKernelRosterTest: every IDOT_KERNELS entry parsed from the real
  banner format, sourced from c/quant.h:582-594 with file:line
  citations ("neon" confirmed RAN via this host's own default-build
  compiler flags), plus a roster-size backstop -- closes the roster
  gap the previous round wrongly reported as already closed (that
  claim rested on eval_glm.py's own test, not on this module's own
  45-test suite, which a scratch reduction to ("avx2",) alone left
  fully green).
- test_trailing_newline_rejected on both parse_engine_banner and
  parse_engine_loaded: fullmatch requires consuming a trailing "\n";
  $ alone does not, so match()/search() would accept a newline-
  terminated banner/load record that fullmatch correctly refuses --
  the shape a real `for line in f:` caller actually hands over.
- test_oversized_field_raises_preamble_error_not_bare_value_error on
  both functions, pinning the F3 root fix directly.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
test_every_roster_entry_parses_from_real_banner_text iterates
IDOT_KERNELS and asserts each entry parses to itself -- but _BANNER_RE
is itself built from IDOT_KERNELS, so a same-length rename of any
entry produces a banner the correspondingly-mutated regex still
matches: the assertion compared the mutation against itself. RAN
(reported and independently reproduced): renaming "neon" to "neom"
left all 51 prior tests green.

Adds test_roster_matches_frozen_expectation: a literal transcribed
from c/quant.h:582-594's #if/#elif ladder, independent of IDOT_KERNELS
and of _BANNER_RE, asserted with assertEqual against the roster
directly. The per-entry parse loop and the length/uniqueness backstop
are kept -- each still defends something real (kernel-dispatch/roster
sync, and an accidental shrink) -- with the vacuous-gate limitation of
the parse loop now stated explicitly in the class docstring.

Checked every other test in this module for the same self-referential
pattern (expectation derived from the artifact under test rather than
an independent literal): none found. test_dispatches_to_banner/loaded
compare parse_engine_preamble's output to parse_engine_banner/loaded's
own output on the same input, which looks similar but is a legitimate
differential check of dispatch routing specifically (a mutant that
misroutes is caught; a mutant shared by both delegate functions is
already independently covered by each function's own hardcoded-literal
tests elsewhere in this file). Every other test asserts against a
hardcoded literal (a dict, a number, a raised exception type).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
reachability, stale docstring, duplicated tree walk, vocab contract

1. The per-row out_f.flush() (c/tools/eval_glm.py) had no test that
could detect losing it: test_result_rows_are_written_and_flushed_
incrementally reads the output file only after main() has unwound
through its `finally` (which closes, hence flushes, out_f regardless
of any per-row flush), so it defends the artifact after a clean-ish
exit, not durability during the run. Added
test_row_is_durable_on_disk_before_the_run_finishes: a probing fake
stdout iterator opens a SECOND, independent file handle mid-run (main()
has not returned) and asserts the previous row is already readable
through it. RAN, proof-of-bite: removing the per-row flush fails this
test with the durability assertion; restoring it passes clean.

2. F2 correction: the prior round's report called this "root-fixed",
overstating it. Re-verified at primary source (no engine anywhere
emits "loaded index" or anything colliding with either preamble
prefix) -- there is nothing to tolerate, so prose was always the
correct and complete fix, not a a compromise standing in for a code
change. Tightened parse_engine_preamble's docstring to state plainly,
up front, what is accepted and that everything else is refused, before
explaining the prefix-collision characteristic.

3. Exhaustively re-tested every fullmatch call site in eval_glm.py
against both .match() and .search() weakenings, full suite each time.
Four mutants genuinely survive (leave the suite green): parse_c17g's
and parse_score_result's fullmatch, each x2. parse_c17g's is
UNREACHABLE via the classifier by construction (its only caller passes
a substring _SCORE_RE already captured via that exact sub-pattern) and
equivalent-in-practice for direct callers (round-trip format check);
documented at the call site. parse_score_result's IS on the
classifier's live path, but the one distinguishing input (a
newline-terminated record -- $ matches before a trailing "\n" the same
way engine_evidence.py's M11-M13 did) is provably unreachable through
classify_score_stdout/ScoreStdoutClassifier.classify, which both strip
exactly one trailing newline and refuse any other first. Direct
callers are not protected by that guarantee, so closed with
test_direct_call_rejects_trailing_newline_record. A third site
(score_request_wire) does not survive -- already caught by an existing
bad-request case -- left alone.

4. completion_error's docstring cited identity-binding/digest/OOV
conditions this PR already deleted. Enumerated what can actually reach
stream_error today (foreign/malformed/duplicated preamble, a
non-finite or malformed SCORE token, a contlen mismatch, extra SCORE
lines, an incomplete preamble at EOF) and decided fatal-for-the-whole-
run remains proportionate for all of them: unlike the DATA/logprobs
serving channel, this SCORE/benchmark channel has no legitimate
non-finite case, and once one record fails to parse nothing guarantees
earlier-looking-fine rows were not already touched by the same
corruption. Docstring corrected to the live conditions; behavior
unchanged.

5. Deduplicated the two PackPythonNeededTests methods that each
independently called the expensive PACK.needed(HERE.parent) real-tree
walk (~0.3s each) via a shared setUpClass computation. Halves this
module's wall time (0.6s -> 0.3s, RAN).

6. score_snapshot_vocab's except clause caught json.JSONDecodeError
but not its own ValueError parent -- json.loads() raises a bare
ValueError (not JSONDecodeError) for a vocab_size literal beyond
Python's 4300-digit int-string conversion limit, escaping main()'s
only try/except (which catches EvidenceError to write the INCOMPLETE
marker and return before ever launching the engine) and crashing
outright with no marker written. Same error-contract class as F3;
fixed the same way. RAN, proof-of-bite at both the unit level
(score_snapshot_vocab itself) and end-to-end through main() (asserts
rc=1 and an INCOMPLETE marker, not a crash).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@monotophic

monotophic commented Sep 18, 2026 •

Copy link
Copy Markdown
Contributor Author

Thank you β€” this was clear and constructive feedback. The only two places where we found different numbers, you had been charitable. We did a deep review on the set of three (1355, 1356, and 1357) and also integration testing with 1102 and 1353 on current dev (as of this posting). I think that what we've done is as good or better than your asks, but if you differ on our "improvements" we can deliver your asks directly.

Two things first: the two places we didn't do what you asked to the letter.

No rebase, but with reason

You asked us to rebase #1356 and #1357 onto this branch's head so each diff shows only its own work. We are not
doing that literally, because your own merge commit 9e966378 is an ancestor of all three branches, and a rebase
would force-push over it.

We served the goal a different way: #1356 and #1357 were rebuilt fresh from current dev, carrying only their own
files.
Each is a forced update, and the result is the diff-shrink you asked for β€” the set goes
from 34 files and +16,228 to 21 files and +8,178. 9e966378 is deliberately no longer an ancestor of #1356/#1357;
it stands on this branch, where you pushed it, untouched.

We chose the rebuild over the rebase because it re-parents reviewed content rather than rewriting it. For #1357 the
rebuilt tree is byte-identical to the head our own review cleared (af9c25f057); only ancestry changed. For
#1356 that is no longer the whole story, and we would rather say so:
after the rebuild we also removed
tools/engine_evidence.py and its test from it, because this revision left #1356 importing nothing from that
module β€” so shipping it there would have been 524 lines the PR does not use. Every one of #1356's remaining 12
files is byte-identical to the reviewed content; two files are simply gone.

If you would rather have the rebase, say so and we will do it. It is your history and your call; we did not want to force-push over your commit when there was a functional alternative.

check_ablate_evidence.py: we moved it to where it belonged rather than parking it

You treated the evidence half as a reader without a writer and asked us to park it. We are parking the part that
genuinely is one β€” the SCORE_EVIDENCE identity binding in eval_glm.py β€” and you are right about it: nothing on
dev reads that variable.

But check_ablate_evidence.py is not in that position. Its writer is #1356's own coli-ablate/2 engine mode.
Rather than assert that, we tested it at the head we are pushing. The checker refuses an artifact whose schema
line reads coli-ablate/1 β€” the version your dev mode emits β€” with
[ablate-evidence] INCOMPLETE: header keys or values are not exact, exit 1; and its own 91-check suite passes
against coli-ablate/2 shapes. So the checker is bound to the schema #1356 introduces. It has a writer; the writer
just lives in the next PR, not this one, so it has moved to #1356.

The full end-to-end round trip was regenerated against the current integrated tree rather than quoted from an
earlier run: an integration cell drove #1356's engine mode over a real container and fed the artifact to this
checker, which validated it against the manifest and the model's own config.json and passed. It is reported with
#1356's evidence.

If you still want it parked, say so and we will park it.

Your asks

you asked disposition where it lives now
"the body … no longer match[es] the diff"; pack_python.py "already fixed on dev, merged as #1364" done β€” body corrected; the stale import-closure claim is gone. You are exactly right about what survives: the test additions plus the release.yml gate this PR's body
"the evidence half is inert … nothing reads it, zero files" β€” split it out done differently β€” the SCORE_EVIDENCE identity binding is parked; the durability half you said is "worth having on its own" stays and is now the whole of this PR. check_ablate_evidence.py moved to #1356 rather than parked (see above) this PR / #1356
"rebase #1356 and #1357 onto this branch's head, so each diff shows only its own work" done differently β€” rebuilt fresh from dev instead of rebased, to avoid force-pushing over 9e966378. Literal rebase offered above #1356, #1357

What changed in each PR, at a glance

PR files lines added moved in moved out parked added on re-review
#1355 8 β†’ 5 +3,315 β†’ +2,153 β€” the ablation-evidence checker, its test and the release.yml gate β†’ #1356 the SCORE_EVIDENCE identity binding a durability guard that fails when the per-row flush is removed; a frozen kernel-roster literal
#1356 15 β†’ 12 +5,449 β†’ +3,706 the ablation-evidence checker, its test and the release.yml gate, from #1355 engine_evidence.py and its test β€” dropped, no importer left here β€” the cap derived from CTX and checked ahead of all three allocations; removal of a one-implementation dispatch typedef; a real import check in the archive gate; a 2.01Γ— logit_topk_select fix
#1357 11 β†’ 4 +7,464 β†’ +2,319 β€” five files returned to the PR that owns each check_native_mtp_witness.py + its test, 2,613 lines seven per-ordinal frame-order tests and a frozen order anchor; the coupling test made bidirectional
set 34 β†’ 21 +16,228 β†’ +8,178

Every ask across the set

One row per ask, in your order. Several asks were raised on one PR and resolved on another β€” that crossing is
the thing this table exists to make visible. The disposition is the same word each PR's own comment uses.

your ask asked on resolved in disposition detail
"the body … no longer match[es] the diff"; pack_python.py "already fixed on dev, merged as #1364" #1355 #1355 β€” this PR's body done this comment
"the evidence half is inert … nothing reads it, zero files" β€” split it out #1355 #1355 (the SCORE_EVIDENCE binding removed) and #1356 (the checker, its test and the release.yml gate) done differently this comment Β· https://github.com/JustVugg/colibri/pull/1356#issuecomment-5725636433
"rebase #1356 and #1357 onto this branch's head, so each diff shows only its own work" #1355 #1356 and #1357 β€” both rebuilt fresh from dev rather than rebased done differently this comment
"is ABLATE_SCORE used by anyone outside your own tree?" #1356 #1356 done https://github.com/JustVugg/colibri/pull/1356#issuecomment-5725636433
"Could the writer collapse to a plain FILE pointer with the tests driving a tmpfile?" #1356 #1356 β€” c/colibri.c; the second structure you named still carries two production-path function pointers done for AblateWriter, NOT for AblateOutputRun https://github.com/JustVugg/colibri/pull/1356#issuecomment-5725636433
"I would make the prose match what the cap actually bounds" #1356 #1356 β€” c/colibri.c, docs/ENVIRONMENT.md done, and then some https://github.com/JustVugg/colibri/pull/1356#issuecomment-5725636433
"send the witness alongside the engine change that emits the record it needs" #1357 monotophic/colibri codex/parked-mtp-witness @ e0474748 β€” out of the PR entirely, preserved on a branch, returning with the engine change parked https://github.com/JustVugg/colibri/pull/1357#issuecomment-5725733595
"the logprob-gap hardening as its own small PR now" #1357 #1357 β€” it is now the whole PR, 4 files done https://github.com/JustVugg/colibri/pull/1357#issuecomment-5725733595
"neither transcript tool is referenced by c/Makefile or by any workflow … What is meant to invoke them?" #1357 #1357 β€” answered; wiring offered on your word answered https://github.com/JustVugg/colibri/pull/1357#issuecomment-5725733595

There is also a c/Makefile interaction between #1356 and #1102 that asks nothing of you; it is noted on both
threads.

What crossed a PR boundary

Without this map, this PR's deletions read as us dropping your work. They are not deletions; they are relocations.

file was in now in why
c/tools/check_ablate_evidence.py #1355 #1356 its writer is #1356's coli-ablate/2 mode
c/tests/test_check_ablate_evidence.py #1355 #1356 follows its subject
.github/workflows/release.yml #1355 #1356 the gate it adds is for the checker above
c/tests/check_native_mtp_witness.py (+ its test) #1357 parked 2,613 lines waiting on an engine that emits MTPEMIT

Merge order, so you can sweep without reading us

Merging #1355 first gives the smallest review for #1357, which then merges dev and its copy of the shared
foundation drops out mechanically. But any order merges cleanly β€” we proved it rather than assuming it: all six
orderings of the three branches merge with zero conflicts and produce one identical tree.

One honest exception, and it is ordinary: #1356 and #1102 both add entries to c/Makefile and will conflict
there β€” only there; the engine sources merge cleanly.
Whichever lands second, we re-merge dev and push within a
day.

The duplication that is still there, and why

c/tools/engine_evidence.py and its test β€” 524 lines, two files β€” remain in #1355 and #1357, byte-identical.
#1356 no longer carries them at all: this revision moved the manifest helpers into check_ablate_evidence.py,
which left that PR importing nothing from the module, so shipping it there would have been 524 lines of code
nothing in the PR used β€” the very pattern you objected to. The duplication that remains is one pair across two
PRs, and it drops out when #1355 lands. The 6,700 lines you counted three times are now 524.

Details β€” origin accounting and evidence

maintainer-requested: body correction; SCORE_EVIDENCE binding parked; the de-duplication.
dev-motion: pack_python.py empty diff (your #1364 fixed it on dev).
re-review-found: the durability guard below.

One thing our own re-review found, disclosed because it is a real gap we shipped. This PR's headline feature is
incremental, per-row durability, and the test named for it could not detect losing it: deleting the per-row
flush() left the suite green. That is a test that manufactures confidence. There is now a guard that fails when
the flush is removed and passes when it is present β€” verified by running the mutation, not by inspection.

Also disclosed: the transcribed wire-format literals in these tools are hand transcriptions of the C source.
Module drift is pinned by tests; C-source drift is not. We have a follow-up in mind for that and are not
folding it in here.

Authored by Opus 5 in Claude Code, analysis in partnership with @Monotophic

@monotophic monotophic changed the title feat(tools): offline ablation-evidence checker and an evidence-bound eval harness feat(tools): durable per-request results and strict stdout classification in the eval harness Sep 18, 2026
@JustVugg
JustVugg merged commit 3dca747 into JustVugg:dev Sep 21, 2026
28 checks passed
@monotophic
monotophic deleted the evidence/python-tooling branch September 21, 2026 04:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants