Repository navigation
ensure_record: check an ensure-patient write on Medplum through FHIR and its audit trail only - #1640
Merged
Merged
Conversation
…itEvent and _history (WIP)
…frozen for the blind run The verifier now closes the change window at a server instant and reads the audit trail until two reads agree (Medplum writes AuditEvents up to ~0.1 s after the save), checks the created record holds nothing the task didn't give (closed), keeps a found record found when another user edits it, and takes attribution from the audit trail alone where the server returns no meta.author. The fixture now runs in a project of its own (Medplum's seeded project is Super Admin) and can make the audit trail read-only to the agent: a plain member can create, change and delete AuditEvents, unlogged.
…t for found records Blind round 1 on Medplum (suite 5c1742e8, verifier 7059004): 17 of 18 right. The miss passed a record that stored the state as "Massachusetts" because the Massachusetts->MA map was applied to the stored value too. With saveAuditEvents off Medplum answers an empty AuditEvent search, so an empty window proves nothing; a found record now counts only when the verifier's own read of it shows up in the trail.
A found record now needs no other record to be the person afterwards; a last read with no end catches an agent write that landed after the window closed; identity reads every name and telecom entry, with candidates from each value searched alone; the heartbeat is on by default; an operation (action E) counts as a write and an unknown action is unreadable; the closed record expects only the fields the task gave and counts meta.security and meta.tag; actor references compare as Type/id. REVIEW.md records each finding and what changed.
# Conflicts: # CAPABILITIES.md # llms-full.txt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Checks an agent's
ensure_patient_registeredwrite on Medplum through the FHIR read path only (searches,AuditEvent,_history), never the database. The verifier,openadapt_flow.ensure_record, gives one of three outcomes:found_existingwith the id,created_verifiedwith the id, orneeds_reviewwith the reasons. The agent's own report doesn't count.What's here
openadapt_flow/ensure_record.pyand 43 tests: theopenadapt.ensure-record/v1contract, a reader that fails closed on any incomplete read, and the judgment.active=true.benchmark/fhir_medplum/readpath/ensure_patient.yaml: the contract. generate-parts: the app-specific parts of a workflow, generated and verified #1520'sgenerate-parts(generator13e2cbdb5, run from its branch) wrote 14 of its 30 lines from three demonstrations of Medplum's new-patient form;generated/holds its output. A person wrote or corrected 16 lines, each markedHAND.probe.pyandprobe.json: what Medplum 5.2.8's read path shows, measured live.RESULTS.md,MINUTES.md, anddocs/ENSURE_RECORD.md(the coverage limits).restrict_agentmakes the audit trail read-only to the agent;Results
Separate agents wrote each fault suite from one brief, without seeing the verifier, and froze it by sha256. The suites and per-case results are private.
5c1742e8(18 cases)705900415803b34c6(20 cases)2efc74000153d7899(20 cases)5ce6e6b26Not blind, for reference: rounds 1 and 2 rerun at
5ce6e6b26scored 18 of 18 and 20 of 20.Round 1's miss: a state stored as "Massachusetts" passed, because the Massachusetts-to-MA map was also applied to the stored value. Fixed.
Round 2's three misses: clean records carrying
active: truewere sent to review.Round 3's miss: a clean record carrying optional
usecodes was sent to review. The contract was left as it was, so the number stays blind.Across rounds 2 and 3, no fault was passed as verified: 0 of 31. Of the 9 clean runs, 5 were judged right; the other 4 were sent to review for an element the task didn't give.
Coverage: name the read path
This read path sees the creates, updates and deletes made through the FHIR API that the server logs as AuditEvents, with who made each. On Medplum 5.2.8 that includes batches, transactions and GraphQL mutations (probed). It doesn't see:
So a coverage claim reads "no other write through the FHIR API, as logged by AuditEvent". The verifier's evidence also depends on how the deployment is set up. Medplum lets a plain member create, change and delete AuditEvents without logging it, so the agent needs an access policy that makes AuditEvent read-only (probed: then refused with 403). It also needs
saveAuditEventson, and must not be an administrator. The suite runner checks the policy and the administrator flags before the first case.Minutes, against OpenEMR
Both columns are agent wall-clock, not a person's hours: an agent did the work both times, and OpenEMR has no hours ledger.
Adversarial review
A separate agent reviewed the branch at
cb849fc56and demonstrated six fail-open defects, among them:All are fixed in
42779eca4, each with a regression test.REVIEW.mdlists every finding and what changed. These fixes came after the blind rounds, so the table above describes the verifier before them. Rerun live on the fixed verifier (not blind): 18 of 18, 20 of 20 and 19 of 20, no fault passed as verified; round 3's miss is the sameuse-code case. The first rerun also found a harness fault, fixed in the runner: its pause after setup was shorter than the window's 2 s lead, so the first case read the runner's own setup write (RESULTS.md).#1520 doesn't need to land first. Its generator ran from its own branch, and this PR commits the generated output and the generator's sha.