8. Execution Modes
Permalink to 8. Execution ModesThis section is normative.
A conforming processor SHOULD implement at least one of the following modes and MAY implement both. A processor that implements both MUST produce behaviorally equivalent runtime results in either mode (modulo timing).
8.1 Code generation mode
Permalink to 8.1 Code generation modeThe processor MUST emit one Playwright .spec.ts file per use case. The file
structure is:
// Auto-generated by @afixt/usecase-runner from <source>.uc.yaml
// Do not edit manually — changes will be overwritten on next generation.
import { test, expect } from '@playwright/test';
// (only if any audit step is present:)
const { AccessibilityEngine } = require('@afixt/afixt-engine');
test.describe('<title>', () => {
test.describe.configure({ mode: 'serial' });
test('<id>: <title> (<type>)', async ({ page }) => {
// Preconditions: …
// Step 1: Access start location
await page.goto('<start_location>');
// Step 2: <comment>
<generated code>
// Step 3: <comment>
<generated code>
…
});
});
The auto-generation banner is REQUIRED. The serial mode declaration is REQUIRED.
The generated await page.goto(...) MUST be step 1; user-authored steps begin
at step 2. This invariant is observable in the report (see
§10).
8.2 Direct execution mode
Permalink to 8.2 Direct execution modeIn direct execution, the processor:
- Launches a Playwright browser (browser type, headed/headless, slow-mo, viewport, default timeout — all per configuration).
- Navigates to
start_location. - Iterates over the resolved steps. For each step, it executes the step's
action against the live page, captures duration, and produces a
StepResult. - On step failure with
screenshot_on_failure: true, captures a full-page screenshot to<screenshot_dir>/<use-case-id>/step-<N>-fail.png, or to<screenshot_dir>/<use-case-id>/iter-<i>/step-<N>-fail.pngfor stepNof iterationi(1-based) of an iterated case (§5.8), or to<screenshot_dir>/<use-case-id>/before/step-<N>-fail.pngfor entryNof thebeforeblock (§4.6), whose numbering also starts at 1. The use case id is reduced to the charactersA–Z a–z 0–9 . _ -for the directory name, every other character becoming_. Step numbers restart per use case and per iteration, so a path without both components lets one case's evidence overwrite another's; the report'sscreenshot_path(§10.1) records the path actually written. - On step failure with
continue_on_failure: false(non-default), short-circuits remaining steps to statusskip. - Closes the browser and computes the overall score.
In direct mode, step indexing starts at 1 for the first user-authored step;
goto is performed before the loop and is not counted. (This is the inverse of
codegen mode — see §10 for how reports normalize this.)
8.3 Mode equivalence
Permalink to 8.3 Mode equivalenceRunning the same conforming use case document through codegen and then through
npx playwright test MUST produce the same pass/fail outcome as running it
through direct execution (modulo flakiness and timing). The canonical
equivalence is defined by §6 and
§5; any divergence is a defect in the implementation.
There are no exceptions. Aggregate assertions (§5.8.4) and continuation past a failing iteration (§5.8.6) hold in both modes: a generated test collects per-iteration outcomes and asserts the aggregate after the loop, so both modes reach the same pass/fail outcome for an iterated document as for any other.
8.4 Interaction profiles
Permalink to 8.4 Interaction profilesAn interaction profile names a set of interaction affordances the page under test MUST NOT require in order to complete the flow. A profile does not change how the page is driven — it changes which verbs the run permits. Omitting it leaves the run unrestricted, which is the default and the behaviour of every run that does not ask for a profile.
The profile is selected per run: RunOptions.profile in the programmatic API
(§13) and --profile <name> on the command line
(§14).
One profile is defined:
| Profile | Forbidden forms |
|---|---|
no-pointer |
hover, hover_out, toggle, activate without via keyboard, select on an option target |
The set is every form that dispatches a pointer event, not every keyword that
can. activate ... via keyboard presses Enter and stays available; select on
a checkbox, radio or native select drives state without a click and stays
available. Under the profile, activate ... via keyboard is the only activation
form, and keyboard: drives options and toggles.
A profile name describes the prohibition, not a simulation: no-pointer
forbids the pointer forms, it does not drive the page by keyboard in their
place. A processor MUST NOT interpret a profile as a request to emulate an
alternative input modality.
What a passing run establishes. That the script as written requires no
pointer — which is the author's assertion about the flow, not proof that the
application requires one. An author who wrote hover may simply have chosen
that route where a keyboard route also exists. The profile makes the script's
claim explicit and checkable; it does not discover the application's
requirements.
When a violation is reported. A profile violation is a property of the
document rather than of the page, so a processor MUST be able to report it
without a browser: validate SHOULD accept the profile and name the offending
steps. The runtime failure below is retained for processors that only see the
document at run time, and for a violation reached through a path validation
could not resolve.
A processor MUST reject an unrecognised profile name rather than ignoring it. Silently dropping an unknown name would report a clean run that enforced nothing, which is the precise failure the profile exists to prevent.
Enforcement
Permalink to EnforcementWhen the active profile forbids a step's keyword:
- The step MUST fail without executing. The processor MUST NOT dispatch the underlying interaction — the assertion is that the flow requires the affordance at all, so attempting it would defeat the check.
- The step result MUST carry
status: "fail"andfailure_reason: "profile_forbidden"(§10.1). - The failure MUST be a failure and not a skip. A flow that cannot proceed without the forbidden affordance is a genuine defect for anyone who lacks it, not a test that turned out to be inapplicable. Scoring treats it like any other failing step (§11), and it gates the exit code accordingly (§14.1).
- The enforced profile MUST be recorded on the result (
profile, §10.1), taken from what was actually enforced rather than what was requested, so a report can never claim a profile the steps did not run under.
Both execution modes MUST enforce the profile identically: direct execution fails the step as above, and code generation MUST emit a step that fails with the same message rather than one that performs the interaction. This is required by §8.3 — a profile enforced in only one mode would make the two modes disagree on the same document.