Skip to content

docs(plans): verifier-independence plan - #590

Merged
r-uben merged 5 commits into
mainfrom
feat/verifier-independence-plan
Sep 4, 2026
Merged

docs(plans): verifier-independence plan#590
r-uben merged 5 commits into
mainfrom
feat/verifier-independence-plan

Conversation

@r-uben

@r-uben r-uben commented Sep 4, 2026

Copy link
Copy Markdown
Owner

Summary

Ticket graph for making the free native lane a sound witness of the model lane. Drafted from a Claude ↔ Codex conversation, attacked by a three-seat panel (Codex fidelity, agy coverage, grok gating) — 24 findings verified against the tree and folded in; Codex approved the revision.

Baseline: run 2 (docs/log/2026-09-04_ladder-corpus-rerun.md) — 7 adjudicated tables, 1 lifted / 6 held, 3 blocked by native row labels.

Test plan

  • Docs only; uvx ruff@0.16.0 format --check . clean.
  • Wave 1 (A1 ∥ B1) is dispatchable on merge.

Summary by cubic

Adds a docs-only, nine-ticket, six-wave plan for making the free native lane a sound witness of the model lane: stream A repairs the native row-label reference in binding.py, stream B instruments per-stage exclusive wall-clock, and stream C moves the disproof crop to geometry-derived cell addresses with an abstain rule.

  • Baseline is the frozen run-2 corpus: 7 adjudicated tables, 1 lifted / 6 held, 3 blocked by native row-label defects; the 8.0 min/page latency is confounded by a mid-run venv repoint spanning three digest values.
  • A1's gate compares a fresh bind() against the frozen sidecar as a multiset with duplicate counts; A1b censuses all 12 class-(c) items and freezes its classifications as A2's native-side-only denominator.
  • B2 and C3 run from a pinned checkout with explicit PYTHONPATH; B2 asserts every sidecar's socr_source_digest equals the intended digest via the resolved package path before tabulating.
  • C2b's frozen-replay gate records a per-item prediction as a separately committed artifact before implementation and fails if every item abstains.
  • doc05/doc07 class-(c) labels are parked out of scope; docs-only, ruff format clean; wave 1 (A1 ∥ B1) can dispatch on merge.

Written for commit ff799b5. Summary will update on new commits.

Review in cubic


Note

Low Risk
Documentation-only; no production code, sidecar schema, or CI behavior changes until follow-up tickets land.

Overview
Adds docs/plans/verifier-independence/ with a nine-ticket, six-wave execution plan (no runtime or test changes in this PR).

STATUS.md records plan stage, frozen run-2 baseline (7 adjudicated tables, 1 lifted / 6 held), a ticket board with dependencies, parallel dispatch waves, and next steps (open PR, then wave 1: A1 ∥ B1).

TICKETS.md is the full spec: goal and panel-verified repo facts (e.g. row repair targets binding.py, not native_rows.py; no row_bands_from_rules yet), then per-ticket problem / files / done-when criteria across three streams — A frozen replay-binding + autopsy + binder row-label fixes, B exclusive per-stage timings_s and a corpus breakdown log, C geometry-based cell correspondence, abstain semantics, and a ladder re-run reported (not gated) vs A2’s frozen-replay gate. Parked work and panel disagreement on C3 gating are documented explicitly.

Reviewed by Cursor Bugbot for commit 63c4e71. Bugbot is set up for automated code reviews on this repo. Configure here.

…agy/grok panel

Nine tickets, six waves: A (replay harness, autopsy, binder row-label repair
#331/#418/#146), B (per-stage exclusive timings, breakdown run), C (design and
implementation of geometry-addressed cell correspondence with an abstain rule,
corpus re-run). Frozen evidence: ~/Data/socr/ladder-run2-2026-09-04 (run 2 at
main@f434019, 1 lifted / 6 held, 3 native-label-blocked). #155 parked.
@qodo-code-review

Copy link
Copy Markdown

ⓘ Qodo reviews are paused because your trial has ended. Ask your workspace admin to add credits to resume reviews. Manage billing

@coderabbitai

coderabbitai Bot commented Sep 4, 2026

Copy link
Copy Markdown

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Team

Run ID: 4a137891-c0f3-44b0-811f-be0ae4a00601


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@r-uben r-uben left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Verdict: MERGE

Docs-only plan. Spot-checked the cited seams on current main (92c1527): binder owns its own rows (binding.py:70-71, _native_rows:559, _assign_bands:332, _row_label_and_bbox:322, bind:1276 — not native_rows.py); _disprove_one really self-witnesses via item.native_bbox (adjudication.py:260-268); bands_from_rules:122 / _horizontal_rules:169 match; orchestrator clamp/lift/held call sites (:5223 / :5245 / :5292) and _adjudicate_clamped_table / _render_adjudication_crop / _apply_binding_adjudication_meta land where claimed. Target label count matches the run-2 log (doc02 p3×3 + doc02 p4×4 + doc04 p3×1 = 8).

Gates are the right shape for this repo: A2 hard-gates on frozen replay (3/3 false clamps cleared + control fixtures against false accepts), not on lifted and not on a live ACCEPTED quota; C3 is a report; abstain never falls back to either lane's box; B1 keeps timings out of fingerprint / fragment markdown and restores on resume; hermetic patches + pin-a-difference called out; Wave 1 file split (A1 import-only of _render_adjudication_crop, B1 owns orchestrator) is real.

Panel call on C3 (Codex over agy's ≥10/18 quota) is correct — live OCR is not a deterministic gate.

Non-blocking — fix before Wave 1 / Wave 3 dispatch, not merge-blocking:

  1. STATUS base SHA is stale. Board says main @ b7323f7 (#587); this PR's base and current main are 92c1527 (#588, digest-correction log). Refresh the base-state line so /plan next does not start from a dead tip.
  2. A2 label gate formula. Done-when says both "fix only A1b's native-side classes" and "8/8 unresolved target labels reconstructed". If A1b reclassifies any of the 8 off shredded_label/bbox_truncated, pin explicitly: reconstruct gate = native-side subset only; absent_text / other logged on their own line and out of that denominator (the "never subtracted" line is easy to read the wrong way under pressure).
  3. B2 vs the 8.0 min/page figure. Run-2's own log records the venv-pointer confound (three digests). B2 should state it establishes a fresh timed baseline under one digest + B1, not that it explains the confounded 8.0.
  4. STATUS "Next action" still says commit/open the PR — already done. Point it at Wave 1 dispatch.

Bot noise on the PR (Qodo paused, CodeRabbit trigger) ignored.

No code. No merge from the desk.

@r-uben

r-uben commented Sep 4, 2026

Copy link
Copy Markdown
Owner Author

Revise panel (gitty demand)

Rubén wants another revise pass on this plan. Please attack fidelity (does the plan match the tree?), coverage (are the real holes ticketed?), gating (are done-when checks pinable / non-vacuous?), and dispatchability (is wave 1 = A1 ∥ B1 still the right first cut?).

Known soft notes from desk MERGE on 63c4e71 (verify or kill):

  1. STATUS.md base SHA / next-action look stale vs current main (92c1527).
  2. A2’s 8/8 pin vs A1b class-demotion formula — if A1b reclassifies, A2’s gate may need an explicit demotion rule.
  3. B2 should be a fresh instrumented baseline, not the confounded 8.0 min/page run-2 number.

Streams: A (binding.py row labels / replay harness / autopsy), B (per-stage wall-clock), C (geometry cell correspondence + abstain; C3 report-not-quota). Parked: #155, #585, latency opt, booktabs.

@claude — coverage + gating; walk the ticket graph against binding.py / disproof / sidecar timing seams.
@codex review — fidelity + dispatchability; reject vacuous done-when and wrong-file targets.
bugbot run — Cursor: unpinned gates, silent loss, SUCCESS-restamp risks in the plan’s claims about the tree.
/gemini review — same axes if the Cloud Assist path is live; otherwise stay silent.

I’ll fold verified findings into the plan and push a revision. Do not merge.

@r-uben

r-uben commented Sep 4, 2026

Copy link
Copy Markdown
Owner Author

@claude Please revise this verifier-independence plan for coverage and gating. Walk A1/A1b/A2/B1/B2/C* against the tree (binding.py, adjudication, locate, orchestrator seams). Reject vacuous done-when. Is wave 1 (A1 ∥ B1) still the right first dispatch?

@r-uben

r-uben commented Sep 4, 2026

Copy link
Copy Markdown
Owner Author

bugbot run

@r-uben

r-uben commented Sep 4, 2026

Copy link
Copy Markdown
Owner Author

@codex review

Revise pass on this docs-only plan. Axes: fidelity to the tree, dispatchability of wave 1 (A1 ∥ B1), and whether A2/C3 gates are non-vacuous. Soft notes to verify: STATUS base SHA vs main, A2 8/8 vs A1b demotion, B2 as fresh baseline not confounded run-2 minutes.

@claude

claude Bot commented Sep 4, 2026

Copy link
Copy Markdown

Claude finished @r-uben's task in 5m 57s —— View job


Revise panel — coverage + gating pass (claude seat)

  • Confirm base SHA drift claim
  • Read STATUS.md / TICKETS.md in full
  • Verify soft notes 1–3 from the desk MERGE review on 63c4e71
  • Walk stream A against binding.py, stream B against sidecar/manifest/CLI seams, stream C against locate.py/adjudication.py
  • Coverage / gating / dispatchability check
  • Post findings

Spot-checked every cited symbol and line range against current main (92c1527) — all of binding.py:322/332/559/1276, adjudication.py:227/260, locate.py:122/169, orchestrator :5223/5245/5256/5522/5542/5577/5639/9112, _run_fingerprint/_flush_page_sidecar/_restore_terminal_page_state/_rewrite_all_fragments, pyproject.toml:67-69, tests/ flatness, and the test_gh367_adjudication_lift.py hermeticity trio hold exactly, including the subtle overlap where _apply_binding_adjudication_meta's call site at :9112 sits inside _restore_terminal_page_state's own cited range. Wave 1 (A1B1) file lists are genuinely disjoint (A1 only imports _render_adjudication_crop, never edits orchestrator.py).

Confirming the desk's three soft notes — all still open:

  1. STATUS base drift, confirmed and worse than a stale SHA. STATUS.md:17 says main @ b7323f7; current main is 92c1527 (docs(log): re-run correction, run 2 spanned three source digests #588, "digest correction"). I pulled that diff (git diff b7323f7 92c1527 -- docs/log/2026-09-04_ladder-corpus-rerun.md): it adds a "Correction (evening): run 2 did not run on one source tree" section — socr_source_digest shows run 2 actually spanned three different trees (doc00–04 on f434019, doc05/doc07 on a second, doc08 on a third), because a concurrent bug(tables): non-outage UNVERIFIED terminals print "infra problem, retryable on resume" and drop the guard-chain cause #581 worktree repointed the shared venv mid-run. STATUS.md's "Measured baseline (run 2, main@f434019)" line still reads as one clean tree. Good news: A2's three target tables (doc02 p3, doc02 p4, doc04 p3) all fall in the unaffected doc00–04 range, so Stream A's targets are sound — but B2 must disclaim the multi-digest confound explicitly, not just "OCR variance," and STATUS.md's base-state line needs the correction folded in. Next-action line also still says "commit the plan folder, open the PR" — done; point it at Wave 1 dispatch.
  2. A2 gate wording, confirmed ambiguous. TICKETS.md:117: "genuinely absent text is reported in the log as its own line, never subtracted from the gate." Read literally this means an absent_text crop still counts against 8/8 — which is unsatisfiable if the text is truly gone from the page. Needs the explicit split the desk named: reconstruct-gate = native-side classes only (shredded_label/bbox_truncated) as the denominator; absent_text/other logged on their own line, excluded from that denominator, not merely "not subtracted."
  3. B2 vs the confounded 8.0 — see L0C-01: Canonical EngineResult/PageOutput contract #1 above; same finding, sharper now that the multi-digest fact is on main in writing.

Two new coverage findings (not in the desk review):

  1. A2 cites bug(tables): native reconstruction loses row labels at scale — the stub column is dropped, and it poisons every drift comparison #331/bug(tables): a word beyond the snap radius from every lane is silently dropped from the grid #418/bug(tables): first data row is emitted as the table header, and the real header band is excluded #146 as if fixing them in binding.py, but they're already fixed elsewhere. rg confirms bug(tables): native reconstruction loses row labels at scale — the stub column is dropped, and it poisons every drift comparison #331 (stub-column retention) is fixed in reconstruct.py::rowize_from_word_list (tested by test_gh331_stub_labels.py, which imports socr.tables.reconstruct, not socr.tables.binding), bug(tables): a word beyond the snap radius from every lane is silently dropped from the grid #418 likewise in reconstruct.py, bug(tables): first data row is emitted as the table header, and the real header band is excluded #146 in header_repair.py/reconstruct.py (test_table_header_gh146.py imports header_repair/reconstruct, not binding). binding.py has its own independent rowizer (_assign_bands, _row_label_and_bbox, _native_rows) that never imports rowize_from_word_list and carries no reference to any of the three issues — confirmed by grep. So A2 isn't closing bug(tables): native reconstruction loses row labels at scale — the stub column is dropped, and it poisons every drift comparison #331/bug(tables): a word beyond the snap radius from every lane is silently dropped from the grid #418/bug(tables): first data row is emitted as the table header, and the real header band is excluded #146, it's fixing an independent recurrence of the same bug class in a sibling module that never got the fix. That's the right scope (binding.py is deliberately its own thing, per binding.py:70-71), but the ticket should say so explicitly and point the implementer at reconstruct.py's proven fix logic as design reference — otherwise there's a real risk of either re-deriving a fix from scratch or, worse, "fixing" it in reconstruct.py again by mistake.
  2. A2's "Files" list mixes must-edit with must-stay-green, and it's not labeled. tests/test_tr1_rowizer.py, tests/test_gh331_stub_labels.py, tests/test_table_header_gh146.py are listed under A2's Files:. All three only import reconstruct.py/header_repair.py — none imports socr.tables.binding (checked directly). Editing binding.py cannot be verified by tests that exercise a different module, so as currently written this list is misleading: an implementer told "Files: X, Y, Z" for a binding.py-only fix will either skip them as irrelevant or waste time trying to edit them. If the intent is "these are the sibling-module regression tests that must stay green as a scope guard" (plausible, given finding L0C-04: DocumentState blackboard #4), say that explicitly and separately from the edit list — the plan's own Wave-disjointness reasoning elsewhere depends on Files: meaning "edited," so overloading it here breaks that convention.

Not re-litigated: stream C's abstain rule, bands_from_rules/_horizontal_rules split, and ContradictionItem's actual construction path (adjudication.py::items_from_bindingbinding.py's ContradictedCell/RowLabelContradiction) all check out against C1/C2a/C2b's Do sections once traced — C2b's shorthand ("binding.py: ContradictionItem population only") is compressed but not wrong, since binding.py owns the upstream dataclasses that feed the conversion.

Verdict: coverage and gating both hold at the ticket-graph level; the two new findings (#4, #5) are non-blocking for Wave 1 (A1/B1 don't touch this) but should land before A2 is dispatched in Wave 3, alongside the desk's three open items. No code, no merge from this seat.

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 4, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-09-04T22:46:26.847730Z 63c4e71 Manual request
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@r-uben

r-uben commented Sep 4, 2026

Copy link
Copy Markdown
Owner Author

/gemini review

@claude

claude Bot commented Sep 4, 2026

Copy link
Copy Markdown

Claude finished @r-uben's task in 4m 10s —— View job


Revise pass — coverage + gating (@claude)

  • Read STATUS.md / TICKETS.md
  • Verify base-state SHA vs current main
  • Walk tree seams: binding.py, adjudication.py, locate.py, orchestrator call sites
  • Check each done-when (A1, A1b, A2, B1, B2, C1, C2a, C2b, C3) for vacuity / pinnability
  • Assess A2 gate vs A1b class-demotion (soft note L0C-02: Born-digital detection #2)
  • Assess B2 vs confounded 8.0 min/page figure (soft note L1B-02: Replace single fallback with fallback chain #3)
  • Judge wave 1 = A1 ∥ B1 dispatchability
  • Post findings

Verdict: no new blockers. All four of the desk's soft notes are still open (not yet folded in) and I confirm all four independently. One additional fidelity nit for C2b (wave 5, not merge-blocking).

Independent tree walk

Re-verified against origin/main (92c1527), not the panel's earlier snapshot — everything the plan cites still lands where claimed:

  • binding.py:70-71 docstring: "Deliberately does NOT use native_rows.py::LabeledRow.values" — confirmed. _native_rows, _assign_bands, _row_label_and_bbox, bind() all present and doing what's described.
  • adjudication.py:227 adjudicate / :260 _disprove_one self-witnesses via item.native_bbox — confirmed line-for-line.
  • locate.py:122 bands_from_rules / :169 _horizontal_rules — confirmed bands_from_rules only ever emits whole-table boxes ("Group horizontal rules... into table bands"); no row-band helper exists. C2a's premise holds.
  • Orchestrator seams (:5223 call site, :5245/:5292 interpret lifted/held, _adjudicate_clamped_table/_render_adjudication_crop/_apply_binding_adjudication_meta, _run_fingerprint incl. socr_source_digest:1251, _flush_page_sidecar, _load_terminal_page, _restore_terminal_page_state:8901, _rewrite_all_fragments:9238) — all present, line numbers within a handful of lines of citation (normal drift, not fabrication).
  • pyproject.toml:67-69 [project.scripts] and "tests/ is flat" — confirmed.
  • Cited test patterns are real and do what's claimed: test_gh367_adjudication_lift.py:177-180 shows the exact three-patch hermeticity idiom (_available_engines_for_agentic, _resolve_judge_model, _transcribe_cell_token); test_p6_disposition_persistence.py's difference-test (same/mutated sidecar → same _load_terminal_page verdict) is the right template for B1's resume-identity check.
  • None of the new test files (test_replay_binding.py, test_timings.py, test_locate_row_bands.py) exist yet — no collision risk for wave 1/4.

Soft notes from the desk — all confirmed still open

  1. STATUS base SHA stale. origin/main is 92c1527 (docs(log): re-run correction, run 2 spanned three source digests #588, digest-correction), not b7323f7. Confirmed via git rev-parse origin/main. Not fixed in this revision yet.
  2. A2's gate is unreachable as written if any of the 8 crops turn out absent_text. TICKETS.md's done-when demands "8/8 unresolved target labels reconstructed... genuinely absent text is reported... never subtracted from the gate." If A1b (which runs first and hasn't yet) classifies any crop as absent_text, no binding.py fix can ever reconstruct text that isn't on the page — so 8/8 becomes structurally impossible, not just hard. Concrete fix: split the denominator now, before A1b dispatches — N/N where N = A1b's count of shredded_label/bbox_truncated crops; absent_text/other/neighbour_capture logged on their own line, explicitly outside that denominator (matches the ticket's own "fix only the classes A1b found native-side" scope, just needs the done-when to say the same thing about the count).
  3. B2 vs the confounded 8.0 min/page number, with the receipt. Pulled the actual correction (docs/log/2026-09-04_ladder-corpus-rerun.md, "Correction (2026-09-04, evening)"): run 2's socr_source_digest shows three different source trees across the 20 pages (a venv-pointer got repointed at a bug(tables): non-outage UNVERIFIED terminals print "infra problem, retryable on resume" and drop the guard-chain cause #581 WIP worktree mid-run), so "wall clock... 8.0 min/page" is confounded by code changes, not just OCR variance — it is not a clean number to decompose. TICKETS.md's B2 problem statement ("Nobody knows whether the 8 min is the ladder...") still frames the ticket around explaining that figure, and STATUS.md's "Measured baseline" bullet states "8.0 min/page" flat, with no pointer to the caveat that lives only in the log. B2's Do:/Done when: text itself is fine (fresh run, no reproduction claim) — just tighten the problem statement and the STATUS baseline line so nobody chases a number the tree itself says is contaminated.
  4. STATUS "Next action" still says commit/open the PR (already done) instead of pointing at Wave 1 dispatch — same fix as L0C-01: Canonical EngineResult/PageOutput contract #1, one edit.

One new finding (wave 5, not merge-blocking)

C2b's file/target annotation for ContradictionItem is imprecise, the same class of error the panel already caught once for A2 (native_rows.pybinding.py). ContradictionItem is defined and constructed in adjudication.py (_item_from_cell, _item_from_row_label, items_from_binding, lines ~70-181) — binding.py never references the name ContradictionItem at all (confirmed via grep). What binding.py actually owns are ContradictedCell (:1002) and RowLabelContradiction (:1011), each already carrying native_bbox; those are the objects that would need to grow the new geometry field for adjudication.py's converters to copy it across. TICKETS.md currently lists "src/socr/tables/binding.py (ContradictionItem population only)" as a C2b file — a wave-5 implementer taking that literally will grep binding.py for a class that isn't there. Suggest: src/socr/tables/binding.py (ContradictedCell / RowLabelContradiction gain the geometry field only)`.

Wave 1 dispatchability: still correct

A1 (benchmark/replay_binding.py new + pyproject.toml [project.scripts] + new test, read-only import of orchestrator._render_adjudication_crop) and B1 (orchestrator.py_phase_agentic/_flush_page_sidecar/_restore_terminal_page_state, state.py, manifest.py, cli.py) touch disjoint files; A1 never edits orchestrator.py, only imports from it, so there's no real collision even though both graze the same module. Verified PageState (core/state.py) has no timings_s field yet and no naming collision with what B1 adds. A1 ∥ B1 is still the right first cut.

No code changes made — this is a review-only pass, docs-only PR as before. Nothing here blocks Wave 1; items 1–4 and the C2b nit are cheap edits before their respective waves dispatch (1/2/4 before Wave 1/2, the C2b nit before Wave 5).

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit 63c4e71. Configure here.

@r-uben r-uben left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Verdict: REQUEST_CHANGES (fold before Wave 1 / before /plan next; docs-only — do not merge until revised)

Revise pass on 63c4e71 vs current main (92c1527). Axes: fidelity, coverage, gating, dispatchability. Soft notes from prior MERGE — all KEEP (one strengthened).

Soft notes (verify → keep)

  1. STATUS base SHA / next-action — KEEP. Board still says main @ b7323f7 (#587). Tip is 92c1527 (#588, digest-correction log). Next action still says commit/open the PR — already done. Point at Wave 1 dispatch and refresh the base-state line so /plan next does not start from a dead tip.

  2. A2 8/8 vs A1b demotion — KEEP / strengthen. Done-when says both "fix only A1b's native-side classes" and "8/8 unresolved target labels reconstructed". Pin explicitly: reconstruct gate = native-side subset only (shredded_label / bbox_truncated); absent_text / other / neighbour_capture logged on their own line and out of that denominator.

  3. B2 fresh baseline — KEEP / strengthen. Run-2's own log (now on main via #588) records the three-digest venv-pointer confound. STATUS still presents 8.0 min/page as an uncaveated measured baseline. B2 must say it establishes a fresh timed baseline under one digest + B1, not that it explains the confounded 8.0.

Fidelity

Seams still match the tree: binder owns rows (binding.py:70-71, _native_rows:559, _assign_bands:332, _row_label_and_bbox:322, bind:1276 — not native_rows.py); _disprove_one self-witnesses item.native_bbox (adjudication.py:260-268); bands_from_rules:122 / _horizontal_rules:169 match; clamp/lift/held / crop / meta call sites land; fingerprint carries socr_source_digest (:1251); restore at :8901. Flat tests/, scripts slot in pyproject.toml — fine.

Minor citation drift only: Fixed-inputs _flush_page_sidecar span (:8272-8453) is stale — def is at :8147 on this tip. Refresh on fold; not a retarget.

Example/target mismatch: A2's problem text quotes Sample 1988:1–2019:12 … (doc05/doc07 class (c) in the run-2 log) but the 3/3 gate is doc02 p3 / doc02 p4 / doc04 p3 only. Either drop Sample from the A2 blurb or ticket those loci.

Coverage

Real hole: plan parks doc05/doc07 under #585 ("sibling-LaTeX and lane items") but the run-2 log keeps class (c) native row-label items there too (doc05: 2, doc07: 1) alongside (b)/(d). A2's 8/8 does not cover them. Fold one explicit line: park those class-(c) items as out-of-wave (mixed hold; #585/#331 follow-up), or add them to A1b's census so they are not invisible.

12 class-(c) items in the log vs 8 target labels — the delta must be named, not implied.

Streams A/B/C scope and parked set (#155, #585, latency opt, booktabs) otherwise still right. C3 report-not-quota (Codex over agy's live quota) still correct.

Gating

Shape is still right for this repo: A2 hard-gates frozen replay (3/3 false clamps cleared + control fixtures), not lifted, not a live ACCEPTED quota; C3 is a report; abstain never falls back to either lane's box; B1 keeps timings out of fingerprint / fragment markdown and restores on resume; hermetic patches + pin-a-difference called out.

Vacuous risks to pin on fold (non-blocking if stated):

  • A1 "reproduces 1 lifted / 6 held on unchanged tree" — good smoke; does not prove the harness rebinds (add one hermetic fixture that forces a bind delta).
  • A2 8/8 — see demotion rule above.
  • B2 — must not treat confounded 8.0 as the thing explained.

Dispatchability

Wave 1 = A1 ∥ B1 still the right first cut. File split is real: A1 = new benchmark/replay_binding.py + scripts entry + hermetic tests + read-only import of _render_adjudication_crop; B1 owns orchestrator.py / state.py / manifest.py / cli.py. C2b's depends-on B1 is file-serialization on orchestrator, not a semantic dep — fine as written.

Do not dispatch Wave 1 until STATUS base SHA + next-action + B2 confound wording + A2 demotion rule + doc05/doc07 class-(c) park line are folded.

Bot noise (Qodo paused, CodeRabbit trigger) ignored. Claude/Codex/Bugbot revise seats still in flight — fold their verified hits in a follow-up push; this is the desk seat.

No code. No merge from the desk.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 63c4e711d0

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +82 to +84
**Done when:** `~/venvs/socr/bin/socr-replay-binding ~/Data/socr/ladder-run2-2026-09-04`
prints 7 rows and reproduces run-2's `1 lifted / 6 held` from the frozen sidecars on the
unchanged tree; `~/venvs/socr/bin/pytest tests/test_replay_binding.py -q` exits 0 with

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Verify fresh binding results instead of replaying recorded statuses

The corpus acceptance check can reproduce 1 lifted / 6 held simply by reading the recorded status that A1 is explicitly told to emit; bind() itself produces no disposition, and this ticket never requires the fresh contradiction signatures or labels to match the recorded items. A harness that extracts the wrong table region, passes the wrong markdown, or returns an empty binding can therefore satisfy this done condition while being unusable as A2's regression oracle. Require an explicit comparison between each fresh binding result and the frozen item/signature set on the unchanged tree.

Useful? React with 👍 / 👎.

Comment on lines +113 to +115
**Done when:** on frozen replay, **3/3 target tables cleared of false native-label
clamps**; **8/8 unresolved target labels reconstructed against the rendered source**
(A1b's `labels.json`); **zero false accepts** on the row-swap and neighbouring-label

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Derive A2's target count from the A1b autopsy

If A1b classifies even one of the eight failures as absent_text, neighbour_capture, or other, A2 is instructed to fix only shredded_label and bbox_truncated cases but is still required to reconstruct all 8 labels and clear all 3 tables. That makes the ticket impossible to complete precisely when the preceding autopsy disproves the current attribution. Define the A2 denominator from A1b's repairable native-side set, while retaining the excluded cases as explicit non-regression expectations.

Useful? React with 👍 / 👎.

Comment on lines +217 to +220
**Done when:** the log exists with all of the above; **the hard gate is A2's frozen-replay
3/3 (already met by then), not this count.** The derivable expectation is 10/18 ACCEPTED
(7 baseline + 3 targets) *if* nothing else moves; the log reports the actual number and,
where it differs, names the class that moved it.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Gate the geometry verifier on frozen real disputes

A2's 3/3 gate runs before C2b and clears the target contradictions, so it cannot validate the geometry-addressed disproof introduced by C2b. The remaining C3 requirement only asks for a report, which means C2b may abstain on every real corpus contradiction—or otherwise fail to produce useful correspondence—and the entire plan still completes. Add a deterministic frozen-replay assertion for known geometry-addressable disputes and expected abstentions after C2b; this avoids a nondeterministic acceptance quota while actually gating the verifier-independence change.

Useful? React with 👍 / 👎.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

No issues found across 2 files

Re-trigger cubic

Second panel (Codex/Claude/Cursor/Bugbot; Gemini silent) updates:
- Base SHA 92c1527 (#588); caveat confounded 8.0 min/page baseline
- Wave 1 dispatch as next action (A1 ∥ B1)
- A1 explicit fresh bind() vs frozen sidecar comparison gate
- A2 native-side-only reconstruct denominator; target-table examples
- B2 fresh timed baseline under one digest
- C2b file split (ContradictionItem in adjudication.py) + frozen-replay gate
- Park doc05/doc07 class-(c) native labels out of wave

Co-authored-by: Rubén Fernández-Fuertes <r-uben@users.noreply.github.com>
@r-uben

r-uben commented Sep 4, 2026

Copy link
Copy Markdown
Owner Author

Revision 2 pushed (82d5a43). Folded, each verified against 92c1527:

  • desk 1/4 — STATUS base SHA → 92c1527, next action → wave 1 dispatch
  • desk 2 + Codex P1 (A2) + @claude 2 — A2 denominator is A1b's native-side N; absent_text / neighbour_capture / other are non-regression lines outside it
  • desk 3 + @claude 3 — B2 is a fresh one-digest baseline; 8.0 min/page labelled confounded in Goal and STATUS
  • Codex P1 (A1) — gate is fresh bind() items vs frozen binding_adjudication[*].items[] multiset, plus a fixture that forces a bind delta
  • Codex P1 (C2b) — deterministic frozen-replay gate: C1's truth table predicts geometry-addressed / abstained per frozen item before implementation, replay asserts it; abstain-on-everything fails
  • desk coverage — doc05/doc07 class-(c) items (3 of 12) parked explicitly; A1b censuses all 12 and locates the unallocated one
  • desk fidelity — Sample … example dropped from A2; _flush_page_sidecar cite refreshed
  • @claude C2b nit — targets ContradictedCell / RowLabelContradiction in binding.py; ContradictionItem stays in adjudication.py

Wave 1 (A1 ∥ B1) unchanged.

@claude

claude Bot commented Sep 4, 2026

Copy link
Copy Markdown

Claude finished @r-uben's task in 3m 13s —— View job


Revise pass — verify revision-2 fold (@claude)

  • Locate the fold commit and diff it against the prior tree
  • Verify all 8 claimed folds against STATUS.md / TICKETS.md / the 92c1527 tree
  • Cross-check the run-2 log's class-(c) arithmetic (12 total) against the plan's census
  • Post findings

Note: the local checkout only has 6473b2a ("docs(vi): fold second revise panel findings into plan", authored by Cursor Agent) — I could not git fetch/gh in this sandbox to confirm the 82d5a43 SHA cited in the trigger comment exists as a distinct commit. Content-wise 6473b2a matches every item in your changelog list, so I've verified against that tree; flag if 82d5a43 is actually a different, later commit I haven't seen.

7 of 8 confirmed folded correctly

  • STATUS base SHA / next action (STATUS.md:19,56) → 92c1527, next action → Wave 1 dispatch. ✓
  • A2 denominator (TICKETS.md:120-124) → N/N where N = A1b's native-side subset; absent_text/neighbour_capture/other logged outside it. ✓
  • B2 / confounded 8.0 — Goal (TICKETS.md:20-23) and STATUS.md:25-27 both now say "confounded" and tie it to the three-digest venv repoint; B2's problem statement (:152-155) frames it as a fresh one-digest baseline, not an explanation. ✓
  • A1 gate (TICKETS.md:84-91) — now an explicit fresh-bind()-vs-frozen-sidecar comparison plus a delta-forcing fixture, not an echo of recorded status. ✓
  • C2b deterministic gate (TICKETS.md:211-215) — requires both a disprove-via-cell_bbox case and an abstain case on the frozen corpus, so an abstain-everything implementation fails the first half. Correct shape for Codex's ask, though it doesn't explicitly cite "C1's truth table" — cosmetic only.
  • C2b file split (TICKETS.md:196,202-203) — ContradictedCell/RowLabelContradiction in binding.py, ContradictionItem stays in adjudication.py (confirmed: adjudication.py:70). ✓
  • Fidelity nitsSample … example dropped from A2's problem text (now Treasury inst. forward rate / 1t 1t only); _flush_page_sidecar cite refreshed to :8147 (confirmed against tree — def is at orchestrator.py:8147). ✓

1 of 8 not actually landed: the 12th class-(c) item is still unallocated

The changelog says "A1b censuses all 12 and locates the unallocated one," but the ticket text doesn't do this yet.

  • Run-2 log (docs/log/2026-09-04_ladder-corpus-rerun.md:54) states 12 total class-(c) items.
  • Named in the plan: doc02 p3 (3) + doc02 p4 (4) + doc04 p3 (1) = 8 (A2's target set) + doc05 (2) + doc07 (1) = 3 (parked, TICKETS.md:235-237). That's 11 of 12.
  • The 12th is unnamed anywhere in TICKETS.md. Arithmetic pins its location: the log's own class totals (run 2: (a)=0, (b)=6, (c)=12, (d)=4, sum=22) only close if doc00 p4-t0 — logged at line 90 as "UNVERIFIED (binding contradiction) … contradiction items not captured for this table" — contributes exactly 1 item, and it must be class (c) (every other class's count is already fully accounted for by the named tables: (b)=6 from doc05+doc07, (d)=4 from doc03+doc05+doc07).
  • A1b's actual ticket text (TICKETS.md:93-104) still only says "the 8 failed disproofs and the 3 native-label-blocked tables" — no mention of a 12-item census or of doc00 p4. Parked (:235-237) only parks doc05/doc07's 3. So the 12th item is currently invisible in the plan, the same failure mode the plan itself warns against ("not invisible") for the doc05/doc07 items.

Suggested fold: add one line to A1b's Do:/Done when: — census all 12 class-(c) items (not just the 8 target-table ones), and name doc00 p4-t0's item explicitly (classify it, and park or fold it the same way doc05/doc07 are parked).

Not re-checked this pass

Stream C1/C2a substance, hermeticity patches, byte-identity/resume-gate citations — these held on the prior two passes and nothing in this revision touched them.

Verdict: one real, concrete coverage gap (doc00 p4-t0 / the 12th class-(c) item); everything else in the changelog checks out against the tree. Non-blocking for Wave 1 (A1 ∥ B1 don't touch A1b), but should land before Wave 2 dispatches A1b. No code, no merge from this seat.

…of the rev-2 fold

On 6473b2a (the concurrent fold of the same panel): A1b censuses all 12
class-(c) items and defines A2's denominator N explicitly; B2 asserts one
socr_source_digest before tabulating; C2b's frozen-replay gate is a per-item
prediction recorded before implementation and fails if every item abstains;
Fixed inputs name ContradictedCell / RowLabelContradiction vs ContradictionItem.
@r-uben

r-uben commented Sep 4, 2026

Copy link
Copy Markdown
Owner Author

Rev 3 (0d703c7) on top of 6473b2a — the two folds of the same panel crossed; 6473b2a kept as base (its A2 problem text and _run_fingerprint:976 cite are better). Re-applied only where mine was stricter: A1b censuses all 12 class-(c) items and defines A2's N; B2 asserts a single socr_source_digest before tabulating; C2b's frozen-replay gate is a per-item prediction recorded before implementation and fails on abstain-everything; Fixed inputs name ContradictedCell / RowLabelContradiction vs ContradictionItem.

…1/A2/B2/C2b gates

A1 compares multisets with duplicate counts and asserts the exact expected
delta with sidecar bytes unchanged; A2 freezes A1b's classifications before
repair and revises 3/3 explicitly if invalidated; B2 checks the resolved
package path and that every sidecar digest equals the checkout's intended
digest (sidecars agreeing with each other does not catch a repointed venv);
C2b's prediction is a separately committed artifact referenced by SHA, with a
feasibility checkpoint instead of a forced geometry-addressed item.
@r-uben

r-uben commented Sep 4, 2026

Copy link
Copy Markdown
Owner Author

Rev 4 (897738b) — four tightenings from the Codex brain seat on rev 3:

  • A1: multiset comparison with duplicate counts; the delta fixture asserts the exact expected delta and that sidecar bytes are unchanged.
  • A2: A1b classifications frozen before repair (A2 may not reclassify); all three targets stay in the report; if findings invalidate 3/3 the gate is revised in TICKETS.md before implementation, never shrunk silently.
  • B2: verify the resolved package path and that every sidecar's socr_source_digest equals the checkout's intended digest — sidecars merely agreeing with each other passes a consistently repointed venv.
  • C2b: the per-item prediction is a separately committed artifact referenced by SHA before C2b starts; 'at least one geometry-addressed item' replaced by a feasibility checkpoint back to the owner.

@r-uben r-uben left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Verdict: MERGE

Re-review of tip ff799b5 (rev 5) vs desk REQUEST_CHANGES on 63c4e71 (5118389648). Docs-only; prior blockers folded.

Prior REQUEST_CHANGES — cleared

  1. STATUS base SHA / next-action92c1527 (#588); next action = Wave 1 A1 ∥ B1.
  2. A2 demotion / N/N → denominator = A1b native-side only; classifications frozen before repair; silent shrink forbidden.
  3. B2 vs confounded 8.0 → Goal + STATUS caveat the three-digest mid-run; B2 is a fresh one-digest baseline (rev 5: pinned checkout + explicit PYTHONPATH + resolved-path check).
  4. doc05/doc07 class-(c) park → explicit parked line; A1b censuses all 12.
  5. Sample / _flush_page_sidecar fidelity → Sample dropped from A2; cite refreshed to :8147.
  6. A1 vacuity → multiset (native_token/model_token/kind, duplicate counts) + exact-delta fixture + sidecar bytes unchanged.
  7. C2bContradictedCell/RowLabelContradiction in binding; prediction as separately committed SHA-referenced artifact; feasibility checkpoint (no forced geometry item).
  8. C3 → inherits B2 run discipline.

Wave 1 file split still real. C3 report-not-quota still right.

Soft — fold before Wave 2 (A1b) / Wave 3 (A2), not merge-blocking

  1. A2 sibling-module framing. #331 / #418 / #146 already land in reconstruct.py / header_repair.py (test_gh331_stub_labels.py imports rowize_from_word_list, not binding). Binder has its own rowizer (binding.py:70-71). Say explicitly: A2 fixes an independent recurrence in binding.py; use reconstruct.py's proven fix as design reference — do not re-touch reconstruct.py.
  2. A2 Files: list. test_tr1_rowizer.py / test_gh331_stub_labels.py / test_table_header_gh146.py do not import binding — label them must-stay-green scope guards, separate from the edit list, or Wave-disjointness convention breaks.
  3. 12th class-(c). A1b says "find it"; Claude's arithmetic pins doc00 p4-t0 (log: contradiction items not captured). Name that candidate in A1b so it cannot stay invisible the way doc05/doc07 almost did.

Bot noise ignored. No code. No merge from the desk.

@r-uben
r-uben merged commit 0adf013 into main Sep 4, 2026
5 checks passed
@r-uben
r-uben deleted the feat/verifier-independence-plan branch September 4, 2026 22:57
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