Add a byte-exact golden regression harness for trajectory tokenization - #996
Conversation
|
Independent consumer review by Hayek and his review delegate; posted by Jarvis at Brad's request. The first-person validation statements below describe the reviewer's work. Changes requested — two P2 harness coverage issues at
Validation: independently read all three added Python files and checked both JSON catalogs; all 13 named value/digest records are internally consistent, and the trace contains776 calls across279 nodeids. Scope/limits: PR996 adds only five test/fixture files; |
|
Independent review by Joshua; posted by Jarvis at Brad's request. Validation below describes Joshua's work. Reviewed exact HEAD I found one blocking correctness issue in the update path:
Two coverage limits are worth keeping explicit: hosted CI runs the trace plugin inert because it does not set Independent validation: all 756 trajectory tests passed in check mode under xdist (including 14 named cases), the committed trace has 279 nodeids / 776 calls with the expected schema, and the exact hosted CI is green. I did not run update mode against the checked-in files or perform downloads. |
|
Addressed all three P2s at
Verification ( On the coverage note that hosted CI runs the plugin inert: the one switch is |
|
Independent follow-up by Joshua, posted by Jarvis under Brad’s requested review campaign. Follow-up review of exact HEAD The revised teardown discards the node from The broad Qwen loader skip noted in my first review is also narrowed to offline/cache dependency exceptions, so ordinary |
|
Independent follow-up by Hayek and his review delegate, posted by Jarvis under Brad’s requested review campaign. Follow-up review at
All 14 named checks passed independently, including the four cached Qwen cases, with network access denied and CUDA hidden. I read the cumulative six-file change and found no additional material regression in the reviewed scope. Both JSON catalogs remain byte-identical to the prior reviewed head; all 13 value/digest records are consistent, and the trace still contains 776 calls across 279 nodeids. This closes my two earlier findings, not the separate update-mode-retention review. I did not repeat the full trajectory/xdist suite, package builds, GPU workloads, or private captures. Hosted CI is a separate check; the quality job was still running at the retained review snapshot. |
Opt-in via ART_TOKENIZE_GOLDEN=check|update; inert otherwise. Records a sha256 over (model, tokens, hex logprobs, flags) per tokenize_history call for every test under tests/unit/trajectories, xdist-safe via worker part files merged by the controller.
Fake character-tokenizer cases always run; Qwen/Qwen3-0.6B cases skip when the tokenizer is not cached offline. Failures name the first differing field and index.
Capture raw tokenize_history outputs during the call and hash them in teardown so timing tests are not perturbed. Track call-phase outcomes via pytest_runtest_makereport: update mode only replaces or drops entries for tests that ran and passed, skips writing on an interrupted session, and never records failed tests. Ship unknown nodeids from xdist workers, write worker fragments under pytest's shared basetemp, treat any other truthy ART_TOKENIZE_GOLDEN value as check, add the no_tokenize_golden marker, and make the inert path fixture-free.
Fake cases no longer request the transformers-backed fixture, so they run without transformers. Tokenizer identity and the pinned revision are folded into each case's input digest; only those 13 digests changed.
In check mode a passing test with a golden entry but no tokenize_history calls now fails like any call-count mismatch instead of passing silently. A call the harness cannot digest fails the test in either mode and un-marks the node so update mode never writes a truncated entry.
Seed a golden in a temp copy of the harness and prove that an injected digest failure leaves the entry byte-identical in update mode, that a zero-call test with an entry fails in check mode, and that the control probe records normally.
Catch ImportError, OSError and the huggingface_hub entry-not-found errors around get_tokenizer; loader regressions such as TypeError now propagate.
d612f10 to
fb92c81
Compare
Summary
A byte-exact golden regression harness for
art.trajectoriestokenization, built so that refactors of_tokenize_chat_view(see the companionrefactor/tokenize-chat-view) can prove identical output rather than argue for it. Tests and fixtures only; nosrc/changes.Under
tests/unit/trajectories/:_tokenize_golden.py— canonicalization and digests: sha256 over(model, tokens, logprobs as float.hex() with NaN → "nan", flags as ints), 16-hex per-field prefixes, plus an input digest (serialized history + kwargs + tokenizer identity/revision) so a failure distinguishes "input changed" from "tokenizer behavior changed".conftest.py— a pytest plugin that is a verified no-op unlessART_TOKENIZE_GOLDENis set (collection is byte-identical with and without it; the inert path requests no fixtures). Incheck/updatemode it wraps thetokenize_historyfunnel, whichHistory/Trajectory/TrajectoryGroup.tokenizeandtokenize_trajectory/tokenize_groupall resolve lazily, so every public entry point is traced. xdist-safe: workers write part files under the controller's basetemp and the controller merges them.test_tokenize_golden.py+tokenize_golden_cases.json— 13 named cases with full token/logprob/flag lists: 9 with the fake tokenizers fromtest_tokenize.py(multi-turn chat + tool calls + reasoning;enable_thinking; thinking-off literal<think>markers; multi-part assistant content; exact/sampled projection; length-stop terminators; mixed length/stop captured histories; NaN logprobs; inexact length stop — the areas fixed in Preserve exact histories across nonterminal length stops #829, Fix length-stop assistant provenance #830, Anchor exact length boundaries to rendered stop spans #847, Prefer exact length-stop boundaries over probe suffix collisions #871, Preserve proved boundaries in mixed-stop captured histories #882, Preserve distinct captures with different prompt tokens #886, Preserve NaN log probabilities in trajectory JSON #903, Preserve group types and whitespace boundaries in trajectory tensorization #904, Fix sampled-token matching after hidden demonstration text #910, Preserve native token boundaries during trajectory replay #924, Preserve literal think markers in thinking-off histories #967) and 4 through the realQwen/Qwen3-0.6Btokenizer pinned to revisionc1899de2…, loadedlocal_files_only=True(skips, never downloads, when uncached).tokenize_golden_trace.json— digests for 776tokenize_historycalls across 279 existing test nodeids.Modes: unset/
0/off/false/no= inert;check(or any other truthy value) = compare and fail with the first differing field;update= rewrite. Update mode only replaces entries for tests whose call phase actually ran and passed, records nothing for failed tests, and writes nothing on an interrupted session, so skipped/deselected/crashed tests cannot silently drop goldens.@pytest.mark.no_tokenize_goldenopts a test out. Digests are computed after the test body finishes so timing tests are not perturbed (remaining in-window overhead ≤ 0.03%).~292 KB of JSON, sorted keys, no paths or hostnames.
Validation
--noconftest.ART_TOKENIZE_GOLDEN=check -n 4: 756 passed (twice).-n0update reproduces the-n 4goldens byte-identically._tokenize_chat_view: check mode caught it in 38 traced tests plus 11 named cases while zero pre-existing assertions noticed. Review verdict "land with fixes"; all findings (deferred digests, update-mode retention rules, xdist unknown-entry reporting, revision pinning, transformers-free fake cases, part-file location, env-value handling, fixture-free inert path) are addressed in the last two commits.ruff check/ruff format --checkclean. Post-rebase onto3ad9a5f8d: 756 passed inert and in check mode withrefactor/tokenize-chat-viewmerged on top.Known gaps (documented in the conftest docstring): direct calls to
_tokenize_history/_tokenize_chat_viewand the_parallelspawned-process pool are not traced; golden mismatches surface as teardown errors.