Masked account-number rule contract
Status: 0.5.0-beta.2 draft; not released. This is the masked-account slice of D2 / #144, stacked on the labelled account rule in #159. Street addresses and masked non-account entity types remain outside this slice.Supported formats and ranges
Use the existing canonicalACCOUNT_NUMBER type and
datafog-core/account-number provenance for two explicit text forms:
account ending in 1234,acct ending in 1234, or one of the existing full account-number labels (account number,account no.,acct number,acct no.) followed byending in 1234. Match exactly four ASCII suffix digits; retainending inoutside the value span.- An existing full account-number label and delimiter followed by 4–12 copies
of ASCII X (case insensitive) or 4–12 asterisks, immediately followed by four
ASCII digits:
account number: XXXX1234oracct no.#****1234. Match the whole visible masked token, including its mask characters. Mixed X/asterisk masks, grouped masks, other mask symbols and longer/shorter tokens are excluded.
Exclusions
Bareending in 1234, XXXX1234 and ****1234 have insufficient entity context.
Credit-card, phone, SSN, invoice and reference labels do not activate this account
rule. Intervening prose, unsupported labels such as account ends in, Unicode
suffix digits, mixed masks and code-style forms such as account_number = XXXX1234 are excluded. This is a lexical rule, not a general code/Markdown
exemption: a supported literal account phrase inside a code block still matches.
Structured field keys do not supply text context or cross field boundaries.
Three negatives from #159 intentionally become positives in this slice:
account-number-suffix-only (account ending in 1234, value 1234),
account-number-x-masked (account number: XXXX1234, value XXXX1234) and
account-number-star-masked (account number: ****1234, value ****1234).
Their acceptance data is updated explicitly; the original contiguous-number
formats and every other earlier negative keep their behavior.
Literal identity and model compatibility
A suffix is not a full account identity. Do not reconstruct digits, equate it with a full number, or promise account-level deduplication or recall. Workspace identity continues to use the observed entity type plus its existing normalized literal text. Equal literal suffixes can reuse an alias even if they came from different real accounts;1234, XXXX1234 and 00121234 remain different
literal identities. X-case normalization follows existing workspace behavior.
Restoration returns the observed literal, not hidden information.
No workspace identity, recall or source-precedence policy changes here. The
partial account rule from #159 still runs alongside a configured account model;
it does not take ownership of the model’s broader account coverage. Normal
selection, exact/regex allowlists and all existing transformation strategies
apply to the observed value span.
Proof
fixtures/masked-account-number.jsonl contains synthetic supported examples and
hard negatives with exact offsets and transformation expectations. Core and
installed Python, Node and real browser WASM consume the same cases. Verify
byte/codepoint/UTF-16 offsets, selection, allowlists, structured boundaries,
provider-backed round trips, literal workspace identity and retained model
routing. Run the required rule checks, SDK smoke, live parity and regression
evaluation without weakening existing thresholds. These fixtures do not qualify
model inference. #144 remains open for the separately scoped street-address rule.
Local impact measurement
On macOS ARM64 with Node 24.18.0, all 76 short masked fixture texts scanned 1,000 times each after warmup averaged 0.54 µs on #159 and 1.12 µs with the new coverage. The latter also returns the new findings; this uncontrolled local measurement is not a stable benchmark claim. Release WASM size changed from 2,458,647 to 2,457,641 bytes. The ordinarycargo dfv bench report is the separate performance
gate.