Skip to content

quickstart: --app openemr runs the three acts on a real OpenEMR - #1431

Merged
abrichr merged 17 commits into
mainfrom
feat/quickstart-openemr
Nov 10, 2026
Merged

abrichr merged 17 commits into
mainfrom
feat/quickstart-openemr

Conversation

@abrichr

@abrichr abrichr commented Oct 20, 2026

Copy link
Copy Markdown
Member

openadapt quickstart --app openemr runs the redesigned quickstart's three acts on OpenEMR 8.0.0.3, a real open-source EHR, in Docker, instead of the bundled MockMed. The default stays MockMed: no Docker, about 22 s, and its output is byte-identical (the existing snapshot passes unchanged).

What it does

  • Setup. It uses the repository's pinned OpenEMR fixture (packages/flow/benchmark/openemr_local/: pinned image digests, verified source files, a hashed SQL baseline) under its own Compose project (openadapt-quickstart-openemr, loopback ports 9741/9740). State stays in ~/.cache/openadapt/quickstart-openemr. A running copy is reused and reset to its baseline. A stopped copy is restarted. On first run it downloads the images if missing, shows progress per layer with elapsed time, installs OpenEMR, and adds synthetic API clients.
  • Act 1, show it once. The referral as it was demonstrated once in OpenEMR. This is the recorded demonstration of the certified referral bundle (qual10, clinical-write, digest ec096afa…), the same program behind the site's OpenEMR Seals (scoreboard: OpenEMR referrals r3–r6 on the certified bundle, reports redacted and under an offline Seal #1409). It was compiled with the shared duplicate rule (apply_referral_rules). The bundle and a URL-free copy of its action log are now committed under benchmark/openemr_local/referral_program/.
  • Act 2, run it. Five synthetic referrals (r3, r4, r5, r7, r8) at once, each on its own clerk account and browser process. Every run goes through the certified run path (qualify.campaign._run: the Standard run gate under clinical-write, a governed authorization, durable, settled, verify.yaml's REST record check). Each is then read back with SQL, 12 of 12 fields: "✓ checked in OpenEMR's record".
  • Act 3, break it. It adds an existing chart (Rosa Delgado, born 1958-03-27), then runs the r6 referral (Rosa Delgado, born 1958-03-22). OpenEMR's duplicate check lists the match, and the program stops before saving: "Stopped before saving: possible duplicate", HALTED_BEFORE_EFFECT. SQL counts 0 new charts. The terminal shows the dialog's screenshot on terminals that draw images.
  • Finale. The same receipt card and Seal, plus Published Seals: https://openadapt.ai/seals.
  • No Docker, or not run from a clone: one line on stderr saying what's missing and how to fix it, exit 2. It never falls back to MockMed.

Why the certified bundle and not a fresh recording

A fresh record-and-compile on this fixture took 66 s plus 68 s, and the result fails the clinical-write policy: 9 violations, which only qualification's reviewed overrides clear. Run without certification, a fresh bundle runs under the demo profile and can't report VERIFIED. The honest options were to qualify on every run (about 10 min) or to run the certified program, so Act 1 replays that program's own recording.

Changes

  • openadapt/quickstart/openemr.py: the engine, the Docker/clone checks, the worker main.
  • openadapt/quickstart/scene.py: per-app words; MockMed's are unchanged.
  • story.py, view.py, workers.py, cli.py: changes to pass the scene through, plus --app.
  • packages/flow/benchmark/openemr_local/quickstart.py: the fixture subclass, bring-up, clerk sessions, the certified run.
  • referral_program/: the committed bundle and demonstration (gitleaks clean; the recording's meta.json and URLs held a sign-in token and are not committed).
  • Docs: docs/quickstart/README.md.

One finding on the way: OpenEMR's tab shell posts execute_background_services.php 10 s after sign-in, then every minute. A run that starts right after sign-in meets that request at its first step, and under load the readiness gate halts. Each clerk session now waits for that first poll before its first run. That wait is part of sign-in and counts in Act 2's time.

Tests

  • tests/test_quickstart_openemr.py: the Docker-missing, not-running and no-compose paths; the clone check; CLI exit 2 with exactly one stderr line and no MockMed fallback; the plain-output snapshot (tests/snapshots/quickstart_openemr_plain.snapshot); Act 3 wording; and test_real_openemr_quickstart, opt in with OPENADAPT_REAL_QUICKSTART_OPENEMR=1 on a machine with Docker (CI skips it).
  • packages/flow/tests/test_openemr_quickstart_driver.py: the committed program's digest, recording ID and duplicate rule; a tampered file is refused; no tokens or URLs; the bring-up paths (reused, restarted, created) with a fake runner; layer progress; checked() needs the engine and SQL to agree.

Measured wall time

To be filled in. The shared Mac hit a load average above 900 from another session's runaway openadapt --version recursion (reported to the coordinator), so no timing yet.

Not done here

  • The site copy changes only once this ships.
  • The mode runs from a clone only: the fixture is repository-only and isn't in the wheel.

🤖 Generated with Claude Code

abrichr and others added 10 commits October 20, 2026 12:28
openadapt quickstart --app openemr runs the same story on OpenEMR 8.0.0.3
in Docker, with the certified referral program behind the site's Seals:
Act 1 shows the demonstration it was compiled from, Act 2 registers five
synthetic referrals at once on clerk accounts through the certified run
path (Standard run gate, REST record check, SQL read-back), and Act 3 adds
an existing chart and shows the program stop before saving a possible
duplicate, with 0 new charts in OpenEMR's database.

The fixture is the repository's pinned OpenEMR fixture with its own Compose
project and ports; a running copy is reused. Without Docker or a clone the
command says so in one line and exits 2; it never falls back to MockMed.
The default stays MockMed, byte for byte.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… tape

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…m the environment

Every mode prints 'See real Seals from OpenEMR runs: https://openadapt.ai/seals'
right after the receipt card, tested to be the canonical page (an opt-in test
fetches it). The OpenEMR fixture's ports can be moved with
OPENADAPT_QUICKSTART_OPENEMR_HTTP_PORT / _HTTPS_PORT; a copy on other ports is
removed with its volumes and set up again.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…rtifact inventory

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…e clone

The clone's packages/flow goes at the end of sys.path, never first, and a
benchmark.openemr_local that resolves anywhere else is refused.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Main's quickstart now ends on the person's own Seal (#1566), so the
OpenEMR scene drops the published-Seals link: view.py and
test_quickstart.py take main's finale, the OpenEMR snapshot loses that
line, and its finale test checks the agent tool line.
# Conflicts:
#	CAPABILITIES.md
#	llms-full.txt
@abrichr

abrichr commented Nov 8, 2026

Copy link
Copy Markdown
Member Author

Independent adversarial review: BLOCK

BLOCK at fb39edd.

P1: Attribute the stop to observed evidence. scene.py:69–99 treats every HALTED run with zero new charts as successful duplicate prevention. I passed the normal renderer a readiness halt before step_000 and an identity halt before step_003, with no screen text or screenshot. Both printed that the duplicate check found an existing chart, that replay would have saved a duplicate, and that the screen showed the duplicate dialog. OpenEMREngine.break_it preserves the actual halt reason, but these branches never inspect it or any duplicate-guard result. An unrelated refusal can therefore look like the advertised successful demonstration. Keep a generic stop when the specific cause is unproven, and show screen content only when observed; add negative coverage alongside the intended duplicate-stop case.

Tested the genuine BreakFacts/Scene/PlainView APIs in an isolated stdlib renderer probe at this head and literal first parent 5f0cf48. Each revision failed both negative cases and all six expectations. Loaded product files matched the exact Git sources before and after. This is a feature defect already present in the first parent, not a merge regression. No Docker, browser, model or real-app run was performed; full package CI is not established by these probes.

Generality: the shipping launcher still contains app-specific adapter code; the benchmark fixture exception should be distinguished from that runtime code. The attribution defect is a general intended-fault-versus-observed-outcome class, with readiness and identity as two siblings. Held-out real-app evidence has not been shown by this review.

Review by Codex.

…e cause

A halted run with no new record read as the advertised demonstration
whatever stopped it. A readiness or identity halt printed that OpenEMR's
duplicate check found a chart, that replay would have saved a duplicate,
and that the screen showed the duplicate dialog, none of it observed.

BreakFacts now carries stop_attributed, set by each engine from the run's
evidence: MockMed when the record check refuted the save; OpenEMR when the
halt is the duplicate-check step's postcondition failing on its no-matches
line with the dialog on screen, before any effect. Otherwise the views say
a generic stop and show screen content only when it was read or observed.
@abrichr
abrichr marked this pull request as ready for review November 9, 2026 04:37
@abrichr

abrichr commented Nov 9, 2026

Copy link
Copy Markdown
Member Author

APPROVE — scoped stop-attribution fix

From: Codex
Reviewed-Head: 062c46d

The shared view now describes a generic stop when the run does not establish the advertised cause. The certified duplicate-check caller attributes a stop only through its required postconditions and complete failure list.

I ran both complete changed test modules on head and literal parent cb1f7f8 in separate normal editable environments. Head: 105 passed, two original opt-in skips. Parent: 94 passed, two original opt-in skips. Total: 203 cases/605 phases, no test failures. Ruff, format and syntax checks passed. Source and dependency checks completed before, during and after collection on both revisions; I independently rehashed 476 loaded source paths across the two refs.

Two separate renderer controls used genuine product classes with synthetic readiness and identity halts. Both head cases avoided the unsupported duplicate-cause/counterfactual claims; both parent cases made those claims. Four negative parent checks establish this difference. An unchanged screen-text substring check falsely passed on the parent and earns no evidence credit. The review wrapper failed because it expected all six parent checks to fail; the parent final source-parity footer remains unrun. I have not changed that probe or claimed an all-green harness.

Scope: the certified caller and these synthetic component cases. Live OpenEMR text matching, Docker/browser opt-ins and held-out application behavior remain untested.

No per-app engine code: shared engine changes are general; app-specific attribution stays in the existing quickstart adapter.
Fix the class: unrelated readiness and identity halts must not inherit a demonstration's claimed cause.
Held-out evidence: absent; this approval is for the scoped software change.

@abrichr abrichr closed this Nov 9, 2026
@abrichr abrichr reopened this Nov 9, 2026
@abrichr

abrichr commented Nov 10, 2026

Copy link
Copy Markdown
Member Author

Retriggering CI now that #1956 turned main green.

@abrichr abrichr closed this Nov 10, 2026
@abrichr abrichr reopened this Nov 10, 2026
@abrichr

abrichr commented Nov 10, 2026

Copy link
Copy Markdown
Member Author

Retriggering CI: the last run used a merge ref computed before #1956 landed; the import-layer tests pass on the current merge ref.

@abrichr abrichr closed this Nov 10, 2026
@abrichr abrichr reopened this Nov 10, 2026
@abrichr
abrichr merged commit 54c758a into main Nov 10, 2026
139 of 151 checks passed
@abrichr
abrichr deleted the feat/quickstart-openemr branch November 10, 2026 03:17
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