Skip to content

docs: publish a design-decisions record - #17

Merged
lintdeveloper merged 1 commit into
mainfrom
docs/design-decisions
Aug 4, 2026
Merged

docs: publish a design-decisions record#17
lintdeveloper merged 1 commit into
mainfrom
docs/design-decisions

Conversation

@lintdeveloper

Copy link
Copy Markdown
Owner

Documentation only. Independent of #16 — different files, no conflict.

What this unlocks

docs/ is now a committed directory: the local-only scratch space moved to .notes/ in .git/info/exclude. Verified that docs/ adds nothing to the published package — files is ["dist"], and npm pack --dry-run shows 0 docs/ files in the tarball.

Why

Until now the reasoning behind the load-bearing decisions lived only in JSDoc comments and commit messages. A contributor asking "why is redaction anchored on written shape rather than on the validators?" had no findable answer — and the answer is a measurement, not an opinion.

What's in it

Eight entries, each with the evidence it rests on:

  1. Format only, never existence — NUBAN's check digit is the sole real checksum
  2. A validator cannot be a detectorparseX normalizes before testing, so isPhone("Total: NGN 8,031,234,567") is true; redaction anchors on shape and uses the validator only to veto
  3. Confidence is evidence, not type — the per-detector false-positive table (100% for bare digit counts, 30% for isPhone, 0.4% for plate/passport)
  4. NUBAN is undetectable without a bank code — the residue proof, and why the same fact makes inferBanks useful while making a silent detector dishonest
  5. A replaced or tokenized identifier gets its own module — the python-stdnum precedent (de.idnr/de.stnr, in.aadhaar/in.vid) behind Tax ID vs TIN and vNIN vs NIN
  6. Cite a source, or leave it out — with the full list of what that rule has excluded: prefix 0917, Yoruba labels, Pidgin labels, plate LGA decoding, VIN hex enforcement, historic area codes
  7. detect() ordering is load-bearing — including the measured 0.09% trade behind placing fixed-line ahead of NIN
  8. Subpaths keep the main entry small — the bundle measurements, plus the constraint that redact.ts must not import the bank dataset

Plus a sources list and the known follow-ons.

The §6 list is the part I'd most want a future contributor to read. Each of those omissions looks like an oversight and is actually a decision — someone "fixing" the VIN pattern to [0-9A-F] would start rejecting real voter cards.

What I deliberately did not do

I did not move the README's <details> content here, even though freeing docs/ was originally proposed for exactly that. Those explanations sit next to the code they justify, they work on npm where clicking away from the page is a real cost, and #16 already verified them. Moving them would be churn for marginal gain.

So docs/ gets the thing that had no home — a contributor-facing design record — rather than material that already has a good one.

lint ✓   333 tests ✓   CONTRIBUTING link resolves ✓   0 docs/ files in npm tarball ✓

Changeset is patch.

The reasoning behind the load-bearing decisions lived only in JSDoc
comments and commit messages. A contributor asking why redaction anchors
on written shape rather than on the validators had no findable answer —
and the answer is a measurement, not an opinion.

docs/design-decisions.md records eight such decisions with the evidence
each rests on: format-never-existence; why a validator cannot be a
detector; the measured false-positive rate per detector; the NUBAN residue
proof and why it makes inferBanks useful but a silent detector dishonest;
the python-stdnum precedent behind Tax ID vs TIN and vNIN vs NIN; the
cite-a-source rule with the full list of what it has excluded; why
detect() ordering is load-bearing including the 0.09% trade; and the
bundle measurements behind the subpaths.

Also records what is deliberately absent and why — prefix 0917, Yoruba and
Pidgin label vocabulary, plate LGA decoding, VIN hex enforcement, historic
area codes — so a future contributor does not 'fix' one of them without
seeing the reason.

This is possible because docs/ is now a committed directory: the local-only
scratch space moved to .notes/ in .git/info/exclude. docs/ adds nothing to
the published package (files is ["dist"], verified with npm pack).

Linked from CONTRIBUTING.md.
@lintdeveloper
lintdeveloper merged commit 162eeb0 into main Aug 4, 2026
2 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