Repository navigation
bench: a public Medplum benchmark vendors can run with their own agent - #1652
Merged
Merged
Conversation
openadapt bench medplum --agent <scripted|claude|cmd:...|py:...> brings up Medplum (Apache-2.0) on loopback and runs 31 cases written for this benchmark across Patient, AllergyIntolerance and Appointment writes. A proxy between the agent and the server injects write-path faults; an oracle reads the whole server before and after. The scorecard compares the agent's claim, a read-back of the named record, and OpenAdapt's ensure_record verifier: harms caught and missed, false stops, and person minutes with the fair test's cost file. ensure_record gains an instant comparison (one moment however it is written) and list filters with a dotted key and a starts-with match, so an Appointment's patient and practitioner participants are read apart.
- The OpenAdapt judge now gates the agent's claim, as the read-back does; the verifier alone is a fourth column. - Cases the verifier couldn't read, or whose fault never did what it describes (the agent never wrote, a search used up the fault, a mutation that changed nothing), are left out and listed. - The proxy skips _search and $operations, rewrites the server's links to itself, and records whether each fault was delivered. - P10 untouched is a right stop (120 s), not a caught harm. - A +1 country code is the same phone number to the oracle. - Six cases: three clean tasks without the element hint, a fake 201, a wrong patient on an appointment, and another user editing the same patient as the agent writes. - Per-class counts; more types in the oracle's snapshot and the sweep; the read-back parses Type/id/_history/n; the early stop is reported.
…, not searched find_matches put every identity value into the search, so a rule whose value has no search parameter (an allergy's substance code) raised KeyError. The search now uses the rule's searchable values and the contract compares the rest. The bench runner records any case crash as that case's error.
…rescore command The --down cleanup reused the agent's name variable, so the scorecard said 'clients.json'. Adds the scripted run and the timed cold run (5.2 minutes from clone to scorecard, images already pulled).
…ed cold run Claude Sonnet 5.5, 37 cases, $1.22: OpenAdapt missed 1 of 9 harms (A10, written after the check) against 8 missed by the agent's claim and the read-back, and stopped 9 records Claude had already corrected with a PUT after reading the changed value back (its contract allows a create and no later change). A cold run of the README took 5 min 12 s from clone to scorecard.
abrichr
marked this pull request as ready for review
October 29, 2026 15:55
abrichr
marked this pull request as draft
October 29, 2026 15:56
abrichr
marked this pull request as ready for review
October 29, 2026 15:57
…ublic artifact inventory Regenerated with check_release_consistency.py --write-public-artifact-inventory and reviewed: seven files, all synthetic and public by design (the case set, the three ensure-record contracts, and three runs' results with no tokens, local paths or private-set material).
Member
Author
Adversarial review of the case set and the scorecard mathsAn independent reviewer read the code, not this PR's conclusions, before any live run. It found no blocker. It raised 8 should-fix items, 3 of which tilted the comparison toward OpenAdapt, plus minor items. Dispositions are in commit
The verifier change (instant compare, prefix filter, leaf counting) was judged fail-closed. Open-core and licensing checks were clean. The live run then found one more verifier bug (an identity value with no search parameter raised |
abrichr
enabled auto-merge (squash)
October 29, 2026 16:49
…nd A10 as a one-time check's limit
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.
What this adds
openadapt bench medplum --agent <scripted|claude|cmd:...|py:...>is a public benchmark that a vendor reruns with their own agent. It runs against a local Medplum (Apache-2.0, pinned by digest, loopback only, synthetic people).packages/flow/benchmark/fhir_medplum/public/cases.yaml), written for this benchmark, across Patient, AllergyIntolerance and Appointment writes:ensure_recordverifier;costs_2.json, with a per-class breakdown.Results (RESULTS.md)
Claude Sonnet 5.5 ($1.22, 20 min):
Scripted agent: OpenAdapt missed 1 of 18 harms; the read-back missed 8.
Cold run of the README by a subagent with no context: 5 min 12 s from clone to scorecard, with the images already pulled.
Verifier changes (
ensure_record,effects/fhir.py)instantcomparison.^=, which read an Appointment's patient and practitioner participants apart.None.KeyError; the live run found this.Review
An adversarial review of the fault set and the scorecard maths ran before the live runs. All eight of its should-fix items, and most of the minor ones, are addressed in
bench(medplum): address the adversarial review. Its open-core and licensing checks found nothing; the one phone number it shared with a private set has been changed.Tests
packages/flow/tests/test_bench_medplum_public.pytests/test_bench_medplum_command.pytest_ensure_record.pyandtest_fhir_extract_path_filter.py