Skip to content

fix(compliance): evidence-based HIPAA coverage, token hint matching, GDPR measures - #354

Open
kevincostner17 wants to merge 1 commit into
mainfrom
fix/compliance-report-evidence
Open

kevincostner17 wants to merge 1 commit into
mainfrom
fix/compliance-report-evidence

Conversation

@kevincostner17

Copy link
Copy Markdown
Contributor

Summary

Compliance reports now rest on evidence from the run instead of optimistic defaults.

  • HIPAA Safe Harbor report passes without dataframe= even when identifier columns exist #245 — HIPAA Safe Harbor passed without dataframe=.
    • Cause: without a source frame, the adapter only saw columns that cleaning touched. Untouched identifier columns (e.g. ssn, patient_email) were invisible, so every identifier came back not_detected.
    • Fix:
      • CleanReport now records input_columns, the post-rename column list, in run_pipeline and apply_plan.
      • The compliance context uses it when dataframe= is absent.
      • When no full column list exists, the HIPAA report sets coverage_verifiable: False, adds a warning, and does not pass.
    • input_columns is not part of to_dict(), so the JSON schema and golden snapshots are unchanged.
  • HIPAA identifier hints match substrings: description, last_updated, business_unit flagged #283 — HIPAA hints matched substrings (ip in description, date in last_updated, sin in business_unit).
    • Column names are now split into tokens on separators, camelCase and letter/digit boundaries.
    • Every hint matches as a whole token or token sequence (DateOfBirth matches date_of_birth), and hints of four characters or fewer match only that way.
    • Longer hints may also match inside run-together names (patientemail), but never starting part-way through a token (ship_address no longer matches ip_address).
    • Added surname and zipcode hints.
  • GDPR Article 30 record always lists 'Hash-salt PII masking' as a security measure #287 — GDPR Article 30 always listed "Hash-salt PII masking (SHA-256 + salt)".
    • security_measures is now built from evidence.
    • A masking entry appears only when columns were masked; it names the recorded strategies and makes no cryptographic claims.
    • The Data Trust Score entry appears only when a trust score was available.

Behaviour changes

  • Untouched identifiers now count: HIPAA reports from fd.clean / fd.apply_plan without dataframe= detect them, so reports that used to pass can fail.
  • No column evidence now fails HIPAA: those reports fail with a warning. This covers synthetic reports, and reports from native backends, streaming and multi-file runs, which don't record input_columns yet.
  • Short hints are stricter: they no longer match inside other words. All-lowercase run-together names that relied on one (e.g. visitdate, patientssn) are no longer flagged; separated or camelCase forms still are.
  • GDPR is accurate: security_measures no longer claims masking or a trust score that wasn't applied.

Tests

Verification

  • ruff check .: all checks passed
  • mypy src/freshdata: no issues in 202 source files
  • pytest -m "not online and not large" on py3.12: 4279 passed, 6 skipped
  • pytest -m "not online and not large" on py3.9 / pandas 1.5: 4275 passed, 10 skipped

Closes #245
Closes #283
Closes #287

…vidence

HIPAA Safe Harbor passed without dataframe= even when identifier columns
existed (#245). Without a source frame the adapter only saw columns that
cleaning touched, so untouched identifiers such as ssn or patient_email were
invisible and all 18 identifiers came back not_detected. CleanReport now
records input_columns (the post-rename column list) in run_pipeline and
execute_plan, and the compliance context uses it when dataframe= is absent.
When neither is available the HIPAA report sets coverage_verifiable=False,
adds a warning and does not pass. input_columns is not added to to_dict(),
so the JSON schema and golden snapshots are unchanged.

HIPAA identifier hints matched raw substrings (#283), so "ip" flagged
description and shipping_cost, "date" flagged last_updated and "sin" flagged
business_unit. Column names are now tokenized on separators, camelCase and
letter/digit boundaries. Every hint matches as a whole token or token
sequence. Hints of four characters or fewer match only that way. Longer hints
may also match inside run-together names (patientemail, dateofbirth), but not
starting part-way through a token (ip_address no longer matches
ship_address). "surname" and "zipcode" hints were added so those common
run-together names are still detected.

The GDPR Article 30 record always listed "Hash-salt PII masking
(SHA-256 + salt)" (#287). security_measures is now built from evidence: a
masking entry appears only when columns were masked, with the recorded
strategies and no cryptographic claims, and the Data Trust Score entry
appears only when a trust score was available.

Closes #245
Closes #283
Closes #287
@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: ae1e114e-ac15-4803-bbcf-76f7e83f4301


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)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant