Skip to content

fix(examples): CAVIAR deep-review follow-ups — vocabulary reproducibility, shipped audit artifacts, canonical close_34 - #199

Merged
niveousdragon merged 24 commits into
mainfrom
feat/caviar-review-followup
Aug 7, 2026
Merged

fix(examples): CAVIAR deep-review follow-ups — vocabulary reproducibility, shipped audit artifacts, canonical close_34#199
niveousdragon merged 24 commits into
mainfrom
feat/caviar-review-followup

Conversation

@niveousdragon

Copy link
Copy Markdown
Contributor

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|full on both EC runners; the default full is byte-identical to previous behavior, activity is 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).
  • Per-section repro commands in the README, each naming its vocabulary explicitly (E.1 gained its own command; D.1 item 1 had none before).
  • Replay proof, bit-for-bit: e10 @ activity reproduces 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

  • Section G gate paragraph rewritten: the old text compared gates across different vocabularies; like-for-like (e11 vs XML: minima identical at 0.050, maximum +14.3%) does not support the deduplication attribution. The abstention cause is the holdout-F1 collapse, as the section's own later analysis states.
  • D.1 item 1 artifact shipped (results/e9_f1_holdout/): top 0.2381, margin 0.1381 — the figures the prose cited now have a JSON behind them.
  • Section F audit shipped as a tool: 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.
  • Section G census shipped as a tool: 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_34 for moving

Per-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 threshold25 suffix, and close_threshold is 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.

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 levi770 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Comment thread docs/experiments/caviar/README.md Outdated
**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

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[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.

Comment thread docs/experiments/caviar/README.md Outdated
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` +

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[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.

Comment thread docs/experiments/caviar/README.md Outdated
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

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[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

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[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.

Comment thread docs/experiments/caviar/README.md Outdated

# 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).

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[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"):

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[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

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[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"]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[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`

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[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.

Comment thread docs/experiments/caviar/README.md Outdated
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,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[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.
@niveousdragon

Copy link
Copy Markdown
Contributor Author

@levi770 — all 15 findings closed in 88314ada..8e18f464 (15 commits, one per finding; same discipline as before). Map:

# Finding Commit
1 "8 of 10" → 9 of 10 per the shipped artifact 2a673bc8
2 vocabulary-recording claim scoped to current runners 811a90f6
3 README states which Section-G artifacts carry close_threshold 5341ccea
4 Section-G replay attestation scoped to the runs it covered 9f129692
5 e5 EC artifacts labeled historical, not runner-reproducible 80b3a232
6 neural-mode fold record now records the actual init pool (incl. close_nn) 512764bb
7 audit tool runnable without torch (lazy imports; red-proven via a meta_path torch blocker) 5d578c72
8 census artifact records close_threshold (artifact regenerated, additive fields only) 7f5b467b
9 miss-detector proven to FIRE: an orphaned ground-truth meeting is named (video/pair/frame/kind), not silently absent 904601c3
10 CI: a caviar-examples job installs CPU torch and runs the theory-loop / XML-corpus / audit / census suites for real (dataset-gated tests self-skip) 8e18f464
11 --transition-vocab activity in neural EC mode now refuses typed instead of recording a false provenance distinction 31c498f1
12 --close-threshold added as the threshold-25 replay entry point (default None = canonical per-fluent, byte-identical) 90e70578
13 audit robustness: non-40ms/nonzero-offset time bases and off-grid event timestamps refuse loudly; main() opts into the loader's verified real-file counts; two equivalence pins (audit walk vs derive_ec_targets_continuous, census cover vs relational_search.body_cover) stop silent drift 839dddf7
14 Hardware table extended for the new artifacts + repro commands for both tools' shipped JSONs e2cf4d55
15 residual "stricter gates" framing dropped 46ef36f3

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
@levi770

levi770 commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Fix-round verification — 88314ada..8e18f464 (15 commits)

Method as before: every claimed closure re-derived from the bytes at the new head by an adversarial verification pass, majors re-verified by my own execution. 14 of 15 findings verified CLOSED; #10 is PARTIAL. Four small new defects found in the round itself (1 MEDIUM + 3 LOW, below).

Independent execution evidence (all reproduced on my machine)

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

New defects from the fix round

  1. 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.
  2. 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-level importorskip("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.
  3. LOW run_caviar_cv.py (--close-threshold) — no value validation: nan, 0, and -5 parse (verified live); NaN makes every dist < threshold false and json.dumps emits a literal NaN token, 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.
  4. LOW ci.yml (torch install) — unpinned, uncached pip 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.

@niveousdragon
niveousdragon merged commit a9c2ed1 into main Aug 7, 2026
18 checks passed
@niveousdragon
niveousdragon deleted the feat/caviar-review-followup branch August 7, 2026 15:19
niveousdragon added a commit that referenced this pull request Aug 10, 2026
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.
niveousdragon added a commit that referenced this pull request Aug 10, 2026
* 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.
niveousdragon added a commit that referenced this pull request Aug 11, 2026
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).
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.

2 participants