ADR-0079 — A date of birth one keying error away is not a contradiction¶
- Status: Accepted
- Date: 2026-10-12
- Spec version at acceptance: 0.81
- Issues: none — a maintainer decision of 2026-10-11, raised in PR #749's review; decisions 3 and 4 revised by the maintainer in PR #758's review (2026-10-12), before acceptance
- Relates to: ADR-0014 (the comparator contract this extends) · ADR-0078 (the skip rule that decides whether a recovered pair is shown)
- Design:
docs/superpowers/specs/2026-10-11-dob-near-miss-design.md
Context¶
The matcher's DOB comparator graded any differing digit DISAGREE, weighted −4. A pair with no shared
identifier cannot absorb that: two charts of "Mary Smith, F" whose DOBs differ by one keying error score
name +5, DOB −4, sex +1 = 2 (base weights; provenance only scales them down), below the review floor
(3.0). So if a clerk overwrites one chart's DOB with a day/month swap (7 January → 1 July 1950) while
"verifying" it against a letter, the matcher's re-check withdraws an auto-link candidate that nobody has
seen, and the chart a ward prescribes on carries neither the warfarin nor the penicillin allergy on the
other.
The maintainer first asked that a shared first name or surname with a DOB within a year and a day be presented as a possible match. Measured on the synthetic Australian name population with an ABS age pyramid, that rule produces about 0.2 false proposals per registration at 10 000 charts and about 2 at 100 000. It was declined in favour of the targeted rule below, once the scenarios were scored: a changed surname or first name with an exact DOB already scores 5 at full provenance and reaches review; the gap is the keying error.
Decision¶
- A new agreement level,
NEAR, betweenDISAGREEandPARTIAL. Levels are persisted by name, so inserting it renumbers nothing stored. compare_dobgradesNEARwhen two full-precision point dates (year, month and day on both sides, each a date on the calendar — no 30 February, no 29 February outside a leap year, no year 0) differ by exactly one keying error, named — first match wins — as "one digit differs", "adjacent digits swapped" (read inYYYYMMDDorder, so a swap across the year/month boundary counts and one across a day-first entry's day/month boundary does not), "day and month swapped" (same year), or "years one apart" (same day and month, across a carry such as 1959 → 1960; 1950 → 1951 is already "one digit differs"). Every other difference is stillDISAGREE; year-only and year-month precisions and §5.4 year ranges are unchanged.- The default weights price
NEARat +2 — weak evidence for a match, far short of an exact DOB (+6): the digits fit one person and a typo, and a one-keystroke miss is rare between strangers. A weights table without the key prices it at 0.0. A learned table may price it otherwise: decision 4 keeps any positive price from auto-linking, but a negative one would hide these pairs again, so a learned table must be checked for that before the pipeline loads one (#765). - A DOB in doubt — graded
NEARorDISAGREE— forbidsAUTO_CANDIDATE, as a veto does: a human decides which DOB is right, which is also when the wrong one gets corrected.DISAGREEneeds this as much asNEAR, because db/016's DOB veto fires only when both DOBs are verified; without it an unverified DOB that differs outright could still auto-link on a shared identifier and an agreeing name (identifier 4 + name 5 + sex 1 − DOB 2 = 8: every identifier currently scores at half its weight of 8, and a DOB at unknown provenance at half its −4) while one a single keystroke off could not. Unlike a veto it does not trigger the below-threshold rescue. For the §5.4 unconfirmed-chart gateNEARis neither corroboration nor a clash. - The proposal says why: a proposal whose DOB was scored
NEARcarries an evidence entry{"kind": "dob_near_miss", "pattern": <the name above>}— derived from the scored level, never a second reading of the dates, so it cannot contradict the DOB row.patternisnullwhen a locale comparator gradedNEARon an error the default profile does not name. - A blocking pass,
name+monthday— a name token with theMM-DDof a day-precision ISO DOB — so a year keying error on a common name is generated at all: the cappednameblock drops such names at scale, and every other DOB-keyed pass needs the same year. On ASCII input its key reads the grammar the scorer parses at day precision (four year digits, a month 1–12 and a day 1–31, unpadded allowed, surrounding ASCII whitespace ignored), so a DOB the scorer can grade is not withheld from it. The scorer also reads a DOB written in another script's digits, which the key does not: such a DOB misses this one pass, never its score. - This is the default comparator profile's behaviour, not core policy. Day/month swaps are a culture-dependent hazard (day-first vs month-first entry); a locale pack may grade differently (ADR-0014).
Consequences¶
- Measured on the matcher's synthetic evaluation set (
eval.generate --entities 2000 --seed 7, whose generator injects DOB typos), against the previous matcher: - Scoring: of 2 000 true duplicates, unproposed fell from 351 to 266 (
missed_match_rate0.175 → 0.133), all 85 recovered into review; auto-links unchanged at 594, and false auto-links unchanged at 1 (auto_false_link_rate0.002). False review proposals rose by 191, against 81 362 already produced when every pair is scored without blocking (7 996 000 non-matching pairs). - Blocking: true duplicates never generated fell from 175 to 136 (
pair_completeness0.912 → 0.932), for 1.3% more candidate pairs (82 331 → 83 369) and no new oversized block (455 either way). - The matcher's package version moves to 0.2.0, so
matcher_versionchanges and every node re-queues every chart once for a re-check (db/056's'config'notice). That re-scan is also the backfill: pairs like the one in the Context return to the worklist. - A changed surname and a DOB keying error together still score below the floor (−2 + 2 + 1 = 1). Declined by the maintainer for its noise (~0.08 false proposals per registration at 100 000 charts); revisit with real adjudication data if missed duplicates of that shape appear.
- A middle name recorded on one chart only, with a DOB keying error, reaches review only at full provenance (0 + 2 + 1 = 3.0), because the default weights price a partial name agreement at 0; a one-letter surname variant (Smith/Smyth) grades as a name disagreement. Both are name-side limits (#762).
- The false-proposal estimate was taken on a name population that produces few namesakes; it is owed a re-measure on the ABS-modelled population with diagnoses, including birth dates assigned as 1 January or 1 July (#760).
- The proposal records the pattern; the worklist and banner do not yet show it. That sentence, and its timed walk, are a follow-up (#759). The search ranker keeps its own, narrower near-miss rule (#764).
- No wire change, no schema change, no new event type: this is the advisory matcher only.
Rejected¶
- The maintainer's first rule (shared first or surname, DOB within a year and a day): about 2 false proposals per registration at 100 000 charts, about 20 at a million-chart hub.
- Reusing
PARTIAL(+1.5): it conflates a consistent coarsening (1950 vs 1950-03-12) with conflicting digits, and does not cap at review. - Keeping −4 and adding a banding rescue: the evidence would still show the DOB as a −4 contradiction while the band said otherwise — two places encoding one fact.
- Pricing
NEARat 0.0 (this ADR's first draft): a typo-close DOB beside a partially recorded name still fell below the floor, and 0.0 under-reads how rarely strangers' DOBs sit one keystroke apart. - Capping only
NEARat review: ranked a DOB one keystroke off below one that differs outright. - Also surfacing the changed-surname-and-typo case: declined by the maintainer (above).