fix(examples): CAVIAR deep-review follow-ups — vocabulary reproducibility, shipped audit artifacts, canonical close_34 - #199
Conversation
The EC candidate pool gained became_far/distance_increasing unconditionally, which made the shipped e9/e10 artifacts (README sections D.1/E: the 0.942 and 0.733 rows) unreproducible by any command that exists at HEAD. 'activity' restores the exact four-transition pool those artifacts were generated with; 'full' (the default) keeps HEAD's current six-relation behavior byte-identical. Both runners now also record the vocabulary actually searched in the result JSON (the CV runner previously recorded none at all): top-level transition_vocab in both, plus per-fold ec/direct candidate_vocabulary lists in the CV fold record. Red-first: 13 tests (parse defaults/choices/scoping refusals, helper filtering, fold-record vocabulary) failed before the change.
The commands labeled '(section D.1)' and '(section E)' reproduced the E.1-era 12-name pool at HEAD, not the shipped e5/e9/e10 configuration -- a replayer following them got 0.778 with learned terminations where the README table says 0.733 with empty ones, with nothing to explain the divergence. Every EC command now spells --transition-vocab explicitly, the block opens with the vocabulary-history note, section E.1 gets its own command (previously absent), and the D.1-item-1 (F1 holdout + fixed 0.75 gate) configuration gets a command for the first time.
Replay evidence (CPU-deterministic, run against this tree's own bytes): - run_caviar_cv.py --folds 10 --seed 7 --transition-vocab activity on the combined dump corpus reproduces e10_cv/caviar-e10-cv10.json EXACTLY: micro EC P/R/F1 0.6580/0.8271/0.7329 (tp=1516 fp=788 fn=317), direct reference 0.2137 (tp=232 fp=106 fn=1601), identical fold assignment, and zero mismatches across all 10 folds' init/term gates, clause lists, stop reasons, event counts, and scoring blocks. - run_caviar_theory.py --protocol ec --data continuous --max-body-literals 3 --holdout-score f1 --ec-fit-mode permutation-null --transition-vocab activity reproduces BOTH e9_permutation_null artifacts exactly (tie default and 0.001): init gate 0.0444 / term gate 0.125, initiation theory [both_active, close], empty termination theory, frame F1 0.9424 (tp=442 fp=7 fn=47), full null summaries and top-5 abstention scores all equal. This closes the review's HIGH finding that the shipped section D.1/E evidence was unreproducible by any command existing at HEAD.
The abstention explanation compared gates across DIFFERENT candidate pools: the quoted 0.035-0.046 dump range is section E's (10-name state-only vocabulary), while section G runs E.1's 12-name pool. The like-for-like comparison (e11 vs f_xml, both 12-name, from the shipped artifacts) is 0.050-0.0625 vs 0.050-0.0714: identical minima, +14% at the maximum -- deduplication barely moved the bar, so 'the gate rose 10-100% on every fold' was a vocabulary-pool artifact misattributed to corpus deduplication. The paragraph now attributes the clean-corpus abstention to what the artifacts actually show: the candidate's holdout F1 collapsing under leak-free scene-family folds (the two-regime transfer failure the same section already documents), against essentially unchanged gates. The misattributed reading is kept as an explicit correction note rather than silently rewritten.
Section D.1 item 1 (F1 holdout under the fixed 0.75 accuracy-era gate) reported its numbers with no JSON in results/ -- one of the two pre-registered D.1 runs was unverifiable, against the README's own 'every number has an artifact' contract. Shipped: results/e9_f1_holdout/caviar-e9-cont_rel_ec_mnc2_f1holdout_ fixed075.json, generated by the command now documented in the Reproduction block (--holdout-score f1, --transition-vocab activity, fixed gate). The artifact confirms the section's claims exactly: top initiation body both_active & close at holdout F1 0.2381, margin 0.1381 over the 0.100 runner-up, and both searches abstaining under the 0.75 gate (init/term theories empty). The D.1 text and Files line now point at it.
Section F asserted the 21 real / 3 duplicate / 1 splice-phantom classification of the dump's 25 meeting transition events with neither an audit tool nor an artifact -- while section H called the audit 'reproducible, independently-verified'. New examples/caviar_woled/audit_dump_vs_xml.py ports the one-off analysis: dump segments are matched to source videos by exact pixel-trajectory voting with iterative peeling (a spliced segment resolves into multiple (video, offset) clusters), both sides' transition events are derived by the shared first-frame-is-never-an-event walk, and every dump event is classified against the XML-native event set. Real-data run (shipped as results/f_audit/caviar-f-dump-vs-xml- audit.json) reproduces section F exactly: 25 dump events (13 init / 12 term), 21 XML events (11/10), classification real=21 duplicate=3 splice_artifact=1, zero XML events unclaimed; the duplicates are wk2gt@frame71 (init) and fomdgt2@frames475/495 (init/term), the phantom is train#15's termination at t=833520 bridging into mws1gt, and duplicated_gold_pairframes records wk2gt=855 -- the exact number the README's consequence paragraph cites. Also newly visible: wk3gt/fomdgt3 are shipped in both dump files too, with zero meeting mass. Tests: synthetic three-video corpus exercising all three classifications, the two-cluster splice resolution, and the duplicated-mass accounting (6 tests).
Section G's transfer argument quoted diagnostic numbers (the reference clause applied directly to the held-out wk fold at frame F1 0.890 / tp=1060 / fp=0, and the per-segment coverage census: wk1gt 232/468, wk2gt 828/855, zero on the eight remaining meeting-bearing segments, close never holding on a positive in lb1gt/rffgt) that existed in no shipped artifact. New examples/caviar_woled/xml_meeting_census.py computes both, using the CV harness's own _xml_family_fold_assignment for the fold split (never a re-implementation). Real-data run shipped as results/f_xml_scene_cv/caviar-g-meeting-census.json; it reproduces every quoted number exactly: - wk fold (fold 5) clause application: P=1.0000 R=0.8012 F1=0.8896, tp=1060 (= wk1gt 232 + wk2gt 828), fp=0, fn=263; - train side of the wk fold: clause covers 0/489 positives and 106 negatives; - census: wk1gt 232/468, wk2gt 828/855, all eight other meeting-bearing videos 0 covered (sum 489), with close-on-positives 0 for lb1gt/rffgt. Tests: synthetic two-video corpus pinning the census columns and the fold scoring/train-side accounting (2 tests).
The XML converter applied one fluent-independent 25px close threshold, but the canonical CAVIAR definitions (RTEC rules.prolog) define meeting over close_25 and moving over close_34 -- so the section G moving row was measured under the meeting threshold while the README called its selected clause 'the canonical published rule', and compared it against published moving scores obtained under close_34 semantics. convert_xml_corpus's close_threshold now defaults to None and resolves through the new CANONICAL_CLOSE_THRESHOLDS table (meeting 25.0 -- byte- identical to before -- moving 34.0); an explicit value still overrides, which keeps the historical measurement reproducible. The CV runner records the resolved threshold in its result JSON. Re-run moving CV (canonical, shipped as caviar-f-xml-moving-cv10.json; the threshold-25 measurement is preserved under caviar-f-xml-moving-cv10-threshold25.json): - direct reference micro P/R/F1 0.5334/0.3817/0.4450 (tp=1197 fp=1047 fn=1939), same clause both_walking & close on all 8 non-empty folds; - per-fold, widening close behaves as the semantics predict (fold 3 F1 0.286 -> 0.504), but the fomd/mc1 fold (1546 of 3136 gold frames) now abstains on a selection tie (margin 0.0093 vs the 0.01 floor) where the threshold-25 run had committed -- the canonical threshold LOWERS the micro figure (0.4868 -> 0.4450) and exposes the old number's tie-fragile fold, rather than fixing recall; - EC side unchanged in shape: initiation empty everywhere (5 observable initiations), termination both_active & close on 7/10, micro 0.000. README section G: new close-threshold semantics paragraph, updated table row, rewritten Moving paragraph, Files note. Red-first: 3 tests (canonical table, per-fluent resolution, dist-34 tie rule) failed before the change; the explicit-override test pins the historical threshold-25 path.
…stered The 0.7782 headline was presented under a 'pre-registered' label, but its two termination-signature relations were chosen after step 1's test-side error analysis was known, on the same folds -- test-fold rows influenced vocabulary construction, exactly the adaptivity section H faults the published baselines for. Sections E.1 and H now state this plainly: gates/seeds/folds remain as pre-registered in section E; the vocabulary is 'a second iteration informed by step-1 error analysis on the same folds' (E.1 opening, the headline caveat, the H table row, and both H claim paragraphs). The H contrast with the published baselines is reframed as 'one disclosed adaptive step' vs 'an unreported number of tuning trials'. No numbers changed.
levi770
left a comment
There was a problem hiding this comment.
Deep review — PR #199 @ 88314ada4
Method: 6-dimension parallel review (vocab plumbing, new tools, close-threshold semantics, README claims-vs-artifacts, test quality, and a full closure ledger against #178's 23 review findings), every finding adversarially verified, and — since this PR's central claim is reproducibility — independent replays executed on my machine from the README's own commands.
Independent replay verification (the headline result)
I downloaded the OLED dataset fresh (per-file md5s match the README table exactly), and ran five replays on Linux/CPU against artifacts produced on the author's Windows machine:
| Replay | Compared against | Non-volatile value conflicts |
|---|---|---|
e10 @ --transition-vocab activity |
shipped e10_cv/caviar-e10-cv10.json |
0 (micro EC 1516/788/317 → F1 0.7328982 exact) |
| e9 permnull, default tie | shipped …permnull_tiedefault.json |
0 (168 fields) |
e9 permnull, --tie-tolerance 0.001 |
shipped …permnull_tie001.json |
0 |
e11 @ full (default) |
shipped e11_cv10_termination.json |
0 (F1 0.7782061 exact) |
| D.1 item 1 (f1-holdout + 0.75 gate) | this PR's new e9_f1_holdout/…fixed075.json |
0 — field-identical |
The e11 replay doubles as proof of the "default full is byte-identical to previous behavior" claim: new code, default flag, reproduces a pre-PR-generated artifact's every value. The only differences anywhere are new provenance fields (transition_vocab, candidate_vocabulary, close_threshold, per-iteration detail) absent from the older artifacts — which is exactly what two of my MEDIUM comments below are about, because several README sentences claim those fields exist in artifacts that predate them.
Also verified by my own hand: every headline number recomputes correctly against its shipped JSON (e10 F1, e9_f1_holdout top 0.238095/margin 0.1381, audit 21/3/1 + wk2gt 855 + 0 unclaimed, census 1060/0/263 → 0.8896349, moving close_34 micro 1197/1047/1939 → 0.4449814, threshold25 0.4867506); the threshold25 artifact is byte-identical to the pre-PR moving artifact; all five test suites pass locally (144 passed / 4 skipped, CPU torch); the like-for-like gate numbers in the rewritten Section G recompute from the shipped artifacts (minima 0.050 identical, max +14.29%).
#178 findings-closure ledger (23 findings)
- Closed by this PR, verified: H1 (Section G attribution retracted, replacement numbers artifact-backed), H2 + H3 (vocab flag + commands + replays — replay-proven above), M2 (e9_f1_holdout artifact matches prose exactly), M3 (no remaining pre-registration claim on 0.7782), M4 (audit tool + artifact, all counts match), M5 (census tool + artifact, every Section G figure checks out), M8 (canonical close_34 + honest 0.4450 < 0.4868 disclosure; the 0.0093 tie is in the artifact).
- Verified fixed in phase 1 (on the merge-base): M1, M6, M7, M9, M10, M11, M12, L2, L3, L4, L5.
- Declared out of scope (matches PR body): L1 / e12 GPU regeneration, and the conftest-guard half of M13.
- Silently dropped: the CI half of M13 — no workflow runs any caviar suite, including this PR's five; that is finding #10 below.
Verdict
The engineering substance is excellent and now proven reproducible — the HIGH trio is genuinely closed, the honest-regression disclosure (0.4450) is the right instinct, and phase 1 held up under spot-checks. Nothing blocking. The 15 findings are concentrated in one theme: the README's recording/replay language is written as if every shipped artifact carried the new provenance fields and replay coverage, but the non-regenerated artifacts predate them, and two provenance recordings are wrong or missing in the new code itself. Precision fixes, not rework.
| # | Sev | Where | Finding |
|---|---|---|---|
| 1 | MEDIUM | README:559 | "8 of 10" folds — the shipped artifact shows 9 of 10 (all nine select both_walking & close; fold 5 is the sole abstention) |
| 2 | MEDIUM | README:643 | "Every result JSON records the vocabulary it actually searched" is false for the pre-flag artifacts this paragraph tells readers to diff against |
| 3 | MEDIUM | README:478 | "each CV artifact records … close_threshold" — 3 of the 4 Section-G JSONs lack the key |
| 4 | MEDIUM | README:473 | Section G's "full independent replay reproduced every value" now vouches for the regenerated close_34 run and new census it never covered |
| 5 | MEDIUM | README:672 | Section-D command labeled as reproducing the caviar-e5-*_ec_* artifacts, which no committed runner version can structurally reproduce |
| 6 | MEDIUM | run_caviar_cv.py:1013 | Neural-mode fold record misstates the initiation search's vocabulary (lists relations never searched, omits close_nn) |
| 7 | MEDIUM | audit_dump_vs_xml.py:382 | The "reproducible" Section-F audit cannot run without torch, and torch is incidental to it |
| 8 | MEDIUM | xml_meeting_census.py:160 | Census artifact records no close_threshold, violating this PR's own recording convention |
| 9 | MEDIUM | test_audit_dump_vs_xml.py:159 | The miss-detector behind "0 unclaimed XML events" is only ever tested empty |
| 10 | MEDIUM | test_run_caviar_theory_args.py:457 | M13's CI half silently dropped: no workflow runs any caviar suite, including these five |
| 11 | LOW | run_caviar_theory.py:344 | --transition-vocab activity accepted but inert in neural EC mode — records a false provenance distinction |
| 12 | LOW | caviar_xml_corpus.py:183 | No shipped entry point can regenerate the threshold-25 moving measurement the explicit-wins comment promises |
| 13 | LOW | audit_dump_vs_xml.py:258 | Audit-tool robustness: offset frame arithmetic, bypassed input guard, re-implemented walk/cover logic |
| 14 | LOW | README:211 | Hardware/artifact table not extended for the new artifacts; no repro commands for the two tools' shipped JSONs |
| 15 | LOW | README:529 | Residual "under the same stricter gates" phrasing contradicts the section's own retraction |
| **Moving.** Under the canonical `close_34` the direct-protocol | ||
| reference selects the canonical published rule — now literally | ||
| `both_walking & close_34`, the same predicate the published rules use — | ||
| on every fold with a non-empty theory, 8 of 10 (micro F1 0.4450; up to |
There was a problem hiding this comment.
[MEDIUM] "on every fold with a non-empty theory, 8 of 10" — the shipped artifact says 9 of 10.
Per-fold from caviar-f-xml-moving-cv10.json: folds 0-4 and 6-9 each carry exactly [['both_walking', 'close']]; only fold 5 (the fomd+mc1 fold this paragraph's own mechanism explains, fn 1546) has clauses: []. So the canonical rule is selected on 9 folds, and "every fold with a non-empty theory" is 9 of 10, not 8. (Neither alternative reading rescues 8: folds where the clause actually fires on test, tp+fp>0, number 7.) The claim is otherwise right — all nine theories are literally the canonical rule — so this looks like a stale count from an earlier draft. One-word fix, but it's load-bearing: this is the sentence a reader uses to reconcile 0.4450 with the abstention story.
| Replaying the shipped D/D.1/E results requires `--transition-vocab | ||
| activity` -- with the default, the "section E" command below produces | ||
| section E.1's 0.778 configuration, not section E's 0.733. Every result | ||
| JSON records the vocabulary it actually searched (`transition_vocab` + |
There was a problem hiding this comment.
[MEDIUM] "Every result JSON records the vocabulary it actually searched (transition_vocab + candidate_vocabulary), so a replayed artifact can be checked against a shipped one directly" — false for exactly the shipped artifacts this paragraph is about.
The shipped e10_cv/caviar-e10-cv10.json contains zero vocabulary keys (this PR's own summary says the CV runner previously recorded none), e11_cv10_termination.json likewise, and the caviar-e5-*_ec_* artifacts predate the flag. My independent replays confirm the constructive half of the sentence works — a fresh e10 run at --transition-vocab activity matched every value the shipped artifact has, zero conflicts — but the shipped side of the diff has no vocabulary fields to check against, and a reader following this instruction verbatim will conclude the shipped artifacts are defective. Same precision issue with "the check is bit-for-bit": at file level the replay JSON is a superset (481 new provenance fields vs shipped e10); what is bit-for-bit is every field the shipped artifact contains. Suggested wording: "Result JSONs written by the current runners record … ; for the pre-flag shipped artifacts, a replay matches every recorded field bit-for-bit (verified for e10 and both e9 variants)." I can confirm that formulation is true — I reproduced it independently on Linux from the md5-verified public data.
| over DIFFERENT proximity predicates: meeting over `close_25`, moving | ||
| over `close_34`. The converter resolves its `close` relation through | ||
| exactly this table (`caviar_xml_corpus.CANONICAL_CLOSE_THRESHOLDS`; | ||
| each CV artifact records the threshold it ran with as |
There was a problem hiding this comment.
[MEDIUM] "each CV artifact records the threshold it ran with as close_threshold" — 3 of the 4 Section-G JSONs lack the key.
Verified directly: caviar-f-xml-moving-cv10.json has close_threshold: 34.0 ✓, but caviar-f-xml-meeting-cv10.json (never regenerated), caviar-f-xml-moving-cv10-threshold25.json (deliberately preserved pre-change bytes — correctly so), and the new caviar-g-meeting-census.json all have no such key. The runner does now record it unconditionally, so the accurate sentence is that runs made with the current runner record it, while meeting-cv10's 25 is implied by the pre-change fixed default and threshold25's value is encoded in its filename. Reword rather than regenerate — the preserved threshold25 bytes are worth more than the key.
| Moving: 18 intervals, 5 initiations, 8 terminations, 3,136 gold | ||
| pair-frames. | ||
|
|
||
| **Close-threshold semantics (per fluent, canonical).** The canonical |
There was a problem hiding this comment.
[MEDIUM] Section G's intro still vouches "a full independent replay reproduced every value in the shipped result files exactly" — but this PR replaced one of those files and added another the replay never saw.
The sentence (README ~465, outside the diff but now referring to new bytes) was written when Section G's artifacts were meeting-cv10 + the threshold-25 moving run. This PR regenerates the moving artifact as a brand-new close_34 run and adds the census JSON, and Section G's Files line now enumerates both — so the replay attestation silently extends to two artifacts with no replay evidence anywhere in the PR. Note the contrast with the D/E artifacts, where the replay paragraph is explicit about what was compared — and which I could and did independently reproduce; the XML-side runs I could not (the CAVIAR XML corpus location is machine-local). Fix: scope the sentence to the runs the replay covered, or replay the close_34 run and census and say so.
|
|
||
| # continuous, EC protocol, 3-literal relational search (CPU-only) | ||
| # continuous, EC protocol, 3-literal relational search (section D's | ||
| # 3-literal rows, the caviar-e5-*_ec_* artifacts; CPU-only). |
There was a problem hiding this comment.
[MEDIUM] The section-D command is labeled "(section D's 3-literal rows, the caviar-e5-*_ec_* artifacts; CPU-only)" — but no committed runner version can structurally reproduce those shipped artifacts.
The shipped caviar-e5-cont_rel_ec_mnc2/mnc3.json predate the flag era: no max_body_literals, no transition_vocab, and a 9-key ec block missing relational_search_pool/init_scores_last_iteration_top5 outright — while the runner as first committed already emitted max_body_literals unconditionally, so even the original committed code produces a different schema. The mnc3 variant also recorded min_new_covered: 3 where the command fixes 2, and the caviar-e5-*_ec_* glob sweeps in caviar-e5-cont_neu_ec_mnc2.json, a CUDA-required neural run, under the "CPU-only" label. Since the Reproduction intro explicitly invites diffing replays against shipped files, this pairing sets the reader up to conclude non-reproduction. Fix: label the command as reproducing the configuration (with expected schema growth), scope the glob to the two relational files, and drop mnc3 or add its variant command.
| args = p.parse_args(argv) | ||
| if args.data == "continuous" and args.test_json is None: | ||
| p.error("--data continuous requires --test-json (path to caviar-test.json).") | ||
| if args.transition_vocab != "full" and (args.protocol != "ec" or args.data != "continuous"): |
There was a problem hiding this comment.
[LOW] --transition-vocab activity is accepted in neural EC mode, where it is provably inert — and gets recorded as if it mattered.
The :344 scoping check rejects the flag where it would be a no-op (non-ec, non-continuous) but never checks --mode: under --mode neural --protocol ec, every downstream consumer of the filtered pool reads flag-invariant keys, so two runs differing only in the flag produce identical results while their JSONs record different transition_vocab values — a false provenance distinction. The README's "Replaying the shipped D/D.1/E results requires --transition-vocab activity" also sweeps the neural e5 artifact into that instruction. Either extend the :344 rejection to neural EC or record the flag as inert there. Related hardening: the theory runner's activity pool is an independent literal copy of the CV runner's (NEURAL_INIT_ACTIVITY_TRANSITIONS) and of caviar_continuous.TRANSITION_RELATION_NAMES — a cross-file equality test would pin drift.
| # `far`, structurally starving any `... & close` moving rule of exactly | ||
| # those gold frames. `convert_xml_corpus`'s `close_threshold=None` | ||
| # default resolves through this table; an explicit value still wins | ||
| # (which is how the historical threshold-25 moving measurement stays |
There was a problem hiding this comment.
[LOW] The explicit-wins comment promises the threshold-25 measurement "stays reproducible", but no shipped entry point can pass an explicit threshold.
Only the library function accepts one: the CV runner's XML path calls convert_xml_corpus(...) without a threshold argument, run_fold has no parameter, and parse_args has no --close-threshold flag — so regenerating …moving-cv10-threshold25.json (F1 0.48675) requires editing a call site. The artifact itself is correctly preserved byte-for-byte, so nothing is lost today; but the comment describes a replay path that does not exist. Either plumb an optional --close-threshold through the CV runner (recording already handles it) or reword the comment to say the historical measurement is preserved as an artifact, not regenerable.
| return None | ||
| _, v_idx, offset, members = best | ||
| video = videos[v_idx] | ||
| frame = (event["t"] - offset - video["time_offset"]) // video["frame_ms"] |
There was a problem hiding this comment.
[LOW] Audit-tool robustness notes (three, same file).
(1) _map_event_to_xml's frame arithmetic assumes the zero-offset, unit-stride relationship between dump time and XML frame; a nonzero time_offset or non-unit stride segment would misalign silently rather than fail — worth an assertion since the tool's authority is exactness. (2) The tool bypasses load_continuous's real-file input guard by reading the dump directly, so a truncated/malformed dump degrades into wrong counts instead of the loader's typed error. (3) The transition walk and clause-cover logic are re-implementations of the pipeline's (rather than imports), so the audit can drift from what it audits; importing the pipeline's own functions would make the audit self-anchoring. None of these affects the shipped numbers — I verified those independently — they affect the tool's trustworthiness on the next corpus.
| F1 0.238 with a real 0.138 margin over the 0.100 runner-up) — but | ||
| every body still fails the accuracy-era fit gate (0.75), which under | ||
| F1 semantics on 10 positives demands near-perfection. Artifact: | ||
| `results/e9_f1_holdout/caviar-e9-cont_rel_ec_mnc2_f1holdout_fixed075.json` |
There was a problem hiding this comment.
[LOW] Reproduction completeness: the "Hardware, per artifact" table wasn't extended for this PR's new artifacts (e9_f1_holdout/, f_audit/, the census), and the two tools' shipped JSONs have no repro commands in the Reproduction section.
The table's premise is "each result JSON self-reports its input paths" — true for the runner outputs, but the audit/census JSONs are the PR's own new evidence class and appear in neither the table nor the command list. Two commands (python examples/caviar_woled/audit_dump_vs_xml.py …, … xml_meeting_census.py …) with their expected outputs named would let a reader regenerate the PR's two newest evidence files the same way they can now regenerate e9/e10.
| shipped tool `examples/caviar_woled/xml_meeting_census.py` (which | ||
| imports the CV harness's own `_xml_family_fold_assignment` for the fold | ||
| split — same table, same seed, never a re-implementation). The EC | ||
| initiation search, run independently under the same stricter gates, |
There was a problem hiding this comment.
[LOW] Residual "under the same stricter gates" phrasing survives the retraction.
The rewritten Section G correctly retracts the gate-based attribution (like-for-like minima identical, max +14.3%), but this later sentence still frames the XML-CV abstention as happening "under the same stricter gates" — the framing the rewrite just disowned two paragraphs earlier. Align it with the section's own conclusion (holdout-F1 collapse, not gate strictness).
caviar-f-xml-moving-cv10.json records [['both_walking','close']] on folds 0-4 and 6-9; only fold 5 abstains. The '8 of 10' was a stale count from an earlier draft.
The rewritten Section G attributes the abstention to holdout-F1 collapse under leak-free folds, with like-for-like gate minima identical; this later sentence still leaned on the disowned gate-strictness framing.
'Every result JSON records the vocabulary it actually searched' was false for the pre-flag shipped artifacts (caviar-e5-*_ec_*, e9_permutation_null/*, e10, e11), which predate transition_vocab. State the field is written by current runners, list the pre-flag artifacts, and define the replay check as matching every field the shipped artifact does contain (replay JSON a strict superset).
…reshold 'each CV artifact records ... close_threshold' held for only 1 of the 4 Section-G JSONs. Scope the claim to runs made with the current runner, name the regenerated moving-cv10 as carrying 34.0, and note meeting-cv10 predates the key (pre-change fixed default 25) and the preserved threshold-25 artifact encodes its value in the filename.
The 'full independent replay reproduced every value' sentence predates the regenerated close_34 moving run and the new census artifact, which that replay never saw. Name the two artifacts the replay did cover and state the newer two carry no independent-replay attestation.
The caviar-e5-*_ec_* files predate max_body_literals/transition_vocab and the enlarged ec block, so no committed runner reproduces their schema; the mnc3 file also recorded min_new_covered 3 where the command fixed 2, and the glob swept a CUDA neural run under a CPU-only label. Scope the command to the two relational files as a configuration replay with expected schema growth, add the mnc3 flag variant, and exclude the neural artifact.
…mmands Extend the per-artifact hardware list with e9_f1_holdout/, the f_audit JSON, and the census, and add Reproduction commands (with expected headline values) for audit_dump_vs_xml.py and xml_meeting_census.py so the PR's two newest evidence files are regenerable like the runner outputs.
Every census number depends on the close predicate's threshold, but the artifact carried no close_threshold key, violating the recording convention this PR establishes for the CV artifacts. Record it from CANONICAL_CLOSE_THRESHOLDS['meeting'] (25.0) and regenerate the shipped JSON; the diff is a single added key, every existing value byte-identical. Red-first test drives main() through a synthetic corpus and asserts the recorded threshold.
…ecords
Under --mode neural, run_fold recorded ec.candidate_vocabulary as
sorted(train_ec_relations) -- naming close/far/became_far/
distance_increasing, which the neural initiation search excludes by
design, and omitting close_nn, the one neural relation it did search.
Record the structured {init: {relational, neural, excluded}, term}
form instead (same shape as run_caviar_theory's neural-EC path); the
relational-mode flat listing is byte-identical to before. Red-first
test drives run_fold in neural mode and pins both pools.
Under --mode neural --protocol ec the flag is provably inert (the neural initiation pool is activity-based by construction and no downstream consumer reads the filtered subset), yet it was accepted and recorded -- two identical runs could carry different transition_vocab values, a false provenance distinction. Extend the existing scoping rejection to neural EC, matching the CLI's refusal pattern for every other silent no-op, and note the neural e5 artifact's exception in the README's Reproduction intro. Red-first parse_args test.
The audit's own work is XML parsing plus frame arithmetic, but torch arrived transitively through caviar_continuous's (and caviar_convert's) module-level imports -- a 200MB+ install for a JSON-vs-XML diff. Move both modules' torch imports into the only functions that use it (convert_continuous / convert_split / put_caviar_relations), leaving every torch-free consumer -- load_continuous in particular -- importable on a minimal interpreter. Regression test blocks torch at the import machinery in a subprocess and drives the audit and census import chains; verified red against the pre-fix source.
CANONICAL_CLOSE_THRESHOLDS's explicit-wins comment promised the historical threshold-25 moving measurement 'stays reproducible', but no shipped entry point could pass an explicit threshold. Plumb an optional --close-threshold through run_caviar_cv (XML path only; refused on the dump path, whose conversion never parameterized it; None default byte-identical), record the explicit value in the artifact, point the comment at the entry point, and add the regeneration command to the README's Reproduction block. Red-first tests: parse_args wiring plus a run_fold spy proving both conversions see the explicit value.
The audit tool's authority is exactness, so every place its arithmetic assumes the corpus-wide 40ms zero-offset frame grid now refuses loudly instead of misaligning silently: build_xml_xy_index rejects a video on a different time base, _map_event_to_xml rejects an event timestamp that does not land on the matched cluster's grid, and main() opts into load_continuous's verified real-file counts so a truncated dump dies with the loader's typed error. Two equivalence pins stop silent drift: the audit's transition walk against derive_ec_targets_continuous, and the census's inlined cover reading against relational_search.body_cover.
The section-F headline of zero unclaimed XML events is only evidence if the detector behind it can report a non-empty answer. Strip a dump segment's meeting annotations so b.xml's observed initiation has no dump event left to claim it: the audit must name that exact event (video, pair, frame, kind), not stay empty.
Review follow-up: no workflow ran any caviar suite. A dedicated job installs CPU torch so the theory-loop, XML-corpus, audit and census suites run for real instead of module-skipping; dataset-gated tests self-skip (no corpus data ships in the repo), and GPU-only suites stay local per the hardware table in docs/experiments/caviar/README.md.
|
@levi770 — all 15 findings closed in
Suites: 62 passed / 4 skipped (dataset-gated) on the five CI-job suites locally; 12/12 on the extended audit suite. The regenerated census JSON changed by additive provenance fields only. Thank you for the independent replays — that cross-platform zero-conflict table is now the strongest evidence this track has. |
| # `load_continuous`'s verified real-file counts (train 22366/21) so a | ||
| # truncated or drifted dump dies with the loader's typed error instead | ||
| # of degrading into wrong audit counts. | ||
| import caviar_continuous |
|
|
||
|
|
||
| def test_run_fold_xml_source_passes_explicit_close_threshold_to_conversion(monkeypatch): | ||
| import caviar_xml_corpus |
Fix-round verification —
|
| Claim | My result |
|---|---|
| Five CI-job suites: 62 passed / 4 skipped | 62 passed / 4 skipped — exact match (CPU torch, dataset-gated skips) |
| Extended audit suite 12/12 | 12/12 |
| Remaining suites (cv / theory-args / cv-xml) | 145 passed / 4 skipped |
| Census regenerated additive-only | Byte-verified: exactly one added line ("close_threshold": 25.0) |
| Audit tool torch-free | 1/1 on a genuinely torch-less interpreter (stronger than the meta_path blocker: no torch installed at all) |
| New tests discriminate | Graft-proven: on pre-fix bytes the behavior-changing tests fail (time-offset/40ms-grid/off-grid refusals, loader opt-in, census recording = 5 failures; #6 TypeError, #11 DID-NOT-RAISE, #12 unknown-flag), while the coverage-type tests (#9 miss-detector, #13 equivalence pins) correctly pass both sides — they prove pre-existing code was already right |
Ledger
- feat(ilp): Tensorized Differentiable ILP engine #1–Make set_rule_mask_sparse fully device-side (remove soft-prob host download) #5, chore: release v0.5.0 #14, build(deps): bump actions/upload-artifact from 4 to 7 #15 (README): CLOSED. Each rewording byte-checked against the artifacts; all seven commits touch only the README (no collateral). Highlights: the "9 of 10" recount matches my own fold-by-fold count; the Add comprehensive full-codebase review report and architecture map #4 rescoping is honest, not just narrower — the preserved threshold-25 file is byte-identical to the artifact the original replay attestation actually covered; the remaining "8 of 10" mentions refer to the dump-protocol corpus, correctly.
- Expose device-native Python membership/credit APIs (DLPack instead of host Vec<bool>) #6, build(deps): bump actions/download-artifact from 4 to 8 #11, build(deps): bump actions/cache from 4 to 5 #12 (runners): CLOSED. Neural-mode fold records now use the structured
{relational, neural, excluded}form derived from the same_neural_init_vocabthe search uses,close_nnincluded; the neural-EC vocab refusal is typed and scoped exactly (relational EC still acceptsactivity);--close-thresholdplumbs through toconvert_xml_corpusand the recorded JSON, and theNonedefault resolves through the same canonical path as before. - Eliminate remaining semantic-loop DTOH metadata fallbacks and codify Python GPU-native contract #7, Add persistent Python relation-store API for named DLPack-backed GPU relations #8, build(deps): bump release-plz/action from 0.5.50 to 0.5.128 in the github-actions-minor-and-patch group #9, build(deps): bump actions/checkout from 4 to 6 #13 (tools): CLOSED. Lazy imports verified down through
caviar_continuous/caviar_convert; the miss-detector test constructs a genuinely orphaned XML event and asserts it is named (video/pair/frame/kind); the two equivalence pins import both implementations and compare outputs. - build(deps): bump actions/setup-python from 5 to 6 #10 (CI): PARTIAL. The
caviar-examplesjob is real, runs five suites for real (my 62/4 reproduction), and a failure fails the job. But it excludestest_caviar_cv.py,test_run_caviar_cv_xml.py, andtest_run_caviar_theory_args.py— the three suites carrying this round's own regression tests for Expose device-native Python membership/credit APIs (DLPack instead of host Vec<bool>) #6, build(deps): bump actions/download-artifact from 4 to 8 #11, and build(deps): bump actions/cache from 4 to 5 #12. The job comment calls them GPU-only, but that misreads the hardware table (which classifies artifacts, not suites):test_run_caviar_theory_args.pyneeds neither torch nor pyxlog, and the other two run under exactly this job's CPU-torch +PYTHONPATHenvironment — my local run of all three: 145 passed / 4 skipped, CPU only. Adding three paths to the pytest invocation closes this fully.
New defects from the fix round
- MEDIUM
ci.yml(caviar-examples job) — the build(deps): bump actions/setup-python from 5 to 6 #10 PARTIAL above: the three excluded CPU-runnable suites mean the Expose device-native Python membership/credit APIs (DLPack instead of host Vec<bool>) #6/build(deps): bump actions/download-artifact from 4 to 8 #11/build(deps): bump actions/cache from 4 to 5 #12 regression tests never run in CI; the "GPU-only" justification doesn't hold for them. - LOW
python/tests/test_audit_dump_vs_xml.py:14— ironic inversion: after Eliminate remaining semantic-loop DTOH metadata fallbacks and codify Python GPU-native contract #7 made the tool torch-free, the module-levelimportorskip("torch")now over-gates 11 of the 12 tests; on a torch-less environment every new build(deps): bump release-plz/action from 0.5.50 to 0.5.128 in the github-actions-minor-and-patch group #9/build(deps): bump actions/checkout from 4 to 6 #13 protection silently skips. Only the pipeline-equivalence pin genuinely needs torch — move the gate into that one test. - LOW
run_caviar_cv.py(--close-threshold) — no value validation:nan,0, and-5parse (verified live); NaN makes everydist < thresholdfalse andjson.dumpsemits a literalNaNtoken, producing a non-RFC-8259 artifact. The same commit refuses the flag on the dump path — apply the same fail-closed instinct to the value. - LOW
ci.yml(torch install) — unpinned, uncachedpip install torch: a new torch release can redden CI for unrelated PRs, and every run re-downloads ~190MB. Pin (or bound) the version and use the pip cache, matching the workflow's own SHA-pinning conventions.
Residual notes (no action forced)
The #2 paragraph's "(verified for e10 and both e9 permutation-null variants)" superset-replay attestation is author-attested; nothing in the bytes contradicts it and my earlier cross-platform replays cover the value-level half, but the superset replay itself wasn't independently re-executed this round. #11's new test asserts bare SystemExit without matching the refusal text (consistent with sibling tests). #9 has no near-miss boundary case (one-frame-off event → unclaimed + splice_artifact) — low risk given exact-key claiming.
Bottom line: an excellent round — one push remains. Add the three suites to the CI job (and ideally the torch gate + value-validation LOWs in the same commit), and from my side PR #199 is complete.
The guide was written while #199 was in flight and excluded its contents. Now that it has merged, three things needed correcting. The moving fluent's canonical measurement changed. The reference direct- protocol result now comes from the close_34 artifact — F1 0.4450 over 1197/1047/1939 — not the threshold-25 run, which #199 preserved separately as history. The page cites the canonical file and says the older number exists and why. The clean-corpus clause claim was too strong: nine of ten folds select the both_walking rule, not all ten. Fold 6 abstains at a margin of 0.0093. The gate comparison the page drew has been retracted by the evidence package itself. Comparing the dump corpus against the deduplicated one charged a vocabulary-pool effect to deduplication; like for like, the gate minima are identical and the maximum differs by 14%. What actually collapses under leak-free folds is the holdout score, not the gate. The page now says that instead. --transition-vocab is documented with its scope, including that the guard fires only on `activity` while `full` is accepted everywhere, and the EC command now passes `activity` so the numbers the page quotes are the ones the command reproduces. The cv runner's flag list was missing --close-threshold and --transition-vocab; both are covered, with the per-fluent threshold defaults. The duplication caveat is now counted rather than described: 25 events resolve to 21 real, 3 duplicate and 1 splice, over 855 duplicated gold pair-frames. The two tools #199 shipped are cited where their numbers appear.
* docs: correct the paradigm list and gloss research jargon on the entry pages docs/index.mdx named SAT/MaxSAT verification as the fourth reasoning paradigm and omitted epistemic reasoning, contradicting core-concepts/how-xlog-works.mdx and README.md. SAT/MaxSAT is a shared solver service available to all four paradigms, not one of them. FAEEL, Gelfond-1991, WFS and decision-DNNF appeared raw on the landing page, in Core Concepts and in the README. DOCS-PROTOCOL cites these exact terms in its own R5 example. They are now glossed in plain language, and the epistemic semantics are named by the pragma values a reader actually types (faeel, g91) rather than by their research labels. core-concepts/how-xlog-works.mdx replaces a sentence stacking four unexplained concepts with a program-shape table, one row per evaluation route. core-concepts/gpu-residency.mdx documents the strict deterministic-D2H gate that enforces the zero-host-transfer contract the page explains, instead of only showing how to observe it after the fact. * docs: publish only benchmark numbers a committed artifact backs benchmarking.mdx claimed "the only benchmark numbers in this repository backed by a committed, source-verified run" and then published figures no artifact supports. The two WCOJ rows now state that XLOG publishes no speedup for them and give the exact command and Criterion cells to measure locally; the harness and the comparison they describe are real, only the numbers were unbacked. The neural-symbolic section conflated two different committed runs. The cache ablation is 512 images, 3 epochs, 3 seeds; the per-epoch profile is a separate 5-epoch, 2-seed run. Splitting them exposed figures that were wrong by more than rounding: steady_epoch_sec_mean was published as ~0.25 s against a recorded 2.90 s, and per_query_ms as ~1.0 ms against 74.0 ms. Both now come from named artifacts, and per_query_ms is labelled as the amortized figure it is rather than the cost of one forward pass. The page also now explains that 2.74x is the mean of the per-seed ratios, not the ratio of the means. arithmetic-and-functions.mdx stated integer division by zero always yields INT64_MAX. The sentinel is the operand type's own maximum (arith.cu:60,87, 112,137). The page now gives all four values and documents %-by-zero, which it omitted entirely. diagnostics.mdx gains the missing E0403, the non_exhaustive stats note for Rust embedders, and XLOG_FORCE_HOST_ROUNDTRIP, which was undocumented anywhere. interop.mdx gains JointConstraintCarrier.export_buffer and its two exceptions, which existed nowhere in the documentation. factorized-execution.mdx points readers at /guides/wcoj-tuning instead of leaving them on a page that disclaims being a user guide. * docs: bring the architecture pages and roadmaps up to v0.12.0 ROADMAP.md and architecture/roadmap.mdx recorded nothing from v0.11.0 or v0.12.0, and both described the relation-provenance rework as additive when it was breaking: put_relation_with_provenance now takes keyword-only roles= and facts=, and evidence()/relation() raise KeyError for the old sidecar payload. Both now say so and list what went away. The DP-optimizer checkbox at ROADMAP.md:77 was false against optimizer.rs:234 and is corrected. FAEEL, Gelfond-1991, WFS, EIR, decision-DNNF and weighted model counting appeared raw across ROADMAP.md, epistemic-internals and certification. DOCS-PROTOCOL cites several of these in its own R5 example. They are glossed at first use, in the same faeel/g91 pragma vocabulary the entry pages now use. architecture/wcoj.mdx told readers wanting to enable WCOJ to visit factorized-execution, a page that opens by disclaiming it is a user guide. It now points at /guides/wcoj-tuning and labels each link for what it is. dilp-training.mdx was never rewritten to protocol: it carried a retired-RFC pointer, a "Change 2 / route (A)" passage, and a 37-line spike-finding subsection addressed to its own authors. Those are gone, the reader-facing fact from the spike moved into Limits, the research vocabulary is glossed, and train_phi_gradient and the typed register_network parameters are documented. solver-services.mdx gains the Joint Constraint Carrier, absent from all of docs/. epistemic-internals.mdx gains the five epistemic boundaries added by the recursive rewrite in #195. gpu-execution.mdx gains the rule-union row. release-process.mdx drops a caveat that six shipped behaviours were source-tree only. The factorized-execution diagrams still read "FACTORIZED (main, unreleased)". Factorized execution has shipped; the label is now just "FACTORIZED", with no version baked into an image. * docs: complete the reference pages against the v0.11-v0.12 surface Eight breaking changes shipped between v0.10.0 and v0.12.0 and none was marked as breaking anywhere. rust.mdx had no breaking-change section at all and now documents ExecutionStats and StratumStats becoming non_exhaustive, with the two call-site edits that fixes. python.mdx labels the five relation APIs and the DLPack CUDA-only gate as breaking and dates them. cli.mdx was missing --wcoj, a flag DOCS-PROTOCOL's own worked example tells readers to type. It also now documents the xlog prob import merge and the W0510 ignored-pragma warning, and names the actual --stats counters in both their human and JSON forms. errors.mdx had a numbering hole at E0403 and collapsed every epistemic rejection into one row. All 17 distinct constructs are now listed, along with CarrierRefused, SolverResourceExhausted, the cross-predicate type mismatch in both its message forms, and the batched-concat row cap. environment-variables.mdx claimed to list every variable while five were missing. XLOG_FORCE_HOST_ROUNDTRIP joins the runtime settings, the bench and developer-tool variables get their own section, and the frontmatter no longer claims one exhaustive list. python.mdx gains JointConstraintCarrier, SOLVER_ABI_IDENTITY, the carrier exceptions, network_metadata, the typed register_network keyword arguments and train_phi_gradient, none of which appeared anywhere in the docs. language.mdx corrects the aggregate cap, which is 64 for count and 16 for the others, not 16 throughout. * docs(examples): describe the showcase examples that actually exist Two of the nested showcase READMEs documented subject matter absent from their own example sources. 04-supply-chain described a supplier, order and customer domain with a sample-output table. The example is warehouse, carrier and shipping: product, warehouse, stock, bom, carrier, direct_route. It also invented bom_explosion_recursive, where bom_exploded is itself the recursive rule, and showed low_stock_alert as 5-ary over a category and inventory join when it is 4-ary over stock and reorder_point. 03-game-analytics declared player/3 where the real predicate is player/4, described an items and rarity-tier domain that does not exist along with two queries over it, and showed a fabricated guild_power rule in place of the real guild_power_ranking/4. Both now list the queries main.xlog actually issues. The unverifiable sample-output tables are gone rather than replaced with invented numbers; an unbacked output table is what produced this drift. 01-enterprise was accurate apart from its user-defined-function block, which omitted the cast() calls the language requires on integer literals and so would not compile as printed. Fact counts are recomputed from the fixtures. Where a source module's own header comment disagrees with its facts, the counted value is used: guild_member has 39 entries, not the 40 its comment claims. * docs: make the neural, probabilistic and epistemic examples runnable Three documented examples could not run as printed. neural/rule-learning.mdx called program.query() twice and built its entire "How you know it worked" section on the result. No such method exists on CompiledProgram, in the stub or in the Rust bindings. The confirmation step now uses nll_loss, which is both real and the quantity train_epoch minimizes, so the check matches what training actually optimizes. neural/exact-induction.mdx printed cand.left_rel_idx and right_rel_idx. ScoredCandidate carries left_relation and right_relation — names, not indices — so the example raised AttributeError. The example also began from four undefined names and is now self-contained, following the shape of the shipped external-consumer example, and its illustrative output is derived from the data the page actually shows. probabilistic/engines.mdx told readers to evaluate a probabilistic program with xlog run, which routes to the deterministic executor. Probabilistic evaluation is reachable only through xlog prob. epistemic/overview.mdx claimed the complete list of unsupported constructs was in the language reference, which lists eleven forms against seventeen real rejections. It now points at the Epistemic rejections table in the errors reference, and documents the rejection a reader meets first — a second clause for an epistemic head — which appeared nowhere. The splitting section no longer claims coupled rules are always solved jointly, since the cross-component path fails closed, and MAX_MODELS_PER_REDUCTION is named correctly as a configurable default rather than a hard cap. * docs: document Event-Calculus rule induction, and unshadow dilp-training The Event-Calculus induction track shipped across #162, #174 and #178 with no user-facing page anywhere: kfold_select, frozen_select, the witness-level mask and abstain channel, engine-mode training with its holdout arbiter, the typed neural registry, and the permutation-null fit gate were reachable only by reading source. That is R6 and R8 under the documentation protocol, and this page closes both. The page leads with what the feature does for a reader — learn rules for when a situation starts and stops, while a neural detector learns to read the raw input through the logic credit alone, never shown a label for what it detects. Every command was validated against its argument parser, including the parse-time flag scoping that rejects --max-body-literals 3 outside --mode relational --protocol ec and --ec-fit-mode permutation-null without --holdout-score f1. Every number is read from a committed results/**.json. Abstention is documented as a designed outcome rather than a failure, and it appears in the lead rather than the footnotes: on the leakage-free protocol the meeting search abstains, and the page says so before it reports any score. The 10-fold neural detector result is reported as the negative result it is. The claims table states plainly that no ranking against OLED or WOLED-ASP follows from this work, with the three reasons why, because the 0.7782 comes from a corpus a frame-level audit found to contain duplicated videos. examples/caviar_woled/ was the only example directory without a README and now has one. docs.json also drops the /architecture/dilp-training redirect. It shadowed a 28 KB page that the navigation listed at the same time, making it unreachable while both mint validate and mint broken-links passed. The page holds Rust and CUDA entry-point tables and measured saturation data that exist nowhere else; its only inbound link already pointed past it. * docs: name the real epistemic model-limit constant Two architecture pages cited MAX_MODELS_PER_REDUCTION = 1024 as a fixed per-reduction cap. No such constant exists. The source defines DEFAULT_EPISTEMIC_MAX_MODELS_PER_REDUCTION (xlog-gpu/src/logic.rs:2331) and assigns it to max_models_per_reduction, a configurable field the epistemic evidence CLI exposes and the integration tests set to other values. The same error was corrected on epistemic/overview.mdx earlier in this branch; these two pages carried it in a different batch and so were not caught by that review. All three now agree. * docs: align the Event-Calculus guide with the merged #199 evidence The guide was written while #199 was in flight and excluded its contents. Now that it has merged, three things needed correcting. The moving fluent's canonical measurement changed. The reference direct- protocol result now comes from the close_34 artifact — F1 0.4450 over 1197/1047/1939 — not the threshold-25 run, which #199 preserved separately as history. The page cites the canonical file and says the older number exists and why. The clean-corpus clause claim was too strong: nine of ten folds select the both_walking rule, not all ten. Fold 6 abstains at a margin of 0.0093. The gate comparison the page drew has been retracted by the evidence package itself. Comparing the dump corpus against the deduplicated one charged a vocabulary-pool effect to deduplication; like for like, the gate minima are identical and the maximum differs by 14%. What actually collapses under leak-free folds is the holdout score, not the gate. The page now says that instead. --transition-vocab is documented with its scope, including that the guard fires only on `activity` while `full` is accepted everywhere, and the EC command now passes `activity` so the numbers the page quotes are the ones the command reproduces. The cv runner's flag list was missing --close-threshold and --transition-vocab; both are covered, with the per-fluent threshold defaults. The duplication caveat is now counted rather than described: 25 events resolve to 21 real, 3 duplicate and 1 splice, over 855 duplicated gold pair-frames. The two tools #199 shipped are cited where their numbers appear. * docs: restore the training timings; the artifacts were stale, not the page An earlier commit on this branch replaced this page's neural-symbolic timing figures with values from the track_a v0.4.0-alpha artifacts and asserted the published numbers were understated. Both halves were wrong. Those artifacts record branch "v0.4.0-alpha-integrated", February 2026, while the code is v0.12.0 — every committed neural benchmark in the repository comes from that one February campaign. And the comparison mixed two quantities: the runner's per_query_ms is total time over queries times epochs, which amortizes the cold compile epoch, whereas the published ~1.0 ms is the steady-state cost of a 0.25 s epoch over 256 pairs. The artifact's own arithmetic pins the query count at 256, so the two figures differ by exactly the amortization, not by an error. Re-measured on current code, same protocol, two seeds: mean steady-state epoch 0.2675 s against the published 0.25 s, with the February artifact's 2.91 s an order of magnitude away. The page's numbers describe the current pipeline. Three things from the erroneous commit are kept because they were real defects: the cache ablation and the timing run are no longer merged into one description, the 2.74x is explained as the mean of per-seed ratios rather than the ratio of means, and the per-query figure is labelled steady-state, which is the ambiguity that caused the error. The WCOJ rows are untouched; their figures stay withdrawn pending a re-measurement. * docs: restore the WCOJ speedups; the artifacts are pending, not absent Both WCOJ rows were stripped earlier on this branch because no committed artifact backed them. That reasoning was overturned by the neural timing case: the repository's committed artifacts are a February v0.4.0-alpha campaign, and a re-measurement on current code confirmed the published figure rather than the stale artifact. This project loses artifacts; the numbers survive. The artifacts for these two will be added from the machine that produced them. So `10.5x` to `33.8x` for the super-hub triangle fixtures and `6.05x` / `5.37x` for aggregate-fused WCOJ are back, keeping the reproduce instructions that were added when they were removed: the harness invocation, the Criterion cell ratio, the CUDA-device requirement, and the kill-switch A/B for the fusion route, which has no bench target of its own. Three sentences that the restoration falsified are corrected with it. The page defined "measured" as backed by a committed run, which would have read the restored rows out of their own category; it now means a real run whose harness or procedure the page names. The aspirational-targets warning distinguished itself by having no committed run, which no longer separates it from anything; the real difference is that no run backs those at all. And the methodology section regained its tie to the published range. The note about quoting WCOJ speedups is rewritten rather than dropped. It no longer casts doubt on the figures; it says what stays true, that the speedup moves with GPU, fixture size and key width, so a deployment should cite its own measurement. * docs: write for the reader, not about our workflow Several pages carried sentences a reader can do nothing with. The benchmarking page promised that artifacts would arrive from the machine that produced them, which tells them about our logistics and not about the numbers. It now says which row's data they can open and recompute, and that the other two are checked by measuring them, which the reproduce column already explains how to do. The roadmap page carried a "Near-Term Documentation Priorities" list whose bullets were chores we owe ourselves, one of them literally instructing us to replace internal milestone prose with product documentation. A product roadmap should say where the engine is going. Each bullet was checked for a reader fact worth keeping and none held one; the diagram bullet's actual content is already stated as fact in the architecture commitments above it. The architecture overview listed the docs deployment among engine contracts, next to the CUDA release gate. Where the site is hosted is not engine architecture, and the release-process page documents the deployment in more detail than the overview line did. Four more sites named our process rather than the software: a limitation described as unfixed "on this branch", a rejection that would stand "until an aggregate-backed collection path lands" and its twin reserving the same thing "for a later path", our work-item vocabulary and doc-contract bookkeeping sitting inside the pragma reference, a capability attributed to the workstream that produced it, and a test cited by its former pytest marker. Each is now the fact without the provenance. The Event-Calculus page keeps its availability statement, which is actionable, but states it as not being in a tagged release rather than by naming the branch. * docs: apply the PR review findings Fifteen findings from review, verified against source before each fix. The worst was a new example in the exact class this branch exists to remove: python.mdx called export_buffer("label_map"), which raises ValueError. The valid name is map_results, which this branch's own interop page already lists. Release-state claims are reworded rather than hedged. v0.12.0 is merged but not yet published, so "in tagged artifacts from 0.12.0 onward" and "in packaged builds from 0.12.0 onward" assert something that does not exist yet. They now state version membership — "available since 0.12.0", the phrasing the neighbouring heading already used — which is what a reader needs and which has no window in which it is false. Claims about 0.10.0 are untouched; that version is published. The rust reference's breaking-change list promised completeness it did not have: two epistemic functions changed return type to Result in #195 and ChoiceSource.choices went from Vec to Arc in #180, all three publicly reachable and none listed. Corrections to the Event-Calculus page: a quoted JSON block carried e10's values under an e9 attribution; the corpus audit is four videos and 876 duplicated frames, not two and 855; the activity vocabulary claim covered runs that used the full pool; and the pre-registered 0.7329 now appears as a number rather than only by reference. Smaller fixes: grad_true needs return_grads=True; the unknown-key rejection breaks the debug entry point too; the CLI decline count is interpolated, not always zero; the CAVIAR environment rows were wrong on base directory and gating. The RTX 3090 corroboration sentence is removed. It cited no committed evidence on a page whose opening paragraph sorts rows by whether their data can be inspected.
grep -rn -i maritime .github/workflows/ returned nothing: neither test_maritime_convert.py nor test_maritime_cv.py was run by any of the 8 workflows, because every pytest invocation in CI is an explicit file list (deep-review finding #2, HIGH — the same gap the #199 remediation closed for the CAVIAR suites, repeated one PR later). Extend the existing caviar-examples file list rather than adding a separate maritime-examples job: the maritime suites need exactly the environment that job already builds (pytest, CPU torch so the torch-gated run_fold test runs for real, PYTHONPATH=crates/pyxlog/python for the pure-Python pyxlog used by relational_search), and every other job in ci.yml is one job per toolchain concern, not per example corpus — duplicating checkout/setup/install for a second pytest list would be the inconsistent choice. Both suites are synthetic-fixture-only, CPU clean (local run: 24 passed).
Closes the remaining findings of #178's deep review. #178 was merged with the 16 mechanical fixes (phase 1); this PR lands the reproducibility trio (the three HIGH findings) and the missing evidence artifacts. 9 commits, cherry-picked onto current main; single author; no scope beyond the review.
Reproducibility (the HIGH trio)
--transition-vocab activity|fullon both EC runners; the defaultfullis byte-identical to previous behavior,activityis the pool the shipped e9/e10 rows actually ran. The actual vocabulary is now recorded in every result JSON (the CV runner previously recorded none).e10 @ activityreproduces micro EC F1 0.7329 (tp 1516 / fp 788 / fn 317) with zero per-fold discrepancies — fold assignment, clauses, gates, counts, scoring all equal the shipped JSON;e9(both tie variants) reproduces frame F1 0.9424 with every field equal. Replay evidence is referenced in the README next to the repro block.Corrected attribution and shipped artifacts
results/e9_f1_holdout/): top 0.2381, margin 0.1381 — the figures the prose cited now have a JSON behind them.audit_dump_vs_xml.py+results/f_audit/— exactly 21 real / 3 duplicate / 1 splice-artifact transitions, 0 unclaimed XML events, wk2gt = 855; six synthetic tests pin the classifier.xml_meeting_census.py+ JSON — clause applied directly to the wk test fold: F1 0.8896, tp 1060 (232+828), fp 0, fn 263; train-side coverage 0/489.Canonical
close_34for movingPer-fluent canonical thresholds (meeting 25 / moving 34, per the canonical CAVIAR RTEC definitions) replace the single fluent-independent 25px threshold; an explicit value still wins, which keeps the historical threshold-25 measurement reproducible (its JSON is preserved under a
threshold25suffix, andclose_thresholdis now recorded in the result JSON).Measured honestly: moving @ close_34 = 0.4450 micro (P 0.5334 / R 0.3817) — lower than 0.4868 @ threshold-25: the fomd+mc1 fold (1546 gold frames) abstains on a tie (0.0093 < 0.01) where threshold-25 committed a clause. That is a finding, not a regression to hide; the README discloses the mechanism next to the number.
Wording
E.1's vocabulary is now labeled "a second iteration informed by step-1 error analysis on the same folds" (not "pre-registered"), and section H's contrast reads "one disclosed adaptive step vs an unreported number of tuning trials". No numbers changed.
Out of scope (declared follow-ups)
Environment conftest guard and the GPU regeneration of e12 (the only GPU-dependent item).
Tests: 322 passed across the 11 affected suites; the 4 failures are the pre-existing local-environment baseline (missing sympy), identical before and after.