Skip to content

fix: semantic-type and domain-validator edge cases from adversarial QA pass#136

Merged
JohnnyWilson16 merged 2 commits into
mainfrom
debug/semantic-domain-validation-jwd
Jul 12, 2026
Merged

fix: semantic-type and domain-validator edge cases from adversarial QA pass#136
JohnnyWilson16 merged 2 commits into
mainfrom
debug/semantic-domain-validation-jwd

Conversation

@JohnnyWilson16

@JohnnyWilson16 JohnnyWilson16 commented Jul 12, 2026

Copy link
Copy Markdown
Contributor

An adversarial QA pass over the Semantic Models (semantic/semantic_types.py) and Domain Validators (all 8 packs) with valid/invalid/missing/malformed/duplicate/noisy/mixed-domain/multilingual/boundary/large-volume inputs. Four confirmed defects, each fixed with a regression test; no API changes.

Fixes

1. Boolean columns could never be detected (semantic/semantic_types.py)
A bool-dtype column or ["yes", "no"] column has ≤2 distinct values, so MIN_DISTINCT_SUPPORT = 5 returned unknown before the boolean check ran — boolean_like was unreachable for the most common boolean representations. All-boolean-token columns are now recognised ahead of the support gate; a bare {"0", "1"} column stays gated since it is just as likely numeric.

2. Strict-format name hints certified contradicted types (semantic/semantic_types.py)
A column named email containing only numbers (0% of values email-shaped) was still reported as email at 0.5 confidence. For strict-format types (email/url/phone/postal_code) a 0% content match now vetoes the name hint and records a conflict evidence entry. Genuinely inconclusive content (nonzero but below the 60% bar) still lets the name hint through unchanged.

3. Finance FIN-006 crashed on all-missing transaction ids (domains/finance/validator.py)
groupby("_txn").transform("sum") raises IndexError: cannot do a non-empty take from an empty axes in pandas when every group key is NaN. NaN-id rows were already exempt from the balance rule; they are now dropped before the groupby, so an all-NaN id column validates cleanly and identified transactions are still checked.

4. validate_fields silent failures at the schema boundary (fieldcheck.py)

  • {"price": "numeric"} (a natural shorthand) crashed with a raw AttributeError; string values now coerce to FieldSpec(semantic_type=...), other non-FieldSpec values raise a clear TypeError.
  • A typo'd/unknown semantic_type with no other constraint silently validated nothing — the user believed the column was checked when it wasn't. This now emits a UserWarning naming the known types. Unknown types with their own pattern/vocabulary constraints keep the documented fallback behaviour, warning-free.

Verified good under adversarial input (no change needed)

  • The flagship outlier case: "apple" in a price column is preserved (never coerced/dropped), flagged by validate_fields as semantic_mismatch → quarantine, and caught by consensus inference even without a schema; "apple" as a company name and number-words in *_id columns are left untouched.
  • All 8 domain packs on empty/junk/multilingual/duplicate-index/non-string-label frames; healthcare/media/transport ambiguity errors are clear and actionable; finance at 200k rows in ~8s with deterministic reports and in-range violation rows.
  • infer_semantic_type on 40+ edge cases: multilingual scripts, garbage bytes, unhashable payloads, embedding-vote conflicts/out-of-range scores, 200k-row columns — confidence always in [0,1], deterministic.

Testing

  • Full suite: 3238 passed, 12 skipped; ruff + mypy clean.
  • New regression tests in tests/test_semantic_types.py, tests/domains/test_finance.py, tests/test_fieldcheck.py.
  • test_name_hint_used_when_content_is_inconclusive fixture updated from 0%-matching to 3/8-matching values so it tests what its name says (inconclusive, not contradictory); the contradiction case is its own new test.

Prepared with AI tooling; every finding and fix manually verified.

Summary by CodeRabbit

  • New Features

    • Field validation schemas can now use semantic-type shorthand strings, such as "numeric".
    • Invalid schema entries produce clear type errors, while unknown unconstrained semantic types generate warnings.
    • Semantic-type inference now better recognizes boolean values and accounts for conflicting column names and content.
  • Bug Fixes

    • Finance balance checks no longer crash or report incorrect violations when transaction identifiers are missing. Identified transactions continue to be checked correctly.

…al QA

- semantic_types: boolean columns (bool dtype, yes/no) were unreachable —
  the distinct-support gate ran before any boolean check even though
  booleans inherently have ~2 distinct values; recognise all-boolean-token
  columns first (bare {0,1} stays gated as likely-numeric)
- semantic_types: a strict-format name hint (email/url/phone/postal_code)
  is no longer certified when 0% of sampled values match it; the conflict
  is recorded as evidence instead
- finance: FIN-006 balance check raised IndexError when every
  transaction_id was missing (pandas groupby-transform with zero groups);
  id-less rows are exempt, identified transactions still checked
- validate_fields: accept {'col': 'numeric'} string shorthand, raise a
  clear TypeError for non-FieldSpec schema values (was AttributeError),
  and warn when an unknown semantic_type has no other constraint (the
  spec silently validated nothing)

All regressions covered by new tests; full suite 3238 passed / 12 skipped,
ruff + mypy clean.
@strix-security

Copy link
Copy Markdown
Contributor

Strix is installed on this repository, but we couldn't run this PR security review because this workspace's trial has ended. Add a card to resume code reviews here.

@coderabbitai

coderabbitai Bot commented Jul 12, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@JohnnyWilson16, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 49 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: b4da53b1-fe35-4d70-bbe9-fccc54acf784

📥 Commits

Reviewing files that changed from the base of the PR and between 909d32e and 7b802f1.

📒 Files selected for processing (1)
  • tests/test_fieldcheck.py
📝 Walkthrough

Walkthrough

Finance validation now handles missing transaction identifiers. Field validation accepts semantic-type shorthand and validates schema entries. Semantic inference uses distinct-value detector shares, earlier boolean detection, and contradiction evidence for strict-format hints.

Changes

Finance balance validation

Layer / File(s) Summary
Filter unidentified transactions and test balance counts
src/freshdata/domains/finance/validator.py, tests/domains/test_finance.py
Balance checks exclude rows with null transaction identifiers before grouping, return no violations when none remain, and cover all-null and partially missing identifiers.

Field schema preprocessing

Layer / File(s) Summary
Normalize schema values and validate semantic types
src/freshdata/fieldcheck.py, tests/test_fieldcheck.py
validate_fields accepts semantic-type strings, rejects unsupported schema values, and warns when unknown semantic types have no executable constraints; corresponding tests cover these cases.

Semantic type inference

Layer / File(s) Summary
Update content detection and hint handling
src/freshdata/semantic/semantic_types.py, tests/test_semantic_types.py
Inference calculates shares from distinct values, detects eligible boolean columns before support gating, preserves binary "0"/"1" handling, and records conflicts for contradictory strict-format name hints.

Estimated code review effort: 3 (Moderate) | ~25 minutes

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description covers the changes, but it is missing several required template sections and the issue/reference and checklist fields. Add the required Description, Fixes #, Type of Change, and Checklist sections, and complete the checklist items.
Docstring Coverage ⚠️ Warning Docstring coverage is 26.32% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title is concise and accurately summarizes the main edge-case fixes across semantic types and domain validators.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch debug/semantic-domain-validation-jwd

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.

@github-actions

github-actions Bot commented Jul 12, 2026

Copy link
Copy Markdown

FreshData benchmark report — 2026-07-12T16:10:07Z

  • freshdata: 1.1.1
  • python: 3.12.13
  • platform: Linux-6.17.0-1018-azure-x86_64-with-glibc2.39
fixture n_rows n_cols p50 s p95 s peak MB repair % false-repair % preserve % trust monotonic export %
crm 10,200 40 1.511 1.516 13.8 100.0 0.0 100.0 93.84 100.0
event_log 10,000 25 0.638 0.640 5.1 100.0 0.0 100.0 99.677 100.0
finance 10,200 60 1.939 1.969 18.3 100.0 0.0 100.0 99.499 100.0
gold 10,200 7 0.230 0.232 3.7 100.0 0.0 100.0 98.3 100.0
provenance 10,000 18 0.498 0.500 7.2 100.0 0.0 100.0 99.765 100.0
wide_schema 10,000 100 3.684 3.689 13.7 100.0 0.0 100.0 96.042 100.0

Authored-code reduction (Metric 6)

  • FreshData: 3 lines
  • pandas baseline: 25 lines (88.0% reduction)

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 3

🧹 Nitpick comments (1)
tests/test_fieldcheck.py (1)

6-6: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Tests cover the new schema preprocessing behaviors well.

The three new tests appropriately verify string shorthand conversion, TypeError for invalid schema values, and UserWarning for unconstrained unknown semantic types. The second half of test_unknown_semantic_type_without_constraints_warns correctly uses warnings.simplefilter("error") to assert no warning is emitted when a pattern constraint is present.

One minor note on line 690: assert any(i.rule == "pattern" for i in report.issues) or report.issues — the or report.issues fallback makes the any(...) check partially redundant, since the assertion passes if any issue exists regardless of its rule. In practice this is unlikely to mask a regression, but tightening to just assert any(i.rule == "pattern" for i in report.issues) would make the intent clearer.

Also applies to: 665-690

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/test_fieldcheck.py` at line 6, Tighten the assertion in
test_unknown_semantic_type_without_constraints_warns by removing the “or
report.issues” fallback and assert directly that report.issues contains an issue
whose rule is "pattern".
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/freshdata/fieldcheck.py`:
- Around line 799-808: Update the warning condition in the FieldSpec validation
logic around spec.semantic_type to account for nullable and required
constraints, so it only warns when both are unset or otherwise inactive
alongside the existing constraint checks. Preserve the current warning behavior
when no executable validation constraints are configured.
- Around line 97-103: Add “postal_code” to _KNOWN_SEMANTIC_TYPES and wire it
through the existing dedicated semantic-type validation logic in the cell and
vectorized check paths. Reuse the established postal-code validator and preserve
the behavior of other recognized semantic types, eliminating the unknown-type
warning for FieldSpec(semantic_type="postal_code").

In `@src/freshdata/semantic/semantic_types.py`:
- Around line 294-308: Update the categorical branch in the semantic type
inference function to return the accumulated evidence tuple, preserving the
strict-format conflict evidence appended earlier. Keep the existing column-role
evidence and result values unchanged, and do not alter the unknown path.

---

Nitpick comments:
In `@tests/test_fieldcheck.py`:
- Line 6: Tighten the assertion in
test_unknown_semantic_type_without_constraints_warns by removing the “or
report.issues” fallback and assert directly that report.issues contains an issue
whose rule is "pattern".
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: bee66d8b-b996-436a-bfb3-b99b3ccb92e7

📥 Commits

Reviewing files that changed from the base of the PR and between 1c2ed29 and 909d32e.

📒 Files selected for processing (6)
  • src/freshdata/domains/finance/validator.py
  • src/freshdata/fieldcheck.py
  • src/freshdata/semantic/semantic_types.py
  • tests/domains/test_finance.py
  • tests/test_fieldcheck.py
  • tests/test_semantic_types.py

Comment thread src/freshdata/fieldcheck.py
Comment thread src/freshdata/fieldcheck.py
Comment thread src/freshdata/semantic/semantic_types.py
test_unknown_semantic_type_without_constraints_warns used
warnings.simplefilter("error") to prove the silent-fallback path stays
quiet, but that also promotes any *unrelated* warning to a hard failure
— on Python 3.9's older numpy/pandas combo, validate_fields triggers an
internal np.find_common_type DeprecationWarning unconnected to this
code, which failed CI on 3.9 only (3.10-3.13 unaffected). Now records
warnings and asserts only that no 'unknown semantic_type' warning fired.
@JohnnyWilson16
JohnnyWilson16 merged commit 30d82b5 into main Jul 12, 2026
15 checks 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.

1 participant