Skip to content

Cover HIPAA §(J) account numbers; split hipaa.rs by posture - #395

Merged
martsokha merged 1 commit into
mainfrom
fix/hipaa-section-j-account-labels
Aug 13, 2026
Merged

Cover HIPAA §(J) account numbers; split hipaa.rs by posture#395
martsokha merged 1 commit into
mainfrom
fix/hipaa-section-j-account-labels

Conversation

@martsokha

Copy link
Copy Markdown
Member

Summary

Before this change HIPAA Safe Harbor / Limited Data Set / Expert Determination scoped `bank_account` alone under `§(J)`. Real `§(J)` — "account numbers" per `§164.514(b)(2)(i)(J)` and `§164.514(e)(2)(x)` — covers every individual-linked account identifier the pattern set detects: also `iban`, `payment_card`, and (under the `§(R)` catch-all reading) `crypto_address`.

That's why the customer-onboarding CSV under HIPAA Expert Determination silently left IBAN, credit-card, and crypto values untouched.

API

Adds a `HipaaAccountNumbers` enum on `PolicyTemplate::HipaaDeidentification`:

  • `Standard` (default): `bank_account` + `iban` + `payment_card`. The traditional `§(J)` reading; matches every de-ID vendor's Safe Harbor preset.
  • `Extended`: adds `crypto_address`. Deployments where wallet addresses can appear in patient-facing artifacts opt in.

Both tiers apply uniformly across Safe Harbor, LDS, and Expert Determination — `§(J)` scope is a property of the identifier list, not the removal method. Threaded through `hipaa::template()` and the three per-method builders. `accounts` is `#[serde(default)]`, so callers already sending `{"method": "safe_harbor"}` continue to work.

Research

HHS OCR's 2012 guidance doesn't narrow "account numbers"; in practice covered entities and de-ID vendors (AWS Comprehend Medical, Google Cloud DLP, etc.) treat bank accounts + IBAN + payment cards as the core §(J) set. The reg does NOT sanction a "Basic vs Extended" split within the four labels themselves — every account identifier is a removable §(J) item — but there IS meaningful ambiguity around crypto wallets (a newer instrument that the reg reads via §(R) catch-all), which is exactly what `Standard` vs `Extended` splits.

Folder split

While in there, split the 800-line `hipaa.rs` into a `hipaa/` folder:

  • `mod.rs` — module doc, `HipaaDeidMethod`, `HipaaAccountNumbers` re-export, `EFFECTIVE_DATE`, `template()` dispatch, all 10 tests
  • `account_numbers.rs` — `HipaaAccountNumbers` enum + label constants + impl
  • `safe_harbor.rs`, `limited_data_set.rs`, `expert_determination.rs` — one posture per file, each owning its own constants and UUIDs

Each posture owns its own labels; Expert Determination reaches into `safe_harbor` for the shared 18-identifier label set.

New tests

  • `standard_accounts_cover_the_traditional_section_j_set`
  • `extended_accounts_add_crypto_to_the_standard_set`
  • `account_tier_lands_in_every_hipaa_method`

Test plan

  • `cargo fmt --all --check`
  • `cargo clippy --workspace --all-features --all-targets -- -D warnings`
  • `cargo test --workspace --all-features --all-targets` (33 template tests pass)
  • `RUSTDOCFLAGS=-D warnings cargo doc --workspace --all-features --no-deps`
  • `cargo machete`

🤖 Generated with Claude Code

Before this change HIPAA Safe Harbor / Limited Data Set / Expert
Determination scoped `bank_account` alone under §(J). Real §(J) —
"account numbers" per §164.514(b)(2)(i)(J) and §164.514(e)(2)(x) —
covers every individual-linked account identifier the pattern set
detects: also `iban`, `payment_card`, and (under the §(R)
catch-all reading) `crypto_address`.

Add a `HipaaAccountNumbers` enum on `PolicyTemplate::HipaaDeidentification`
picking the account label scope:

- `Standard` (default): `bank_account` + `iban` + `payment_card`.
  The traditional §(J) reading; matches every de-ID vendor's
  Safe Harbor preset.
- `Extended`: adds `crypto_address`. Deployments where wallet
  addresses can appear in patient-facing artifacts opt in.

Both tiers apply uniformly across Safe Harbor, LDS, and Expert
Determination — §(J) scope is a property of the identifier list,
not the removal method. Threaded through `hipaa::template()` and
the three per-method builders. Caller-side change is one new
`accounts` field on the wire (`#[serde(default)]` so callers
already sending `{"method": "safe_harbor"}` continue to work).

While in there, split the 800-line `hipaa.rs` into a `hipaa/`
folder — one file per posture (`safe_harbor.rs`, `limited_data_set.rs`,
`expert_determination.rs`), one file for the account-tier enum
(`account_numbers.rs`), shared items and tests in `mod.rs`. Each
posture owns its own constants and UUIDs; Expert Determination
reaches into `safe_harbor` for the shared 18-identifier label set.

New tests:

- `standard_accounts_cover_the_traditional_section_j_set` — pins
  the Standard tier.
- `extended_accounts_add_crypto_to_the_standard_set` — pins
  Extended.
- `account_tier_lands_in_every_hipaa_method` — verifies the tier
  widens every method's policy scope.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@martsokha martsokha added feat request for or implementation of a new feature template regulatory policy templates (HIPAA, GDPR, PCI DSS, CCPA) labels Aug 13, 2026
@martsokha martsokha self-assigned this Aug 13, 2026
@martsokha
martsokha merged commit 20662c6 into main Aug 13, 2026
8 checks passed
@martsokha
martsokha deleted the fix/hipaa-section-j-account-labels branch August 13, 2026 16:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feat request for or implementation of a new feature template regulatory policy templates (HIPAA, GDPR, PCI DSS, CCPA)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant