---
name: al-user-verification
description: Guide the user through one slice's `ready-for-verification` verify task in the `tasks/` folder for AL/Business Central — punchline-first, one scenario at a time, in chat. The user walks the non-recorded Journey Examples in their own browser and reports what they see; the agent runs containers, the pre-flight recording batch, and Contract checks, asks one check at a time (ask-before-reveal), records, and routes. Functional outcomes gate; usability observations become findings → tasks.
---

**Style:** Concise — cut filler, keep grammar. Opinionated — pick a side. Arrows (→) for causality. Technical terms exact, code and errors quoted verbatim.

# /al-user-verification — Walk a slice's Verification Plan

Pick a `ready-for-verification` verify task. Run its fresh `Verification Plan`: pre-flight the slice's recording batch, run Contract examples against the named client, then guide the user — **one scenario at a time, in chat, punchline first** — through the **non-recorded** Journey Examples (`Record: no`) and the Exploration Charters in their own browser. The recorded scenarios (`Record: yes`) the user already walked live while recording in `/al-page-script`, and the pre-flight batch re-confirms them on a fresh container — they are **not re-walked**. All functional-pass + pre-flight green + second-opinion-reconciled → flip `done`, hand off to the next slice (or `/al-code-review` per-feature → `/al-validate-breaking-changes` if last). Any functional fail → flip `blocked`, record inline, route to `/al-steer` with trigger #8.

**User is the runner; agent is the guide.** The agent operates everything mechanical — container spawns, publish, the pre-flight regression batch, Contract examples, status flips, the transcript — and turns each `Record: no` Journey Example and each Exploration Charter into single concrete instructions the user performs in the BC Web Client. The user's eyes are the oracle; the user never reads the task file or the plan grammar — they click, look, and answer. No AL writes, no `/al-build` run, no codebase walk (page-ID and option/enum value-range lookups for deep links and structured questions are permitted). Two outcome dimensions split by *checking vs testing*: **functional/observable** outcomes (a Status value, a cue count, an HTTP status, an error) are *checked* — read off the screen by the user — and **gate** the verify task; **subjective usability** outcomes (clunky, unclear, flow isn't one motion) are *sapient testing* → **findings → tasks**, never a gate. Two guards against leading the witness: **ask-before-reveal** (the agent asks what the user sees before naming the expected value), and `/al-second-opinion` reviews the written verdict for coverage.

**Layer.** Owns the human-walked subset of E2E (the `Record: no` Journey Examples), Contract checks, and the exploratory layer (see [`test-strategy.md`](../../references/test-strategy.md)). The user is the direct sapient oracle; `/al-second-opinion` guards coverage and routing, not their eyes. The recorded E2E subset is owned by `/al-page-script` and only **re-confirmed** here by the pre-flight replay.

## What gets walked vs replayed

`/al-refine` marks every Journey Example `Record: yes` or `Record: no` (the framework-limitation call — `Record: yes` only where no AL test layer can automate it; see [`test-specification.md`](../../references/test-specification.md)).

| Plan element | Here | Gate |
|---|---|---|
| Journey Example `Record: yes` | **replayed** in the pre-flight batch (spawn #1); the user already eyeballed it live while recording | replay green |
| Journey Example `Record: no` | **walked** by the user, card by card, ask-before-reveal | observed value vs `Observable Checks` |
| Contract Example | agent runs the named client/harness, no user involvement | captured output vs `Observable Checks` |
| Exploration Charter | user wanders the prompt, narrates | usability → findings/tasks (never gates) |

The sign-off accounts for the `Record: yes` scenarios explicitly: they are confirmed by replay, not unseen.

## Preconditions

- Branch matches `^\d{3}-`. If not: **Stop**. Verify task only exists inside an in-flight feature.
- `specs/<branch>/tasks/` holds a `kind: verify` task with `status: ready-for-verification` and a populated `Verification Plan`. Plain `ready` → **Stop**, `/al-refine T-NNN`. `ready-for-verification` with an empty plan → **Stop**, `/al-steer`; status and proof disagree. `blocked` → `/al-steer`. `done` → downstream evidence exists; do not reopen here.
- `review: clean` present in the verify task's frontmatter — the durable clean per-slice `/al-code-review` evidence, stamped at slice-done (the status byte alone reads identically before and after review). Missing → **Stop**, re-enter via `/al-code-review T-NNN`.
- `event-model.md` present alongside; verify tasks only exist for user/API-facing features. Verify task without `event-model.md` → contract violation, **Stop**, route to `/al-steer`.
- Read [`test-specification.md`](../../references/test-specification.md) and [`test-strategy.md`](../../references/test-strategy.md) before guiding; this skill consumes the `Verification Plan` grammar (incl. the `Record:` flag) and layer rules.
- Every `Record: yes` Journey Example has its recording at `pagescripts/recordings/<NNN>-<slug>__<slice>__NN.yml`. A missing recording for a `Record: yes` example → **Stop**, `Next: /al-page-script T-NNN`. The pre-flight batch runs the slice's recordings plus every prior slice's before the user is invited in. (A plan with only `Record: no` / `Contract` / `Exploration` and no recordings is valid — skip the batch, go straight to spawn #2.)
- If the plan has `Contract Examples`, the named client/harness is available and configured. Missing harness/config → **Stop**, surface the exact blocker.
- Inline partial-run record present → resume at example granularity (see *Partial walks*). No partial-run record → start from the first walkable example.
- **A human drives every walkable scope.** `Record: no` Journey Examples and Exploration Charters are user-driven; there is no agent-driven substitute. Contract-only plans (no walkable scope) have no walk — every check is agent-run against captured client output. Degraded verification never flips `done`.
- **Login is the user's.** Agent surfaces the Web Client URL and the throwaway dev credentials ready to paste: `container.username` / `container.password` from repo-root `al-build.json` (defaults `admin` / `P@ssw0rd`). Local container hosts only — never `*.dynamics.com`. User cannot reach the container URL → **Stop**, fix environment, re-enter.

## Container lifecycle

Three `new-agent-container.ps1` spawns per cycle. Fresh-each-time isolates verification from prior state and leaves the next consumer a clean container.

**Spawn #1 (pre-flight).** `new-agent-container.ps1` → `publish-apps.ps1` → `pagescript-replay.ps1` (batch mode, every `pagescripts/recordings/*.yml`) when recordings exist. Confirms the `Record: yes` scenarios and catches both current-slice regressions and cross-slice collisions before the user walks.

- Green → continue to spawn #2.
- Red → flip verify task `status: blocked`, record `**Replan flag**: trigger #4` for any prior-slice recording red, `**Replan flag**: trigger #8` for a current-slice recording red. Route `/al-steer T-NNN`. Run spawn #3 for cleanup and exit.
- No recordings at all → skip spawn #1; spawn #2 publishes to its own fresh container.

**Spawn #2 (contract check + guided walk).** Only on pre-flight green. `new-agent-container.ps1` → `publish-apps.ps1` → Contract examples (agent-run, no user involvement) → guided walk when walkable scope (`Record: no` Journey Examples or Exploration Charters) exists.

Hand the user:
- Web Client URL: `http://<container-name>/BC/`
- Credentials per the Preconditions login grant
- Deep link to the starting page: `http://<container>/BC/?page=<id>` (page ID read from the page AL)

Contract-only plan → no handover, no walk; the gate judges captured client output. This handover lives here and only here: spawn #1/#2 each recreate the container, so a user invited in earlier gets their session killed mid-walk. Evidence is the transcript of the user's verbatim answers plus any saved screenshots.

**Spawn #3 (exit).** Always runs at end of cycle, pass or fail. `new-agent-container.ps1` only — leaves a fresh container for the next consumer. Skill exits after spawn returns.

Spawn invocations:
- container spawn (any): `pwsh "${CLAUDE_SKILL_DIR}/../al-build/scripts/new-agent-container.ps1"`
- publish all apps (spawn #1, #2): `pwsh "${CLAUDE_SKILL_DIR}/../al-build/scripts/publish-apps.ps1"`
- batch replay (spawn #1): `pwsh "${CLAUDE_SKILL_DIR}/../al-build/scripts/pagescript-replay.ps1"`

## Workflow

### Opener, sized for a human

Announce the verify task: `T-NNN` id, slice slug + `event-model.md` step, counts by what the user will do — **scenarios to walk** (`Record: no` Journey Examples), exploration charters, and (run agent-side first) contract examples — plus estimated walk length (*"3 scenarios, ~5 minutes"*) **and the infra wait before it** (container spawns + publish run minutes; say so). Name how many `Record: yes` scenarios will be confirmed by replay rather than walked, so the user knows the slice's full coverage. No URL or credentials yet — that handover happens inside spawn #2. Leave status `ready-for-verification` while guiding. One scenario open at a time.

### Guide the walk — punchline first, ask before revealing

Each `Record: no` Journey Example becomes one card. **Punchline first** names the *point of the scenario* — the business outcome being checked — **without** naming the expected field value (that would lead the witness). Then the **Do** bullets (the example's `Action`). Then the agent asks the checks one at a time. The next card opens only after this scenario's checks are answered (the exponential-reveal gate sits between scenarios; the opener gave the count).

> **Scenario 1 of 3 — Releasing a blocked customer's order should be refused.**
> *Open the Web Client (link above) and do these — then I'll ask what you see.*
>
> **Do**
> - Open the Sales Order for the blocked customer
> - Choose **Release**

**Functional (checking, gates).** Ask for the observed value **before** naming the expected one: *"What does the Status field show now?"*, never *"Does Status say Open?"*. For a closed enumerable field (an option/enum like `Status`), use `AskUserQuestion` with the field's full value range plus *"Something else — describe"*. For open-ended observables (counts, error text, HTTP bodies), use a free-text question. Record observed-vs-expected verbatim from the user's words, checked against the example's `Observable Checks`. Never infer the value from what the AL "should" do. These walk questions are witness elicitation, exempt from the lettered-options decision rule in [voice-contract.md](../../references/voice-contract.md) — options must never reveal the expected value.

**Usability (testing, findings).** For Exploration Charters, give the charter punchline and prompts, let the user wander and narrate. Friction in their own words — clunky sequencing, ambiguous caption, slow refresh — the agent classifies each remark (functional fail vs usability finding) and confirms the classification in one line so misfiles are catchable. Usability observations are never gate signals.

An action's expected outcome is implicit and observable checks are listed later → wait for the check to ask for the functional observation; do not gate on the action alone. User reports an unexpected surface mid-walk (flicker, sudden navigation, wrong page)? Ask what screen they're on, re-orient via deep link, and re-run the in-flight scenario's remaining checks. Reproducible unexpected navigation is a functional observation (the View state is an observable — it gates); a one-off flicker is a usability finding.

### Pre-flight failure routing (spawn #1 red)

Pre-flight surfaces failures BEFORE the user is invited in. Two failure shapes; both route to `/al-steer` but the trigger names what `/al-steer` is asked to triage.

- **Current slice's recording red.** A recording `/al-page-script` just committed fails on a fresh container — a fragile recording or a regression since its green. Flag `**Replan flag**: trigger #8 (verification failed)`. `/al-steer` triages: guided re-record via `/al-page-script` if fragile, or insert a `fixes:` task if a real defect surfaced.
- **Prior slice's recording red.** An earlier slice's recording fails on the current slice's published code — the current slice broke a prior user-facing surface. Flag `**Replan flag**: trigger #4 (sibling now wrong)`. `/al-steer` triages: regenerate the prior recording via `/al-page-script` if the surface change was intentional, rewrite the prior Verification Plan via `/al-refine` if the contract is invalid, or insert a `fixes:` task if it was unintentional regression.

Mixed-red is one root cause more often than two; the transcript names every failed recording, both flags stamped, `/al-steer` picks one. Flip `status: blocked`, stripping `review: clean` in the same Edit. Run spawn #3 for cleanup before exiting.

### Functional fail: stop the scenario, flip blocked, route

First functional fail in any `Record: no` Journey Example or Contract example, or functional failure during Exploration: **stop**. Do not continue to later checks in the same scenario, do not move to later scenarios.

- Walk/Exploration fail → ask the user to save a screenshot under `.output/verification/T-NNN/` (gitignored; agent cannot persist a chat-pasted image) and reference that path in the inline record so `/al-steer` finds it in a later session.
- Contract fail → captured request/response is the evidence; no screenshot needed.

Record inside the task file: which example (`V#`, `C#`, or `X#`) and which step/check/prompt; observed vs expected verbatim from the user's report (or captured output), screenshot referenced by its `.output/verification/T-NNN/` path; `**Replan flag**: trigger #8 (verification failed)`. Flip `status: blocked`, stripping `review: clean` in the same write — a stale `review: clean` would vouch for a diff it never saw. Announce route to `/al-steer T-NNN`. This skill does not propose the fix; surface failure and stop. A usability finding is **never** a functional fail.

### Second opinion before the gate

All checkable examples pass → before flipping `done`, run `/al-second-opinion` on the written verdict. Tell the user they're free first — the cross-family dispatch can take minutes. Compose the artifact: per scenario/charter, the instruction given, **the exact question as posed — verbatim, including any structured-question options offered and any follow-up questions asked while triaging a remark**, the user's verbatim reported observation (or captured client output), the expected value, evidence reference, and usability findings with their classification; plus the list of `Record: yes` scenarios confirmed by replay (with the pre-flight result). The question goes in as asked, never paraphrased — a neutral paraphrase of a led question hides exactly the defect this gate exists to catch. The gate reviews **coverage and routing**: was every observable check and prompt asked and answered with an observed value; were the replay-confirmed scenarios accounted for; did any pass rest on a led question, a bare yes/no, or an inferred value; was every user remark routed correctly (functional vs usability). It does not re-see the screen. Reconcile per line: real coverage gap → re-ask that check; real routing gap → re-classify and re-state verdict. `Second opinion skipped: …` → absorb and proceed (checkpoint, not hard gate).

### Pass: continue, then flip on the functional gate

- **Check passes** → move to next check.
- **Last check of a scenario** → append the scenario's line to the inline partial-run record (example id, verdict, observed values, exact questions as posed — the second-opinion artifact needs them verbatim, and a session boundary erases the chat transcript). Then move to the next scenario/charter.
- **All checkable examples pass + pre-flight green + second-opinion reconciled** → flip `status: done`, stripping `review: clean` in the same write. Collapse the inline partial-run record into the Closeout shape from [`test-specification.md`](../../references/test-specification.md), including the `Record: yes` scenarios as replay-confirmed.
- **Usability findings** → materialise as candidate task files in the slice, named `NNN-T-MMM-<slug>.md` with a fresh `T-MMM` id and a run-order prefix per the gap rule in [`markdown-spec-discipline.md`](../../references/markdown-spec-discipline.md), frontmatter `status: ready`, `kind: technical`, same `slice:`. Non-gating; `/grill-me` adjudicates ambiguous ones. They queue *after* the next slice's opened tasks unless the user promotes one.
- **Next slice** → flip every technical task in the next slice (whose first task carries `depends_on:` this verify task) from `blocked` to `ready`. The cross-slice gate is the only mechanism that opens the next slice.

Run the Gate report. The gate flips on the user's own reported observations plus replay-confirmation of the recorded scenarios (Contract-only: captured client output); the user can halt or veto at any step.

### Partial walks survive session boundaries

A session interrupted mid-walk leaves the verify task at `ready-for-verification` with the incrementally appended partial record inline (written per completed scenario in the Pass step). Re-entry resumes at **scenario granularity**: completed scenarios stay closed, but the in-flight scenario restarts from its first action, because re-entry spawns fresh containers and the data its earlier actions created is gone. Re-ask only that scenario's checks. Closed scenarios whose data the in-flight one depends on: re-drive their *actions* as setup on the fresh container without re-asking their checks — their verdicts stand on the record. Contract examples re-run on every spawn #2 (agent-side, free); the recording batch re-runs in spawn #1; only walk scenarios stay closed.

## Gate event

Once when the verify task flips to `done`. Gate report — rendered box-first, passed through the pre-send checks ([voice-contract.md](../../references/voice-contract.md)) — names the slice (slug + `event-model.md` step), what the user confirmed by walking and what was confirmed by replay (the `Record: yes` scenarios) in BC vocabulary (Role action, Business Event, View state, Status value, API/client result), the usability findings surfaced (→ candidate tasks), the evidence (transcript + replay result + any saved screenshots), the second-opinion outcome (reconciled / skipped), next handoff: `/al-refine` on the next slice's first technical task; or, if last slice, `/al-code-review` per-feature → its clean pass opens the `kind: breaking-change` task → `/al-validate-breaking-changes`.

Gate report on failure (flipping to `blocked`) is the Stop shape from [voice-contract.md](../../references/voice-contract.md): one stop line naming scenario / check / observed-vs-expected, state table (verify task id, scenarios completed, scenario blocked on), next action (route to `/al-steer`).

## Next step

End by naming the concrete next move, read off current state. The status flips and same-feature `blocked` → `ready` opens below are state writes this skill owns inline — naming the next step is separate, and never auto-invokes it.

- **Verify pass, next slice opened** (its technical tasks flipped `ready`) → `Next: /al-refine T-NNN` on the next slice's first task.
- **Verify pass, last slice** → `Next: /al-code-review` per-feature (its clean pass opens the breaking-change task → `/al-validate-breaking-changes`).
- **Functional fail or pre-flight red** (verify task `blocked`, `review: clean` stripped) → `Next: /al-steer T-NNN`.

If state can't be read, fall back to `/al-refine` on the next slice (or `/al-steer` after a fail).

## Composition

| | |
|---|---|
| **Runs after**     | `/al-page-script` recorded every `Record: yes` Journey Example, and `/al-code-review` per-slice stamped `review: clean` at slice-done (preserved through refine) |
| **Hands off to**   | next slice's technical tasks opened to `ready` for `/al-refine`; or — if last slice — `/al-code-review` per-feature → its clean pass opens the `kind: breaking-change` task → `/al-validate-breaking-changes`. `/al-steer` on failure (after `status: blocked`). Usability findings → candidate tasks in the slice. |
| **Uses**           | `new-agent-container.ps1` (three spawns per cycle), `pagescript-replay.ps1` (batch mode for spawn #1's pre-flight), `publish-apps.ps1` (spawn #1, #2), Web Client deep links + `al-build.json` credentials, `/al-second-opinion` (coverage review before the gate), [`../../references/test-specification.md`](../../references/test-specification.md) (`Verification Plan` grammar + `Record:` flag), [`../../references/test-strategy.md`](../../references/test-strategy.md) (layer + checking-vs-testing frame) |
| **Replan venue**   | `/al-steer` — trigger #4 (pre-flight prior-slice red), trigger #8 (pre-flight current-slice red or functional-walk fail) |
| **Sidebands**      | `/grill-me` (adjudicate an ambiguous usability finding, or whether an observation matches the expected outcome), `/al-research` (BC surface behaviour to verify against documentation) |

**Advisor checkpoint.** Do a final coverage check before flipping the verify task to `done` — the same-session complement to the `/al-second-opinion` cross-family coverage gate. The flip greenlights the next slice; if the verdict doesn't cover every walked observable check with a user-reported value and every `Record: yes` scenario with a replay result, or any pass rests on a led or inferred value, the gate is theatre.
