Skip to content

feat(desktop): Check it asks three questions; the recording fills in the rest (hold: founder review) - #1353

Merged
abrichr merged 8 commits into
mainfrom
claude/desktop-three-decisions
Oct 20, 2026
Merged

abrichr merged 8 commits into
mainfrom
claude/desktop-three-decisions

Conversation

@abrichr

@abrichr abrichr commented Oct 19, 2026

Copy link
Copy Markdown
Member

Hold: founder's visual review before merge. Builds on the Calm UI pass (#1309, #1310), now on main.

What this changes

From "I recorded something" to "it runs", Check it now asks three questions. Everything else the recording shows is filled in and shown once, folded:

  1. Is this the right record check? Learned from the read the app made after the save (Flow's record-check synthesis, feat(flow): build a working record check from the app's own reads #1284), bound as the same effect a person would type in the form. The screen says what its fault test caught and what it can't catch.
  2. Which values change per item? Every typed value, proposed from one recording or several. A value marked fixed is filled in on every item and Run it doesn't ask for it. Then one practice item (the person approves its save) and the five drills, on their own.
  3. Approve?

The person's agent can do steps 1, 2 and the checks over MCP (python -m openadapt_desktop.agent_mcp). Its answers are recorded as the agent's, the window says so, and only the person approves.

Counts, on MockMed, real engine and real Flow runs

Before (#1310) After After, agent answering
Setup inputs, recording to approval 10 (2 typed), then Flow refused the practice item 3 decisions + 1 save approval 2 (both approvals)
Navigation 4 2 1
Certified, sealed, approved No Yes Yes
First real item Not reached Ran, gated by the person; Flow's record check confirmed the save not run in this walk

Every input, with a screenshot, is in packages/desktop/docs/SETUP_INPUTS.md. scripts/setup_walk/walk.py --variant before|after|agent reproduces each walk (about 10 minutes).

Before: 10 inputs, then a refusal Check it couldn't explain

The form (part 3) After 10 inputs
before form before refused

After: three questions

Question 1 Question 3
after q1 after q3

After, with the agent answering

agent approve

Bugs found on the way (each stopped a Check it run on a web app; fixed here)

  1. Environment observer. Desktop started the check bound to no observer; a web app without OpenAdapt markers or a session cookie (MockMed, most real apps) failed "observer does not match the project". Flow now uses the project's own web observer at run time (fix(flow) commit); Desktop binds Flow's generic web observer, or the signed-in session for an attached browser.
  2. No case result could be recorded. Since July the engine retains report.json but still required the old run-report-receipt.json. Results are now bound by the retained report's digest.
  3. Identity policy wasn't set when the compiled step was already armed (part 2 said "Confirmed" while Flow refused).
  4. Case scope included steps a person confirmed read-only; now Flow's required actions, as Flow's own qualify campaign does.
  5. Drill evidence: the frames and proofs a report names are now retained with the result.
  6. Approving certified the plaintext version, then sealed an uncertifiable copy (case results bind the executable workflow, which includes encrypted), and the copy failed to load (stale authorization template). Check it now seals before the practice item and approves that sealed version.

Needs a decision

  • Admission. A run gets "done and checked" only under the Standard profile, and Flow refuses Standard without a signed qualification admission (Cloud or the organization's signer). Approve in Check it doesn't produce one, so the first item runs unprofiled and shows "Finished, not checked" even though Flow's report has the save confirmed. Should Approve sign a local admission, or does admission stay with Cloud?
  • Desktop's recorder doesn't keep network traffic yet, so on a real Desktop recording Check it falls back to the parts. The walk writes the recording's network.jsonl the way Flow's own record-check tests do (stated in the doc).

Not changed

No check is weaker: a yes sends the same qualification commands the form sends, with more fields matched; every environment, identity and evidence digest is still compared. Nothing approves on its own, and the agent socket has no approve, certify, seal or save-approval command.

Tests

  • Desktop engine: 912 passed (1 local-only failure: openadapt-privacy not installed). New: test_check_setup.py, test_agent_setup.py, receipt binding.
  • Desktop UI: 376 passed (vitest), tsc clean.
  • Flow: tests/test_web_environment_binding.py and the web-session tests pass.
  • MCP: a stdio client initializes, lists the five tools and calls one.

🤖 Generated with Claude Code

abrichr and others added 8 commits October 19, 2026 10:14
A deployment wires the backend's own marker observer into every
qualification case. A web app with no OpenAdapt markers (MockMed, most real
apps) can't satisfy it, so a project could never be observed and every
Desktop practice item stopped with "qualification environment observer does
not match the project". The signed-in session branch was unreachable for
the same reason.

A project whose boundary names Flow's generic web observer (the one the
qualify campaign uses) or the signed-in session observer now gets that
observer at run time instead of the default adapter. The observer id, its
contract, the origin, the declared version and the environment digest are
still compared with the project, and the input-edge guard still re-observes
before every input, so a page reload mid-run stops the run.

observe_web_environment() reads the environment once, for binding a project
before its first case. PlaywrightBackend.launch records whether the browser
is headless, which that observer's digest includes.

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

Check it used to ask for every part by hand: what the save changes, how to
recognize the record, a record-check form, a settings file from IT, a test
values attestation, then practice, drills and approval. On MockMed that was
10 inputs, and the practice item was then refused by Flow anyway.

Now the engine proposes what the recording shows (get_check_setup):
- the record check, from the read the app made after the save (Flow's
  record-check synthesis, #1284), as the same effect binding a person would
  type, plus the app's own anti-double-save key; its fault test is run on
  exactly that binding and shows what it catches and misses;
- which steps only read: the network capture shows the app sent data only
  when the person saved;
- the right-record check from the recording, and the app and environment;
- which values change per item, from one recording or several.

The person answers three things: "Is this the right record check?",
"Which values change per item?" (then one practice item whose save they
approve, and the drills on their own) and "Approve?". A yes sends the same
qualification commands the long form sends; "Change" opens the parts. Values
marked as the same on every item are filled in by run_item and not asked in
Run it. Without a learned check, the parts ask as before.

The person's agent can answer the first two over the local socket and MCP
(python -m openadapt_desktop.agent_mcp): read the setup, answer, run the
checks. Socket answers are always recorded as the agent's, the window says
so, and approving stays in the window.

Fixes found on the way, each of which stopped a Check it run on a web app:
- start the check bound to an environment observer a web app can satisfy
  (Flow's web observer, or the signed-in session for an attached browser);
- the project gets its own identity policy for the save even when the
  compiled step already carries the recorded gate;
- a case result is bound by the retained report.json's digest; the engine
  stopped writing run-report-receipt.json in July but still required it, so
  no practice or drill could be recorded;
- a case proves Flow's required actions, as Flow's own qualify campaign
  does, not steps a person confirmed only read;
- the frames and proofs a run report names are retained with the result, so
  Flow can credit a drill.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Flow binds every case result to the exact executable workflow, and sealing
sets the workflow's encrypted flag, so results recorded on the plaintext
version can never certify the sealed copy. Approving certified the
plaintext version and then sealed a copy that was never certified and
couldn't run; loading the copy also failed, because the seal kept the
authorization template derived from the certification it cleared.

Check it (and the agent's run_checks) now seals before the practice item,
runs the practice item and drills on the sealed version, and approves that
version. The seal drops the derived template along with the certification.
When the agent's checks finish, the window reloads.

Also: write the learned record check as a plain effects section (the
deployment's own profile still applies), and line-length fixes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
docs/SETUP_INPUTS.md counts what a person gives from a finished recording to
the first real item, with a screenshot of each input:

- before (#1310): 10 inputs (2 typed), then Flow refused the practice item;
- after: 3 decisions and 1 save approval, certified, sealed and approved; the
  first item ran, gated by the person, and Flow confirmed its save;
- with the person's agent over MCP: 2 inputs, both approvals.

scripts/setup_walk reproduces it: the real Desktop engine behind a
loopback HTTP bridge, real Flow, MockMed's transactional server, and the UI
from npm run dev in a headless browser. Synthetic data only.

OPERATOR_SCREENS.md describes the new Check it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
# Conflicts:
#	packages/flow/openadapt_flow/backends/playwright_backend.py
0.21.1 never reached PyPI (the release check refused the Desktop asset
set, fixed in #1403), and its tag cannot be rebuilt. Ship 0.21.0, 0.21.1
and this PR's changes as 0.22.0.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@abrichr
abrichr merged commit dc97bdb into main Oct 20, 2026
53 checks passed
@abrichr
abrichr deleted the claude/desktop-three-decisions branch October 20, 2026 04:13
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