Skip to content

feat(flow): API steps compiled from a recording's network capture - #1269

Merged
abrichr merged 12 commits into
mainfrom
claude/api-steps-network-capture
Oct 19, 2026
Merged

abrichr merged 12 commits into
mainfrom
claude/api-steps-network-capture

Conversation

@abrichr

@abrichr abrichr commented Oct 18, 2026 •

Copy link
Copy Markdown
Member

Replaces #1261 (the spike). Same work plus the feature, rebuilt as one commit on main, because gitleaks scans history and a made-up token in a test on that branch would have failed every run.

What it does

A web form save that OpenAdapt can repeat as one request now runs as one request through the replaying browser's own session. The right-record check before the save and the record check after it stay the same. When a check fails before the save is sent, the recorded GUI steps run instead, resolving on the page structure first as they always do.

  • Capture (record --capture-network, web only): writes network.jsonl beside the events. No headers are written. Passwords, --secret fields, CSRF and session tokens, and echoed cookie values are withheld before anything reaches the disk. The format is a versioned contract: docs/NETWORK_CAPTURE.md.
  • Proposal (compile): an ApiBinding(kind="web_form", on_unavailable="gui") on the save, only when every field of the request is explained (run parameter, select label, session value, or form default). Reads whose responses carry the text the GUI checks before saving become pre-checks; on OpenEMR, that's the duplicate search that must say "No matches were found." api_proposal.json gives the reason when nothing is proposed.
  • Admission (openadapt-flow api show | propose | admit): only a person admits, at a terminal, as with check admit. The admission is bound to the exact binding and copies the save step's record check.
  • Run (WebFormActuator + Replayer): each run re-reads the form (CSRF token, defaults, options, field and validation-rule drift), enforces required fields, runs the pre-checks, and posts once. Every refusal before the post falls back to the GUI. Once the post starts, the API tier's no-double-write rule applies: HALT, and RECONCILIATION_REQUIRED on a lost response. Reports mark api_folded and api, and put api_fallback on the first covered step.
  • Not used (the GUI runs instead) under each_item or problems_only approval (the person approves what the screen shows), governed, durable, resumed, or multi-surface runs, and when the steps, checks or record check changed after the proposal or admission.

Docs: docs/API_TIER.md, docs/NETWORK_CAPTURE.md. Tests: tests/test_api_tier_web_form.py (31).

Status

  • tests/test_api_tier_web_form.py: 31 pass, covering capture redaction, the proposal and its refusals, person-only admission, actuator refusals and HALTs, the replayer span and its fallbacks, and RECONCILIATION_REQUIRED on a lost response.
  • On the local OpenEMR referral with this code: a demonstration recorded with capture (28 requests, 12 of 12 saved). The compiler proposed the API step for the save in place of 41 GUI steps: all 105 fields explained, the duplicate check carried as a pre-check, and 11 record-check effects. An earlier smoke run saved two referrals 12 of 12 through the live session.
  • Numbers: none claimed here. The 20 vs 20 measurement runs as scoreboard arm program_api against program (benchmark/openemr_api_tier/scoreboard_arm.py), owned by the scoreboard (demo: CUA to program on openIMIS claims, plus the scoreboard (arms 1-3) #1303) under its protocol and load gate. The spike's figures in benchmark/openemr_api_tier/spike/ used a standalone sign-in and are not the feature's.
  • Root CAPABILITIES.md (docs: one map of what OpenAdapt can do #1260) is not on main yet. Its two rows ("Capture a recording's network traffic…" and "Fall back from the API step…") and scripts/build_llms_full.py get updated when this lands.

🤖 Generated with Claude Code

A web form save that OpenAdapt can repeat as one request now runs as one
request through the replaying browser's own session, with the same
right-record check before it and record check after it; when a check
fails before the save is sent, the recorded GUI steps run instead.

- record --capture-network (web only): NetworkCapture writes
  network.jsonl beside the events. No headers are written; passwords,
  --secret fields, CSRF/session tokens and echoed cookie values are
  withheld before anything reaches the disk. Format:
  docs/NETWORK_CAPTURE.md (schema openadapt.network-capture/1).
- compile proposes an ApiBinding(kind="web_form", on_unavailable="gui")
  on the save when every field of its request is explained (run param,
  select label, session value, form default). Reads whose responses carry
  the text the GUI checks before saving become pre-checks.
  api_proposal.json says why when nothing is proposed.
- openadapt-flow api show / propose / admit. Only a person admits, at a
  terminal; the admission is bound to the exact binding and copies the
  save step's record check.
- WebFormActuator re-reads the form each run (CSRF, defaults, options,
  field and validation-rule drift), enforces required fields, runs the
  pre-checks and posts once. Every refusal before the post falls back to
  the GUI steps; after it starts, the API tier's no-double-write rule
  applies (HALT, RECONCILIATION_REQUIRED on a lost response).
- Replayer runs an admitted API step in place of its GUI steps in plain
  linear runs; each_item/problems_only approval, governed, durable,
  resumed and multi-surface runs keep the GUI. Reports mark api_folded /
  api, and api_fallback on the first covered step.
- docs/API_TIER.md, docs/NETWORK_CAPTURE.md,
  tests/test_api_tier_web_form.py (31 tests).
- benchmark/openemr_api_tier: the October spike (spike/, standalone
  session, 20 + 20 runs, probes) and feature_e2e.py, which records,
  compiles, admits and replays the referral with the shipped feature.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
abrichr and others added 3 commits October 18, 2026 13:40
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…t to save 12/12

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
abrichr and others added 3 commits October 18, 2026 16:08
…-like program rows

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

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

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@abrichr
abrichr marked this pull request as ready for review October 18, 2026 21:14
abrichr and others added 3 commits October 18, 2026 20:22
…py fixes

- public-artifacts.json regenerated: the 59 new files under
  benchmark/openemr_api_tier/spike/ (redacted HAR summary, compiled
  spike bundle, run results). No credential, cookie, CSRF value or raw
  HAR is among them. The git-ignored OpenEMR compose download under
  benchmark/openemr_local/out/ is not registered.
- cli_api: the 'api admit' hint goes through cli_hints.command().
- cli_api, compile: narrow Optional bindings for mypy.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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