Skip to content

test(parity): value-level label parity — catch accept/accept-with-divergent-data (#1009 P0) - #186

Merged
saadqbal merged 1 commit into
developfrom
feat/1009-value-level-label-parity
Jul 8, 2026
Merged

test(parity): value-level label parity — catch accept/accept-with-divergent-data (#1009 P0)#186
saadqbal merged 1 commit into
developfrom
feat/1009-value-level-label-parity

Conversation

@LukasWodka

@LukasWodkaLukasWodka commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Summary

The validator-parity harness pinned only accept/reject verdicts. So the one failure mode RFC-0002 leans hardest on — the CLI previews "N labeled rows, K classes" while the ingestor actually writes null/fewer — sailed through every gate. That's the data-ingestors #340 class (a case-/whitespace-mismatched label passes both verdicts, then reads NULL in-cluster). This adds a value-level layer on top of the verdict pins: the resolved label header + row count + class set the real ingestor read path produces must equal the Go preview's.

This is the P0 "value-level parity" keystone of #1009 — "the only thing that catches accept/accept-with-divergent-data."

What changed

  • gen-validator-goldens.py — for cases flagged value_parity (and accepted), drives the REAL ingestor read path (CSVIngestor.read_data + the chore: back-merge main → develop (adopt cobra 1.10.2 + reconcile drift) #340 label resolution + RecordProcessor) and records {resolved_label, row_count, classes}. Fails loudly if the target ingestor predates chore: back-merge main → develop (adopt cobra 1.10.2 + reconcile drift) #340 (won't pin the bug).
  • preflight.go — factored CheckLabelDiversity's read/resolve/NA/collapse loop into readLabelColumnValues (one scan → resolved label, class set, row count) and exposed ReadLabelValues. CheckLabelDiversity now derives its verdict from that single source — no forked read loop; also gives RFC-0002's "check your data" preview a real value read to show.
  • parity_golden_test.go — for value_parity cases, asserts the Go preview's resolved label + row count + class set equal the ingestor golden.
  • sync-validator-goldens.sh --check — now compares values too (they carry no fixture paths), so a value-only drift can't slip past the verdict-only check.
  • cases.json — flags the 9 accept/accept string-label cases as value_parity.

Proven to bite

Mutating imgc-label-case's golden to the pre-#340 state (unresolved label, empty classes) fails the test:

resolved label: Go preview = "Label", ingestor golden = "label"
(the read paths resolve the label column differently — #340 class)
class set: Go preview = [cat dog], ingestor golden = []

Regenerating against #340 restores green. imgc-label-case (header " Label " vs config label) is exactly the `Label`/label read-path case #1009 P0 names — value parity turns it into a live proof of #340.

Scope & dependency

Type

Test hardening · cli · RFC-0002 foundation. Part ofbackend#1009 (P0 value-level parity) — not the whole ticket.

Remaining #1009: money-path seam (submitFn/portForwardFn/mintTokenFn + exit-code/reclaim matrix), CI drift wiring (pin the schema-drift + goldens SHA, per-package coverage floor), cross-repo taxonomy contract test, one real content-compared ingest e2e.


Note

Low Risk
Test-hardening and a refactor of label reading that keeps diversity checks on the same scan; production preflight behavior should be equivalent with clearer shared semantics.

Overview
Extends the validator-parity harness beyond accept/reject so the Go CLI preview cannot agree with the ingestor on verdict while reading different label data (data-ingestors #340).

Preflight refactors label diversity into a shared readLabelColumnValues scan that returns resolved header, row count, and class set via ReadLabelValues / LabelReadValues; CheckLabelDiversity now derives its verdict from that same read.

Harness & goldens:cases.json marks nine accept cases with value_parity. gen-validator-goldens.py records ingestor value goldens from the real CSVIngestor read path (requires #340_resolve_label_column). parity_golden_test.go asserts Go values match those goldens. sync-validator-goldens.sh --check compares verdicts and values so value-only drift fails CI.

Numeric-label cases stay verdict-only; string-read paths are what value parity pins.

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

…ergent-data (#1009 P0)
The validator-parity harness only pinned accept/reject verdicts, so the one
failure mode RFC-0002 leans hardest on — the CLI previews "N labeled rows"
while the ingestor writes null/fewer — passed every gate (data-ingestors
#340). This adds a value-level layer on top of the verdict pins.
Generator (gen-validator-goldens.py): for cases the manifest flags
`value_parity` (and the ingestor accepts), drive the REAL ingestor read path
(CSVIngestor.read_data + the #340 label resolution + RecordProcessor) and
record the resolved label header, the row count, and the class set it stores.
Requires the #340 fix in the target ingestor; fails loudly rather than pin the
bug if it's absent.
Go preview (preflight.go): factor CheckLabelDiversity's read/resolve/NA/
collapse loop into readLabelColumnValues — one scan that returns the resolved
label, sorted class set, and row count — and expose it as ReadLabelValues.
CheckLabelDiversity now derives its verdict from that single source (no forked
read loop; loses only the multi-class early-exit micro-opt). This also gives
RFC-0002's "check your data" preview a real value read to display.
Test (parity_golden_test.go): for value_parity cases, assert the Go preview's
resolved label + row count + class set equal the ingestor golden. Proven to
bite: mutating imgc-label-case's golden to the pre-#340 state (unresolved
"label", empty classes) fails the test with "the read paths resolve the label
column differently — #340 class"; regenerating against #340 restores green.
sync-validator-goldens.sh --check now compares values too (they carry no
paths), so a value-only drift can't slip past the verdict-only check.
imgc-label-case (header " Label " vs config `label`) is the ` Label `/`label`
read-path case #1009 P0 asks for — value parity turns it into a live proof of
#340.
Scope: string-read labels (image/text always; tabular string-family). Numeric
labels stay verdict-only — cross-language float formatting ("1.0" vs "1") makes
value comparison unreliable, and the numeric collapse is already verdict-pinned.
Depends on data-ingestors #340 (di#352): the value goldens are generated
against it. Once #340 lands on data-ingestors develop, a regen is a no-op; the
P0.3 CI drift job must pin a data-ingestors SHA that includes #340.
Part of backend#1009 (P0 value-level parity). Remaining #1009: money-path
seam, CI drift wiring (pin SHA + coverage floor), cross-repo taxonomy contract,
one real content-compared e2e. Part of the data-ingest epic backend#1008.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@saadqbal

Copy link
Copy Markdown
Collaborator

bugbot run

@cursor

cursorBot commented Jul 8, 2026

Copy link
Copy Markdown

Bugbot couldn't run

Bugbot is not enabled for your user on this team.

Ask your team administrator to increase your team's hard limit for Bugbot seats or add you to the allowlist in the Cursor dashboard.

@LukasWodka

Copy link
Copy Markdown
ContributorAuthor

bugbot run

@cursorcursorBot 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 00f728e. Configure here.

@saadqbal

Copy link
Copy Markdown
Collaborator

Nice, careful PR 👍 The single-scan refactor of CheckLabelDiversity is behavior-preserving (all 25 parity cases still pass) and the pre-#340 mutation test is a solid proof it bites. One non-blocking thought: read_label_values value-parity leans on infer_schema typing everything VARCHAR — worth a comment noting numeric-looking labels need an explicit schema, though that asymmetry predates this PR.

@saadqbal
saadqbal merged commit e0e4fc4 into developJul 8, 2026
20 checks passed
saadqbal added a commit that referenced this pull request Jul 9, 2026
…0.3) (#188)
* ci: pin the data-ingestors schema ref + add a coverage floor (#1009 P0.3)
Two of the three CI drift tripwires from #1009. (The third — a scheduled
`sync-validator-goldens.sh --check` against the pinned ingestor — waits for
#340 to land on a stable ref, since the value-aware check regenerates against
the ingestor read path and needs the #340 fix; the Go-side parity test already
enforces the committed goldens on every PR.)
(b) Pin the schema-drift check to a data-ingestors SHA, not floating master.
sync-schema.sh now builds the fetch URL from scripts/.data-ingestors-ref (a
pinned commit SHA), overridable via DATA_INGESTORS_REF. Before, any upstream
commit touching the schema reddened every open CLI PR until someone synced;
now adopting upstream is a deliberate SHA bump + re-sync in one PR. Pinned to
0de1f148 (current master; the embedded schema matches it — check stays green).
(c) Add a per-package coverage floor. `go test -cover` printed numbers and
asserted nothing, so the two load-bearing, historically thin-tested packages
could silently rot. scripts/coverage-floor.sh fails the build if internal/cli
or internal/submit drops below its floor; wired into the Test job after
`go test`. Floors are a RATCHET (bump UP only, lowering is a reviewed edit),
set just under current develop: internal/cli 68% (now 70.1%), internal/submit
72% (now 74.8%). Bump these up once #186/#187 land (they lift internal/cli to
~72%). The script is bash-3.2-portable (no associative arrays — macOS default).
Verified locally: sync-schema.sh --check matches at the pinned SHA;
coverage-floor.sh passes and bites (a 99% floor fails, a below-current floor
passes); shellcheck clean; build.yml parses; full suite green.
Part of backend#1009 (P0 CI drift tripwires). Remaining #1009: the goldens
drift job (post-#340), the cross-repo taxonomy contract test, one
content-compared ingest e2e. Part of the data-ingest epic backend#1008.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* ci: fail loudly on a malformed coverage-floor entry (#1009 P0.3)
A dropped ":floor" in FLOORS left min="$entry" (the whole token); the
awk comparison then errored on that as bare source and exited non-zero,
which `if awk` read as "not below floor" and printed a bogus "ok" — the
ratchet became a silent no-op for that package. Validate each entry has
a "package:INT" shape before the awk call.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* ci: validate the data-ingestors ref before it enters the schema URL (#1009 P0.3)
The ref (pinned file value, or the DATA_INGESTORS_REF override) is
interpolated into a raw.githubusercontent.com URL. An unvalidated ref
could inject path traversal ("../..") or extra path segments — the same
class scripts/install.sh already guards for its release tag. Restrict
the ref to a SHA/branch/tag shape (alnum start; alnum . _ - / ; no "..")
and fail with exit 2 otherwise.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Asad Iqbal <asad.dsoft@gmail.com>
@LukasWodka
LukasWodka deleted the feat/1009-value-level-label-parity branch July 9, 2026 11:41
Sign up for freeto 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

@LukasWodka@saadqbal