ADR-0075 — The step-3 prompt is a nudge, not a completeness claim¶
- Status: Accepted
- Date: 2026-09-26
- Spec version at acceptance: 0.77
- Issues: #671 · filed: #679 · #680 · #681 (the repair path)
- Relates to: ADR-0061 · ADR-0060 · ADR-0014
- Amends: nothing in the wire or the floor. It retires one condition from the funnel design
(
docs/superpowers/specs/2026-09-20-registration-search-funnel-ui-design.md, Risks) and restores ADR-0061's meaning ofsearch.incompletewhere the reference UI had widened it.
Context¶
The registration funnel's step-3 prompt shows at most PROMPT_CAP (5) candidates, and the new chart's
birth act signs exactly those as search.displayed (ADR-0061). The funnel design assumed a
full-name-plus-DOB search returns few candidates, and set its own revisit condition: if the prompt is
routinely incomplete, the cap is wrong.
Slice 2c measured it over 50,000 real names
(cairn-gui/cairn-gui-tauri/results/2026-09-23-funnel-prompt-truncation.md). db/046 is a disjunction —
any name token OR the exact DOB — so a search returns a median of ~100 candidates, and because
bound_for_prompt OR-ed display truncation into incomplete, 92% of registrations signed
incomplete: true. A flag that is nearly always on tells a later reader nothing.
The measurement also showed the limits of any prompt:
- ranked by passes matched, an exactly-typed duplicate is first in 500/500 searches;
- a duplicate typed with a wrong date of birth is shown in 100/500, ranked or not — it matches the name pass alone, which ties with every namesake;
- a duplicate with a typo in a name token loses that token's match, so it can be found only through its other keys (the remaining name tokens, an exact DOB) — and a name with every token misspelt is not found at all.
The obvious fix — show every "strong" candidate and sign that the weak remainder was withheld by rule — would have withheld exactly the wrong-DOB duplicate, and would still have left the prompt claiming a completeness it cannot have.
The maintainer's clinical judgement settled the direction: duplicate registration is common, most often from typos in hard-to-spell names; the person at the desk cannot be made to browse a long list when they only want to open or create a chart; and people do the right thing most of the time as long as a mistake has no serious consequence. The practical answer is to accept that duplicates happen and make repairing them easy and safe.
Decisions¶
1. The step-3 prompt is a best-effort nudge, and truncation is its normal state¶
It shows the closest few charts to what was typed. It does not claim to show every candidate, and it is never a gate (the trigger stays advisory, as before). The funnel design's "if it is routinely incomplete, the cap is wrong" condition is retired: a cap that truncates is working as designed.
This is the same stance §5.8 already takes — finding candidates is advisory, a miss is a false split (§5.2's safe direction) — carried through to what the prompt signs.
2. The safety measure is how fast a duplicate is FOUND, not whether the clerk looked¶
A duplicate is repaired by an auditable, reversible link with no data loss (principle 2; §5.7). What
the link cannot repair is anything that happened in the window before it — an allergy recorded on
chart A while a drug is charted on duplicate B. So effort goes into shortening that window: a
commit-time local duplicate check by the advisory §5.2 matcher, a duplicate worklist, and a link
gesture that is fast and safe. Those are future slices, filed with this ADR as
#679 (commit-time check),
#680 (worklist) and
#681 (link gesture); nothing here builds them. Until they exist, the backstop is the hub sweep (ADR-0014), which an isolated node may not
reach for a long time — an honest, stated gap.
3. search.incomplete means the SEARCH was partial — ADR-0061's meaning, restored¶
ADR-0061 defined it: "if the node could not read some candidate it found, the attestation says so."
The reference UI's bound_for_prompt additionally set it whenever the prompt cut the list. From this
ADR on it does not: display truncation is not an incompleteness of the search, and the attestation's
displayed array — literally true, the ids on screen in order — already states what was shown.
- No wire change.
db/045requires a JSON boolean and is unchanged; so isdb/046. - Stated plainly, since a signed field's reading changes: bodies signed before 2026-09-26 by the
reference UI may carry
incomplete: truemeaning "more matched than were shown". Cairn is pre-clinical — only test fixtures and measurement corpora carry such bodies — so no clinical record is misread. A reader of an older body should treatincomplete: truefrom that UI as possibly truncation only. - ADR-0060 is not relaxed. Decision 2 (partial completion is reported, never implied) is met by
displayeditself, which claims only what was on screen, and by the on-screen line below. Decision 3 (under uncertainty, over-report) does not apply: truncation is known, not uncertain.
4. Truncation is shown, not signed¶
The prompt still tells the person at the desk that more matched — one quiet line, in the reference UI
"… the 5 closest of 103 matches, listed below; type more to narrow" — carried as a count separate from
incomplete. No signed count is added: the size of a disjunctive search (everyone sharing a token or
the birth date) means nothing to a reader years later, and ADR-0061 already rejected counts in favour of
named ids.
5. Ranking is improved where it costs nobody a step¶
The order of the prompt is the one lever that helps without asking anything of the user. It only
reorders — never adds or removes a candidate — by passes matched, then an identifier match, then
a §5.4 callsign typed whole (db/046's one way to match a callsign; how a clerk re-finds a John Doe
from a wristband), then name tokens matched (exactly or as a typed prefix of at least 3 bytes, as
db/046's name pass matches them, and never a callsign's parts), then a DOB near-miss (day/month
swapped, year ±1, the year's last two digits transposed, or the same date written in another form such
as 1980-3-7, which db/046's exact string compare misses), then exactly-matched tokens (so a prefix-only
"Annabel" never ties a typed "Ann"), then chart age. The identifier key, the callsign key, the prefix
rule and the exact-token tie-break came from this ADR's own PR review: without the identifier key and
the prefix rule, a chart found only by its identifier (a nickname and a married surname) and a chart
found by a shortened first name ("Alex" for "Alexander") both ranked with, or below, every namesake;
without the callsign key, a John Doe whose callsign was typed whole scored nothing while the
callsign's own part "ed" lifted every plain "Ed …" above it; the tie-break was needed once the prefix
rule was measured. It is advisory: a ranking computed in Rust that drifts from
db/046's SQL normalisation can only worsen the order, never lose a candidate. The measure is the rig's --perturb arms (dob, and name, both,
dob-any, both-any, added while measuring); the -any arms are the near-miss key's
controls and measure where the prompt stops helping. Measured 2026-09-26 over 50,000 real names
(cairn-gui/cairn-gui-tauri/results/2026-09-26-funnel-prompt-ranking.md): a DOB slip or a
simply wrong DOB with the name right, and a surname typo with the DOB right or slipped, are all
now shown 500/500, as are a chart found only by its typed MRN (48/500 before the review's
identifier key) and a shortened first name with a wrong DOB (499/500); a surname typo together
with a simply wrong DOB is shown 203/500, and a common full name with a wrong DOB in a twin-heavy
population 72/500. Those residues are Decision 2's. Stated limit of these figures: the rig drew
its 50,000 names from the name pool's first rows, which hold about four times the pool's share of
its commonest surnames. That over-states namesakes, so the figures are likely conservative, but they
are not yet the figures for a representative draw; the rig now draws one, and the re-run is
#685.
Consequences¶
- The attested
incompleteflag becomes a real signal again: set only when the node failed to read a candidate. - The prompt stays five rows and asks nothing more of the user.
- Duplicates are expected; the next design thread is the repair path (Decision 2).
PROMPT_CAPis unchanged, and is still named and test-pinned — it is now a layout choice, not a completeness boundary.
Rejected¶
- Show every strong candidate and sign the weak remainder as "withheld by rule" (#671's first direction): it withholds the wrong-DOB duplicate, and still claims a completeness the search cannot have.
- A signed count of candidates not shown: noise to a later reader; ADR-0061 already chose named ids over counts.
- A new signed field instead of restoring
incomplete's meaning: a second field whose only job is to contradict the first, for bodies that exist only in test fixtures. - Raising
PROMPT_CAPuntil the number looks better: a longer list is exactly what the person at the desk will not read. - Making the prompt a gate (must scroll, must confirm): fails paper-parity, and confirmation dialogs are not a safety mechanism (principle 3).