Found during functional review of the data-ingest flow on develop (2026-07-10).
What
The --schema col:TYPE override (and the schema field in an ingest.yaml) is not type-validated locally. A bogus SQL type token sails past every local preflight check:
tracebloc data validate <spec with schema {age:NOTATYPE, label:totally_fake_type}> → prints <file>: ok and exits 0.tracebloc data ingest <csv> --task tabular_classification --label-column label --schema age:NOTATYPE --dry-run --no-input → passes all local checks, reaches "Connecting to your workspace…", exit 3 (kubeconfig only) — byte-identical local flow to a valid age:INT.
Only malformed syntax is caught (age: / age=INT → exit 2 "must be col:TYPE"); the TYPE token itself is never checked.
Why it matters
Defeats the CLI's "fail fast, fail local" design for the manual override path: the dedicated millisecond preflight tool (data validate) gives a false green, and data ingest burns a full upload before the in-cluster ingestor rejects the type. The documented exit-2 "schema validation failed" contract is bypassed.
Where
internal/push/tabular.go:231 — ParseSchema passes the TYPE through verbatim (its docstring explicitly defers type-checking to the in-cluster ingestor).internal/schema/ingest.v1.json:130-137 — the embedded schema constrains each schema value only to type:string, no enum/pattern.- Shared by the interactive path via
internal/cli/interactive.go:471 (validateOptionalSchema).
Fix direction (care needed)
Validate the TYPE token locally and return exit 2 on an unknown type. Do not naively enum the --help shortlist — the ingestor accepts more than that (INTEGER is a valid MySQL synonym of INT; TIMESTAMP/TIME/TEXT are supported per ParseSchema's own docstring). Mirror the ingestor's real accepted type grammar (the di#349 parity source is the authority) so valid synonyms aren't over-rejected.
Scope
Only affects the explicit --schema path; the default inferred-schema path (di#349) always emits valid types, so the common case is unaffected. Worst locally-provable cost is a wasted cluster round-trip.
Severity: MED. Verified via adversarial re-run on the real develop binary.
Found during functional review of the data-ingest flow on
develop(2026-07-10).What
The
--schema col:TYPEoverride (and theschemafield in aningest.yaml) is not type-validated locally. A bogus SQL type token sails past every local preflight check:tracebloc data validate <spec with schema {age:NOTATYPE, label:totally_fake_type}>→ prints<file>: okand exits 0.tracebloc data ingest <csv> --task tabular_classification --label-column label --schema age:NOTATYPE --dry-run --no-input→ passes all local checks, reaches "Connecting to your workspace…", exit 3 (kubeconfig only) — byte-identical local flow to a validage:INT.Only malformed syntax is caught (
age:/age=INT→ exit 2 "must be col:TYPE"); the TYPE token itself is never checked.Why it matters
Defeats the CLI's "fail fast, fail local" design for the manual override path: the dedicated millisecond preflight tool (
data validate) gives a false green, anddata ingestburns a full upload before the in-cluster ingestor rejects the type. The documented exit-2 "schema validation failed" contract is bypassed.Where
internal/push/tabular.go:231—ParseSchemapasses the TYPE through verbatim (its docstring explicitly defers type-checking to the in-cluster ingestor).internal/schema/ingest.v1.json:130-137— the embedded schema constrains eachschemavalue only totype:string, no enum/pattern.internal/cli/interactive.go:471(validateOptionalSchema).Fix direction (care needed)
Validate the TYPE token locally and return exit 2 on an unknown type. Do not naively enum the
--helpshortlist — the ingestor accepts more than that (INTEGERis a valid MySQL synonym ofINT;TIMESTAMP/TIME/TEXTare supported perParseSchema's own docstring). Mirror the ingestor's real accepted type grammar (the di#349 parity source is the authority) so valid synonyms aren't over-rejected.Scope
Only affects the explicit
--schemapath; the default inferred-schema path (di#349) always emits valid types, so the common case is unaffected. Worst locally-provable cost is a wasted cluster round-trip.Severity: MED. Verified via adversarial re-run on the real
developbinary.