Skip to content

fix(flow): bind API step fields by which step typed them, not by equal values - #1368

Merged
abrichr merged 1 commit into
mainfrom
fix/api-proposal-bind-by-provenance
Oct 19, 2026
Merged

abrichr merged 1 commit into
mainfrom
fix/api-proposal-bind-by-provenance

Conversation

@abrichr

@abrichr abrichr commented Oct 19, 2026

Copy link
Copy Markdown
Member

Second of six fixes from an external review of #1269 (the API step). Independent of the other review fixes; targets main.

Bug

api_proposal bound a posted field to a parameter when the posted value equalled the demonstration value, and skipped empty values. Two failures followed:

  • Blank demo value. A blank demonstration note became form_default="", so a later run's "New note" was silently dropped.
  • Equal demo values. Two parameters with the same value made the binding ambiguous.

Fix

Fields are bound by provenance: a TYPE step types into the field the click before it targeted. The target comes from the compiled anchor, or failing that from the recorded event's structural target. It is matched to a form control by id (#id), by [name=...] selector, or by name; the form parser now keeps control ids.

The proposal refuses, and names the reason, when:

  • a field carries a parameter's value although no recorded step typed it there (for example a hidden copy);
  • a typed field was sent with another value;
  • a typed field isn't sent by the save;
  • a typing step's field isn't a control of the form;
  • a field is typed twice with different values.

API_TIER.md's binding table and refusal list are updated.

Tests

tests/test_api_proposal_provenance.py (new, 7 tests):

  • a blank demo note binds form_note as a parameter, and a later run's "New note" is in the body;
  • equal demo values bind each field to its own step;
  • each refusal above has its own test.

All 7 fail on main. The existing proposal tests now give the recorded clicks their targets, as a real recording does. 41 pass.

Checked on the real OpenEMR referral recording: the API step is still proposed, with the same 12 fields bound by provenance.

Synthetic values only.

🤖 Generated with Claude Code

…l values

Review of #1269: api_proposal bound a field to a parameter when the posted
value equalled the demonstration value and skipped empty values. A blank
demonstration note became form_default="", so a later run's "New note" was
silently dropped; equal demonstration values made the binding ambiguous.

Fields are now bound by provenance: a TYPE step types into the field the
click before it targeted (the compiled anchor, else the recorded event's
structural target), matched to a form control by id, name selector or name.
The proposal refuses a field that carries a parameter's value although no
step typed it there, a typed field sent with another value, a typed field
the save doesn't send, a typing step whose field isn't a form control, and
a field typed twice with different values. The form parser keeps control ids.

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