Skip to content

fix(ingest): mirror semseg-mask + missing DataValidator parity in preflight (cli#352)#374

Merged
LukasWodka merged 1 commit into
developfrom
fix/352-preflight-parity
Jul 21, 2026
Merged

fix(ingest): mirror semseg-mask + missing DataValidator parity in preflight (cli#352)#374
LukasWodka merged 1 commit into
developfrom
fix/352-preflight-parity

Conversation

@LukasWodka

@LukasWodka LukasWodka commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

What

Closes two data ingest preflight parity gaps where a dataset accepts locally then rejects after the full upload (cli#352):

  1. Semantic-segmentation mask resolution. data-ingestors composes a second ImageResolutionValidator for semseg — name "Mask Resolution Validator", subdir="masks", same target_size/min_size as the image one (modalities/validators.py:168-173). The CLI only validated images/, so a corrupt or mis-sized mask sailed through preflight and failed in-cluster. Now previewed by a new ValidateMaskResolution over masks/.

  2. DataValidator per-value type check. For tabular / time-series schemas the ingestor validates every value against its declared SQL type (validators/data_validator.py); the CLI only checked that the schema's columns exist (CheckSchemaColumns). A non-numeric or fractional value in an INT column, or a non-numeric value in a FLOAT column, passed preflight and rejected in-cluster after the table was created (orphaning it). Now previewed by a new CheckColumnValueTypes.

Why this scope (and what's deliberately left out)

preflight.go's contract is never out-strict the ingestor — an over-reject burns a valid upload. DataValidator is a ~1000-line, ~15-type validator built on pandas to_numeric/to_datetime coercion. Reproducing the string-length, BOOLEAN, and DATE/DATETIME/TIMESTAMP/TIME checks (plus integer overflow and non-finite) in Go risks rejecting values the cluster accepts — the same reason perGroupTimeViolation already leaves the date branch a documented under-preview. So this mirrors only the numeric type mismatch (INT-family non-numeric + non-integer; FLOAT-family non-numeric), which is provably never-over-reject (NA handling matches coercion.NA_SENTINELS; ParseFloat accepts a superset of pandas' numeric grammar; the time-series grouping time column is excluded exactly as the ingestor's factory excludes it). The remaining DataValidator surface is left as a safe under-preview — flagged for a follow-up.

Pin

scripts/.data-ingestors-ref is left unchanged. Both validators already exist at the pinned ref (8f89aec), so this is a mirror gap, not a stale pin — no goldens regeneration is required to fix it. (The pinned commit is behind develop and its comment is out of date; bumping it is a separate, deliberate change that would pull in unrelated upstream drift and needs a full goldens regen against a data-ingestors checkout.)

Test plan

  • New unit tests: TestValidateMaskResolution, TestCheckColumnValueTypes (17 sub-cases incl. over-reject guards), TestNumericCellBad.
  • Parity corpus +4 cases (drive both the Go preflight and the real Python validators): semseg-mask-res-mismatch (reject), tabular-int-nonnumeric (reject), tabular-int-noninteger (reject), tabular-typed-ok (accept — over-reject guard). TestValidatorParity green across all 71 cases.
  • Local gates green: go build, go vet, gofmt -s -l (clean), go test ./..., make lint (errcheck/ineffassign/misspell/staticcheck), make fmt-check, make schema-check, make deadcode, make vulncheck, scripts/file-budget.sh (preflight.go 1650 ≤ 1700 — the new validators live in image_resolution.go + value_types.go).
  • goldens-drift runs in CI (needs a data-ingestors checkout); the four added golden verdicts were derived from the validator source at the pin and the existing analog goldens.

🤖 Generated with Claude Code


Note

Medium Risk
Changes ingest preflight gates on tabular CSVs and semseg datasets; scope is limited to under-reject-safe numeric checks and mask parity with images, with strong unit and golden parity coverage.

Overview
Closes two accept-locally, reject-after-upload preflight gaps (cli#352) so failures surface before the full ingest.

Semantic segmentation masks: Preflight now validates masks/ with the same rules as images—corrupt/empty files, --min-size, and exact target_size—via shared scanImageResolutions and ValidateMaskResolution, wired into the semseg branch of PreflightDataset.

Tabular schema values: After column presence checks, preflight runs CheckColumnValueTypes to mirror the ingestor’s numeric DataValidator slice: non-numeric or fractional values in INT columns and non-numeric values in FLOAT/DOUBLE/etc. String, date, and boolean per-value rules are intentionally not mirrored to avoid over-rejecting valid uploads.

ValidateImages delegates decoding to the shared scanner so image and mask resolution previews stay aligned. Four parity cases plus unit tests cover mismatch rejects and an over-reject guard for valid typed data.

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

…flight (cli#352)

The `data ingest` preflight under-mirrored two in-cluster validators, so
some datasets ACCEPTED locally then REJECTED after the full upload:

- Semantic-segmentation mask resolution: the ingestor runs a SECOND
  ImageResolutionValidator ("Mask Resolution Validator", subdir=masks)
  the CLI never replicated, so a corrupt or mis-sized mask slipped through.
  Now previewed by ValidateMaskResolution over masks/, with the same
  target-size + min-size as the images (shared decode core with
  ValidateImages).

- DataValidator per-value NUMERIC type check: for tabular / time-series
  schemas the ingestor validates every value against its declared type;
  the CLI only checked column presence. Now previewed by
  CheckColumnValueTypes: a non-numeric or fractional value in an INT
  column, or a non-numeric value in a FLOAT column, is caught locally.
  Scope is deliberately numeric-only and never-over-rejects (string /
  boolean / date length + coercion, integer overflow and non-finite stay
  a documented under-preview — mirroring pandas there would risk
  rejecting values the cluster accepts).

Parity corpus extended with 4 cases (semseg mask-res mismatch, INT
non-numeric, INT non-integer, and a fully-typed accept guard). Pin left
unchanged: both validators already exist at the pinned data-ingestors ref,
so the drift is a mirror gap, not a stale pin.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@LukasWodka LukasWodka self-assigned this Jul 21, 2026
@LukasWodka

Copy link
Copy Markdown
Contributor Author

👋 Heads-up — Code review queue is at 31 / 30

Above the WIP limit. The team convention is to review existing PRs before opening new work.

Open PRs currently in Code review (oldest first):

Pull from review before opening new work. (This is a nudge from the kanban WIP check, not a block.)

@LukasWodka

Copy link
Copy Markdown
Contributor Author

@BugBot run

@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 b9b0fa3. Configure here.

@LukasWodka
LukasWodka merged commit 16f75af into develop Jul 21, 2026
25 checks passed
@LukasWodka
LukasWodka deleted the fix/352-preflight-parity branch July 21, 2026 12:58
@saadqbal

Copy link
Copy Markdown
Collaborator

/fr-pass

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