Skip to main content
All case studies
HealthcareCompleted

Patient Matching When the API Contract Is Ambiguous

A de-identified field pattern for containing patient-match risk when filter and mode parameters interact in undocumented ways.

Published
Materially updated
Reading time
5 min read
Context
De-identified field experience

Evidence at a glance

Context markers for the implementation. Measurement windows, caveats, and remaining gaps are documented in the study.

Observed Conflict
2 parameters
a score filter and best-match mode with unclear precedence
Auto-link Policy
Fail closed
reject or review candidates that fail local invariants
Regression Proof
Pinned fixtures
record request shape, response shape, and the expected local decision

Implementation stack

Backend

  • REST API
  • Go

Database

  • PostgreSQL

Monitoring

  • Prometheus

Patient matching is a bad place for an implicit contract. A false positive can associate activity with the wrong chart. A false negative creates duplicates and manual reconciliation. An ambiguous response can do either while looking technically successful.

This case study describes a de-identified failure pattern I encountered from both sides of an API boundary. A patient-search endpoint accepted a minimum-score filter and a “return best matches” mode. When both were present, the mode could return candidates below the requested threshold.

The durable fix was not a smarter guess about upstream behavior. It was a local decision boundary with contract fixtures, constrained auto-linking, review for uncertain cases, and instrumentation that could show which rule ran.

TL;DR

  • If a filter and a mode can conflict, the API needs an explicit precedence rule.
  • Treat a vendor score as a signal, not authorization to link records.
  • Apply local invariants before any irreversible action. If required evidence is missing or contradictory, fail closed or send the case to review.
  • Pin the ambiguous behavior in contract fixtures so a documentation gap becomes an executable regression check.
  • I removed the old 99% accuracy, two-million-calls-per-month, 75% debug-time reduction, 15 ms latency, and storage-cost claims. There is no shareable measurement set here that can reproduce them.

Context and evidence

This is a de-identified field retrospective, not a public benchmark or a claim about a named client or vendor. The parameter names are retained because they make the contract problem concrete:

  • minscore appeared to define a lower acceptance threshold; and
  • returnbestmatches selected a broader best-match mode.

The observed behavior was that enabling the mode could return candidates below minscore. I do not have a public vendor contract, source repository, labeled patient corpus, or production telemetry that readers can inspect. For that reason, the outcomes below describe the containment pattern and its evidence, not an accuracy or performance result.

The challenge

The endpoint returned a valid response. The ambiguity was semantic: which parameter owned the final candidate set?

Diagram comparing filter-first patient matching with mode-override behavior where best-match mode can return candidates below the requested minimum score.
Figure 1. A filter and a mode need an explicit precedence rule; otherwise both interpretations are plausible to a consumer.

This is dangerous because status codes and schemas cannot detect it. The request is well formed, the response validates, and the wrong assumption survives until someone inspects candidate-level behavior.

Constraints

ConstraintDesign consequence
False positives carry higher harmAuto-linking needs stricter evidence than candidate retrieval.
Upstream scoring is opaqueLocal code cannot infer what a score means beyond the documented contract.
Demographic data can be incomplete or staleMissing evidence must not be treated as agreement.
Protected health information (PHI) is sensitiveLogs and fixtures need minimization, redaction, and controlled access.
The upstream contract can driftRequest and response behavior need repeatable contract checks.
Some cases remain ambiguousHuman review is a required state, not an implementation failure.

Decisions and implementation

The API can retrieve candidates. Local policy decides whether any candidate is safe to auto-link. Those are different responsibilities.

The local decision checks only reviewable invariants: whether the upstream threshold was honored, whether required identifiers agree, whether date of birth matches when policy requires it, and whether contradictory evidence is present. A candidate that fails the boundary is rejected or queued for review.

The following is illustrative pseudocode, not a drop-in clinical matching algorithm:

for candidate in response.candidates:
    if candidate.score < policy.minimum_score:
        reject(candidate, "upstream threshold not honored")
        continue

    if required_identifier_conflicts(candidate, request):
        reject(candidate, "identifier conflict")
        continue

    if required_demographic_evidence_missing(candidate, request):
        review(candidate, "insufficient evidence")
        continue

    if local_invariants_pass(candidate, request):
        allow_next_workflow_step(candidate)
    else:
        review(candidate, "ambiguous match")

The “next workflow step” may still require approval. Passing local validation is not a universal guarantee that two records identify the same person.

Turn the ambiguity into contract fixtures

The useful fixture is not only a response body. It records the complete behavior under test:

Fixture fieldWhy it matters
Endpoint and API versionPrevents a test against the wrong contract.
Request parametersCaptures the exact filter and mode combination.
Sanitized candidate responsePreserves the observed precedence behavior without copying live PHI.
Expected local decisionTests reject, review, or continue separately from retrieval.
Observation dateMakes drift and vendor changes visible.

Contract tests should include each parameter independently, both together, boundary scores, empty results, and malformed or partial candidates.

Instrument decisions, not patient details

Useful telemetry answers:

  • Which request mode was used?
  • Did any returned candidate violate the requested threshold?
  • Which local rule produced reject, review, or continue?
  • Which API and policy version made the decision?
  • How long did the dependency and local validation take?

The metric labels should not contain names, identifiers, dates of birth, or raw response fragments. Detailed audit evidence belongs in an access-controlled store with an explicit retention policy.

Make review a first-class outcome

Binary “match/no match” interfaces encourage unsafe certainty. The local workflow uses at least three states:

  1. Reject when a hard constraint fails.
  2. Review when evidence is incomplete or contradictory.
  3. Continue when the configured local invariants pass.

Reviewer decisions can improve policy, but they should not silently train or change production behavior. Any rule change needs versioning and validation against an approved, representative set.

Outcomes and measurement context

The unsafe assumption became an explicit invariant

The integration no longer depended on minscore being honored implicitly. It verified the threshold on every candidate before the local workflow could continue.

The documentation gap became reproducible

A pinned fixture could demonstrate the parameter interaction without repeatedly querying production or relying on memory. That gave API owners and consumers a concrete artifact to discuss.

Ambiguity gained a safe destination

Candidates with missing or conflicting evidence moved to review instead of being forced through an auto-link path. This is a workflow outcome; without a labeled corpus and adjudication protocol, it is not an accuracy percentage.

Operational signals became actionable

Threshold-violation counts, decision reasons, API versions, and latency distributions can reveal drift. The study does not publish values because the underlying telemetry is private and the original figures were not reproducible.

Limits and open work

  • Local validation cannot repair a poor upstream candidate generator. It can only constrain downstream action.
  • Exact demographic matches are not sufficient proof of identity, and missing data is common.
  • Thresholds require validation against a representative, labeled population with clinical and governance oversight.
  • A manual queue needs ownership, audit rules, service expectations, and a path for urgent cases.
  • De-identification limits how much evidence this public write-up can provide. That is preferable to implying false precision.

Takeaways

  1. Document precedence, not just parameters. A truth table is often clearer than two independent descriptions.
  2. Separate candidate retrieval from record linking. The upstream score should not directly authorize an irreversible action.
  3. Fail closed on missing evidence. “The API returned it” is not a matching invariant.
  4. Make ambiguity executable. Fixtures turn a support anecdote into a regression test.
  5. Measure with a labeled set or do not claim accuracy. Directional percentages without a cohort, denominator, and adjudication method are not evidence.

The related patient-matching field note covers the narrative side of the same contract failure.

Working through a similar constraint?

I am happy to compare implementation notes, tradeoffs, and the evidence you would want before shipping.

Patient Matching When the API Contract Is Ambiguous | Case Study | FlexInfer