Skip to content

feat(eligibility): API-first 270/271 eligibility waterfall (Stedi client, payer route map, document-hash verified artifacts)#147

Draft
abrichr wants to merge 1 commit into
mainfrom
feat/eligibility-api-first-spike
Draft

feat(eligibility): API-first 270/271 eligibility waterfall (Stedi client, payer route map, document-hash verified artifacts)#147
abrichr wants to merge 1 commit into
mainfrom
feat/eligibility-api-first-spike

Conversation

@abrichr

@abrichr abrichr commented Jul 18, 2026

Copy link
Copy Markdown
Member

What

The API-first eligibility spike for the dental offer: a working EDI 270/271 eligibility-check path through a clearinghouse API (Stedi), integrated as a flow-idiomatic component with effect verification — so eligibility checks hit the sanctioned API route where one exists and portal replay becomes the fallback.

New package openadapt_flow/eligibility/ (import-light, not on the replay hot path; no new dependencies — httpx and PyYAML are already core):

  • client.pyStediEligibilityClient against Stedi's documented real-time 270/271 JSON endpoint (Authorization: Key header, tradingPartnerServiceId/subscriber/encounter.serviceTypeCodes request, benefitsInformation/AAA-error response). Normalized EligibilityResult (active/inactive, plan name, copay/coinsurance/deductible/OOP-max where present) with the raw 271 retained plus its SHA-256 wire digest. parse_271 fails closed: a malformed or signal-free response is indeterminate, never a guessed benefits answer. Secret-isolated auth per the effect kit's convention (env-var references via AuthRef or STEDI_API_KEY; construction fails loud when absent; the key never enters results, reasons, or artifacts).
  • waterfall.py + payer_routes.yaml — the waterfall seam: a committed per-payer capability map (payer → api | portal | excluded) and resolve_route/run_waterfall so the fulfillment loop picks the route automatically. The six confirmed-covered dental payers route api-first; Availity is excluded + portal_banned (scraping contractually barred) with the sanctioned-API conversion path documented; unknown payers default honestly to portal. Fallback rule is explicit: a 270 is an idempotent read, so a no-answer API attempt may fall through to the portal tier — the opposite of the write-path ApiActuator's HALT rule — except when the portal is banned, in which case the check lands in the practice queue.
  • artifact.py — the API result lands in the same practice-local results artifact set as a portal replay (appended eligibility_results.csv row + the raw 271 written byte-exact as 271_<digest16>.json) and is certified by the kit's document-hash verifier: exactly one raw-271 document (record_written) whose bytes hash to the wire digest (field_equals on sha256). The CSV row carries the digest, so every benefits answer traces to the exact 271 that produced it. Effect verification is source-agnostic — the halt-instead-of-guess wedge governs the artifact whether a portal, an API, or a human produced it.
  • docs/ELIGIBILITY_API_WATERFALL.md — the waterfall design, the practice-held-account/click-through-BAA deployment model, per-check cost ($0.30 tapering to $0.08, mocks free), practice activation steps, the ADA weak-tail caveat, and the documented backup clearinghouse (pVerify; Availity Essentials API for Availity-locked payers).

Honest proof status

Contract-proven, not live-proven. The client is built against Stedi's public docs (fetched 2026-07-18, including their published dental mock catalog — Ameritas / Anthem / Cigna / MetLife / UHC Dental, service type code 35). CI proves parsing, fail-closed behavior, routing, secret isolation, and the artifact write+verify roundtrip against faithful local fakes of those documented shapes. A live smoke test (tests/test_eligibility_live_stedi.py) runs Stedi's own dental mock end-to-end and is env-gated on STEDI_API_KEY with a precise skip reason — Stedi's test mode is self-serve and mock checks are free, so the first run with a real test key graduates the mocked path to live-proven. Only doc-verified payer IDs are committed (cigna_dental: 62308, from Stedi's own mock catalog); all others are null with verified: false and resolved from Stedi's payer directory at enrollment.

Tests

34 new tests (33 run + 1 env-gated live skip): documented-shape fakes for active/inactive/AAA-42/AAA-75/AAA-43/payer-not-supported/malformed (fail-closed), request-shape and Authorization: Key header assertions via httpx.MockTransport, missing-env fails loud, secret never serialized, registry contents + alias/case-insensitive resolution + malformed-registry fail-loud, waterfall fallback rules (including portal-banned → queue and portal-route-needs-no-key), artifact write+verify roundtrip, tamper → REFUTED, duplicate write refused.

ruff check, ruff format --check, mypy, and the full non-e2e unit suite are green locally. Frozen lanes untouched — the diff is purely additive (no existing file modified).

🤖 Generated with Claude Code

…ent, payer route map, document-hash verified artifacts)

The API tier of the dental eligibility offer: where a payer exposes a
sanctioned real-time 270/271 route through a clearinghouse API, the check
hits that route first and compiled portal replay becomes the fallback.

- eligibility/client.py: StediEligibilityClient against Stedi's documented
  JSON endpoint (Authorization: Key header, tradingPartnerServiceId /
  subscriber / encounter.serviceTypeCodes request, benefitsInformation +
  AAA-error response). Normalized EligibilityResult with the raw 271
  retained byte-exact plus its SHA-256 wire digest. parse_271 fails
  CLOSED: malformed or signal-free responses are indeterminate, never a
  guessed benefits answer. Secret-isolated auth per the effect kit
  convention (env-var references only; construction fails loud).
- eligibility/waterfall.py + payer_routes.yaml: the committed per-payer
  capability map (payer -> api | portal | excluded) and the resolver the
  fulfillment loop calls, so route choice is reviewed data, not code.
  Six confirmed dental payers route api-first; Availity is excluded +
  portal_banned with the sanctioned-API conversion path documented;
  unknown payers default to portal. Fallback rule is explicit: a 270 is
  an idempotent READ so no-answer API attempts fall through safely (the
  opposite of ApiActuator's write-path HALT), except banned portals which
  land in the practice queue.
- eligibility/artifact.py: results land in the same practice-local
  artifact set as portal replay (eligibility_results.csv row + byte-exact
  271_<digest16>.json) and are certified by the document-hash verifier
  (record_written + sha256 field_equals against the wire digest) --
  effect verification is source-agnostic.
- docs/ELIGIBILITY_API_WATERFALL.md: honest proof labels
  (contract-proven vs live-proven), practice-held account / click-through
  BAA model, per-check cost, activation steps, backup clearinghouse.

Contract-proven against faithful fakes of Stedi's documented shapes
(including their published dental mock catalog); an env-gated live smoke
test (STEDI_API_KEY, test mode, mock checks are free) graduates the
mocked path to live-proven. Purely additive: no existing file modified,
no new dependencies (httpx and PyYAML are already core), nothing on the
replay hot path.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@abrichr
abrichr marked this pull request as draft July 18, 2026 19:10
@abrichr

abrichr commented Jul 18, 2026

Copy link
Copy Markdown
Member Author

Holding this PR in draft after independent review. The API-first eligibility thesis is sound, but this exact implementation is a contract spike rather than a safe production fulfillment path.

Before it can return to ready:

  1. Rebase onto the independently verified 1.14.1 release boundary.
  2. Bind the reviewed payer route to the exact payer ID sent on the request; unknown or unverified routing must queue/halt.
  3. Parse benefits by requested service type, service date, network, coverage level, and time period; mixed or ambiguous entries must not collapse to an unrelated “active” answer.
  4. Distinguish credential/configuration errors, invalid payer/request errors, throttling, and transient payer failures. Only explicitly transient cases may retry or fall back.
  5. Stage and atomically verify both the raw response and the exact practice-facing normalized result before either is promoted as consumable.
  6. Put raw 271/member data behind an explicit PHI-bearing local storage, encryption, retention, and egress boundary.
  7. Add atomic/locked/symlink-safe artifact writes, spreadsheet-formula neutralization, endpoint allowlisting, response-size limits, and bounded concurrency/retry behavior.
  8. Integrate one exact partner/practice workflow and run at least three live test-mode trials before making product claims.

Current CI is green and the code appears MIT-compatible; the hold is about silent-wrong-answer, PHI, effect-verification, and fulfillment completeness—not general code quality.

@abrichr

abrichr commented Jul 19, 2026

Copy link
Copy Markdown
Member Author

Status refresh (2026-07-19): the MIT-only release boundary is restored, so the remaining hold is the production contract described above. This stays a useful API-first spike but not a merge candidate until exact payer routing, benefit/time/network interpretation, error taxonomy, atomic normalized/raw artifacts, PHI retention/egress, and >=3 effect-oracled integration trials are implemented on current released main. The staff-first attended path and UI execution layer remain the launch critical path; this PR should integrate with them if resumed, not become a parallel fulfillment runtime.

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