Skip to content

fix(semantic): stop unsafe auto-repairs and fix memory replay expert lookup - #352

Merged
kevincostner17 merged 1 commit into
mainfrom
fix/semantic-repair-safety
Sep 15, 2026
Merged

kevincostner17 merged 1 commit into
mainfrom
fix/semantic-repair-safety

Conversation

@kevincostner17

Copy link
Copy Markdown
Contributor

Summary

These are four accuracy fixes for semantic repairs that were either auto-applied when they shouldn't be, or never replayed.

  • Memory replay auto-applies a learned repair to a different, already-valid value #252: fuzzy memory replay auto-applied to a different, already-valid value.
    • A fuzzy match kept confidence min(learned, similarity), so a one-character-different email (similarity 0.96) cleared the 0.95 auto threshold.
    • Now only exact normalized matches keep the learned confidence. Fuzzy matches are capped at semantic_auto_threshold - 0.01, so they are suggested for review and never auto-applied.
  • semantic_mode='auto' turns '45%' into 45.0 in a rate column of fractions #253: '45%' became 45.0 in a rate column of fractions.
    • NumericFormatExpert now reads the column's plain numeric values.
    • If there are at least 3 and all lie in [0, 1], it proposes value/100 in the review band.
    • A rate/ratio column with too little evidence is also held for review.
    • Percent-scale columns, and percent/pct columns without evidence, still auto-repair as before (TruthBench edu-07 unchanged).
  • semantic_mode='auto' rewrites version '1.10' as '1.1.0' (shape alignment changes meaning) #254: shape alignment rewrote '1.10' as '1.1.0'.
    • Alignment now requires the value's separator-delimited groups to match the template's groups one-to-one (same count and lengths). Otherwise nothing is proposed.
    • An unseparated value, which could be split several ways, is only suggested for review.
    • '555 0101''555-0101' (TruthBench crm-04) still auto-applies.
  • Memory replay picks the wrong expert per issue type; learned NFC repairs never replay #300: memory replay used the wrong expert for an issue type.
    • Experts were looked up in a map keyed by issue type, which kept only the last format_alignment expert. Learned NFC and shape-alignment repairs were checked as if the column were a date, so they never replayed.
    • Replay now looks up the stored expert name, and falls back to the issue type only when exactly one expert handles it.

Behaviour changes:

  • These are now suggested for review instead of auto-applied:
    • fuzzy memory matches
    • percent values in fraction-scale or unknown-scale rate/ratio columns
    • unseparated shape alignments
  • Shape alignments whose groups don't match are no longer proposed.
  • Learned NFC and shape-alignment repairs now replay from memory.
  • docs/semantic-cleaning.md now says fuzzy memory matches are only suggested.

Tests

  • New tests/test_semantic_repair_safety.py (37 tests):
    • fuzzy vs exact memory replay, and the threshold cap
    • percent handling on fraction, percent and unknown scales
    • version and phone shape alignment
    • the expert lookup for every built-in expert
    • end-to-end replay on the identical frame for 5 experts
  • 11 of these fail against main. The rest guard repairs that must keep working.

Verification

  • ruff check .: all checks passed
  • mypy src/freshdata: no issues in 202 source files
  • pytest (-m "not online and not large"), py3.12: 4276 passed, 6 skipped
  • pytest, py3.9 / pandas 1.5: 4272 passed, 10 skipped
  • TruthBench and golden tests pass with no expectation changes.

Closes #252
Closes #253
Closes #254
Closes #300

…t regrouping

Four accuracy fixes to semantic repairs that were auto-applied, or never
replayed, incorrectly.

Memory replay auto-applied fuzzy matches (#252). A learned repair replayed
onto any value with difflib similarity >= 0.92 at confidence
min(learned, similarity), so a one-character-different, already-valid email
(0.96) cleared the 0.95 auto threshold and was rewritten to the learned
target. Only exact normalized matches keep the learned confidence now. Fuzzy
matches are also capped at semantic_auto_threshold - 0.01, so they are
suggested for review and never auto-applied. Memory proposals have no
packaged calibration curve, so calibration cannot raise them back over the
threshold.

Percent stragglers ignored the column's scale (#253). NumericFormatExpert
treated every percent|pct|rate|ratio column as percent-denominated, so '45%'
in a column of 0-1 fractions became 45.0. The expert now reads the column's
plain numeric values. When at least 3 exist and all lie in [0, 1], it
proposes value/100 in the review band (0.80). A rate/ratio column with too
few plain numbers to show its scale is also held for review. Percent-scale
columns, and percent/pct columns without scale evidence, keep today's
automatic repair (TruthBench edu-07 unchanged).

Shape alignment re-split digits across groups (#254). ShapeAlignmentExpert
re-rendered the alphanumeric payload into the dominant template, so '1.10'
became '1.1.0' among semver values. Equal payloads do not mean equal values
when the separators move. Alignment now applies only when the value's
separator-delimited groups match the template's groups one-to-one (same
count and lengths). A value whose groups differ is left alone. A value with
no separators, which could be split several ways, is suggested for review
(0.75) instead of auto-applied. Separator drift such as '555 0101' ->
'555-0101' (TruthBench crm-04) still auto-applies.

Memory replay used the wrong expert per issue type (#300).
_EXPERTS_BY_ISSUE kept only the last expert per issue_type. Five experts
share format_alignment, so every learned repair of that type was gated by
IsoInstantDateExpert.applies. Learned NFC and shape-alignment repairs
therefore never replayed on their own columns. Replay now looks up the
expert by the stored expert name. It falls back to the issue type only when
exactly one expert handles that type.

Regression tests are in tests/test_semantic_repair_safety.py.

Closes #252
Closes #253
Closes #254
Closes #300
@coderabbitai

coderabbitai Bot commented Sep 14, 2026

Copy link
Copy Markdown
Contributor

Important

  • 🔍 Trigger review

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

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Advanced

Run ID: 778a68f4-34c2-4c90-832f-c53a5834fa75


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

Copy link
Copy Markdown

FreshData benchmark report — performance

  • freshdata: ?
  • python: ?
  • platform: ?
fixture n_rows n_cols p50 s p95 s peak MB repair % false-repair % preserve % trust monotonic export %

Authored-code reduction (Metric 6)

@kevincostner17
kevincostner17 merged commit 8c801f2 into main Sep 15, 2026
21 checks passed
kevincostner17 added a commit that referenced this pull request Sep 15, 2026
Add Unreleased Added, Changed and Fixed entries for merged PRs #351,
#352, #353, #354, #356, #357, #358, #360, #361, #362, #363, #364, #365,
#367, #368, #369, #370, #371, #372, #374, #375, #377, #378 and #379.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment