Skip to content

Correct snapshot backend and custom-action documentation #1689

Description

@thymikee

Plan 006: Correct snapshot backend and custom-action documentation

Executor instructions: Follow this plan step by step. Run every
verification command and confirm the expected result before moving to the
next step. If anything in the "STOP conditions" section occurs, stop and
report — do not improvise. A reviewer maintains the plan index for this work;
do not create or edit plans/README.md.

Drift check (run first):
git diff --stat 13bc70f24..HEAD -- website/docs/docs/snapshots.md website/docs/docs/commands.md src/__tests__/command-doc-coverage.test.ts
If any in-scope file changed since this plan was written, compare the
"Current state" excerpts against the live code before proceeding; on a
mismatch, treat it as a STOP condition.

Status

  • Priority: P2
  • Effort: S
  • Risk: LOW
  • Depends on: none
  • Category: docs
  • Planned at: commit 13bc70f24, 2026-08-08

Why this matters

The snapshot guide says a zero-node XCTest result fails without switching to
AX, but regular iOS capture now has an explicit recursive-tree → query-sweep →
private-AX recovery plan. The public CLI also exposes --actions, while both
website reference pages omit it. Correcting the prose prevents false diagnosis
of recovered/degraded snapshots, makes merged accessibility affordances
discoverable, and adds a schema-derived guard so the canonical snapshot usage
cannot drift from the command reference again.

Current state

  • The command schema is the canonical CLI usage source:

    // src/commands/capture/snapshot.ts:49-59
    const snapshotCliSchema = {
      usageOverride:
        'snapshot [--diff] [-i] [-d <depth>] [-s <scope>] [--raw] [--actions] [--force-full] [--timeout <ms>]',
      allowedFlags: [
        'snapshotDiff',
        ...SNAPSHOT_FLAGS,
        'snapshotCustomActions',
        'snapshotForceFull',
        'timeoutMs',
        'record',
      ],
    } as const;
  • Its field description provides the user contract that documentation must not
    overstate:

    // src/commands/capture/snapshot.ts:24-32
    interactiveOnly: booleanField(),
    depth: integerField(),
    scope: stringField(),
    raw: booleanField(),
    customActions: booleanField(
      'Name the affordances an element merged away (iOS UIAccessibilityCustomAction, React Native accessibilityActions) — a card whose reply/options controls are not separate elements still lists them here. The names are for PLANNING, not invocation: there is no API to trigger them, so reach the affordance through the element detail screen, through the same control exposed as a labeled element elsewhere, or by coordinates from its rect. iOS simulator only; costs one accessibility round trip per merged element.',
    ),
    forceFull: booleanField(),
    timeoutMs: integerField('Maximum wall-clock time for the snapshot command.'),
  • The flag registry repeats the essential short-form limitation:

    // src/commands/cli-grammar/flag-definitions-workflow.ts:203-208
    {
      key: 'snapshotCustomActions',
      names: ['--actions'],
      type: 'boolean',
      usageLabel: '--actions',
      usageDescription:
        'Snapshot: name the affordances merged inside an element (iOS sim); not directly invokable — reach them via the detail screen, labeled children, or coordinates',
    },
  • The accepted snapshot strategy requires fallback for sparse regular output:

    <!-- docs/adr/0004-ios-snapshot-backend-strategy.md:38-43 -->
    Keep XCTest as the default iOS automation runner and split iOS snapshot capture into explicit
    strategies:
    
    - **Regular visible strategy**: use recursive XCTest snapshots, emit the effective user-visible
      tree plus visible ancestors and scroll-hidden hints, and fall back through the capture plan when
      XCTest returns sparse output.
  • The live plan confirms the backend order:

    // apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/
    // RunnerTests+SnapshotCapturePlan.swift:115-118
    // MARK: Plan definitions
    
    static let regularVisiblePlan: [SnapshotBackendKind] = [.recursiveTree, .querySweep, .privateAX]
    static let rawDiagnosticPlan: [SnapshotBackendKind] = [.recursiveTree, .privateAX]
  • The guide currently contradicts those sources and omits current options:

    <!-- website/docs/docs/snapshots.md:19-26 -->
    | Option       | Description                  |
    | ------------ | ---------------------------- |
    | `-i`         | Interactive-only output      |
    | `-d <depth>` | Limit tree depth             |
    | `-s <scope>` | Scope to label or identifier |
    
    Note: If XCTest returns 0 nodes (foreground app changed), agent-device fails explicitly.
    It does not automatically switch to AX.
  • The command reference is not the canonical schema usage:

    <!-- website/docs/docs/commands.md:306-313 -->
    ## Snapshot and inspect
    
    ```bash
    agent-device snapshot [--diff] [-i] [-d <depth>] [-s <scope>] [--raw]
    agent-device diff snapshot [-i] [-d <depth>] [-s <scope>] [--raw]
    agent-device get text @e1
    agent-device get attrs @e1
    ```
  • src/__tests__/command-doc-coverage.test.ts:7-17 intends to prevent public
    command-reference drift, but extractDocumentedCommandTokens at lines 38-54
    extracts only the first command token. Follow this test's fs +
    node:assert/strict style and derive snapshot usage through
    getCliCommandSchema plus buildCommandUsage; do not duplicate the usage
    literal in the test.

  • Website CI runs pnpm check:command-docs for docs-only pull requests at
    .github/workflows/pr-preview.yml:21-40, and the production docs build runs
    pnpm --dir website build through
    .github/actions/build-docs/action.yml:16-22.

Commands you will need

Purpose Command Expected on success
Command-reference gate pnpm check:command-docs exit 0; command names and canonical snapshot usage are documented
Docs build pnpm --dir website build exit 0; Rspress builds website/doc_build without broken Markdown or links
Affected gates pnpm check:affected --run exit 0 for selected local checks; CI-owned checks are reported only
Scope check git status --short only the three in-scope files are changed; generated docs output is ignored

Dependencies must already be installed. Use pnpm only; do not create or
restore package-lock.json.

Scope

In scope (the only files you should modify):

  • website/docs/docs/snapshots.md
  • website/docs/docs/commands.md
  • src/__tests__/command-doc-coverage.test.ts

Out of scope (do NOT touch, even though they are evidence for the docs):

  • src/commands/capture/snapshot.ts
  • src/commands/cli-grammar/**
  • src/cli-schema/**
  • src/daemon/**
  • apple/runner/**
  • docs/adr/0004-ios-snapshot-backend-strategy.md
  • Any new custom-action invocation API or fallback behavior.
  • README, skills, changelog, other website pages, generated website/doc_build,
    plans/README.md, and all other plan files.

Git workflow

  • Branch: advisor/006-snapshot-backend-actions-docs
  • Use one logical commit after the red/green proof:
    docs: align snapshot fallback and actions guidance
  • Do NOT commit the intentionally red test state or generated docs output.
  • Do NOT push or open a pull request unless the operator explicitly instructs it.

Steps

Step 1: Add a canonical-usage regression and prove it red

In src/__tests__/command-doc-coverage.test.ts:

  1. Import getCliCommandSchema from
    ../cli-schema/command-schema.ts and buildCommandUsage from
    ../cli-schema/usage.ts.

  2. Reuse COMMANDS_DOC_PATH and the existing filesystem read style.

  3. Add a focused test named
    commands.md publishes the canonical snapshot CLI usage that computes:

    const usage = buildCommandUsage('snapshot', getCliCommandSchema('snapshot'));

    and asserts the Markdown contains the executable code-block line
    agent-device ${usage}. Do not paste the expected flag list into the test;
    the schema must remain the source of truth.

This is deliberately scoped to snapshot. Do not generate the entire command
reference or turn narrative documentation into exact-schema output.

Verify red: pnpm check:command-docs → exit nonzero, with the new test
reporting that the canonical snapshot usage is absent. Record the failing test
name. If it passes before editing commands.md, STOP because the regression is
not checking the intended drift.

Step 2: Publish the canonical command-reference usage

Replace the snapshot usage line in website/docs/docs/commands.md with the exact
value produced by the schema, prefixed by agent-device:

agent-device snapshot [--diff] [-i] [-d <depth>] [-s <scope>] [--raw] [--actions] [--force-full] [--timeout <ms>]

Keep diff snapshot, get, and is examples intact. Add a short bullet below
the code block explaining that --actions names merged custom accessibility
affordances on iOS simulators and is for planning, not direct invocation. Do not
claim physical-device or cross-platform support.

Verify: pnpm check:command-docs → exit 0, including the new canonical-usage
test and all existing bidirectional command-token checks.

Step 3: Correct the snapshot guide from the accepted/live contract

Update website/docs/docs/snapshots.md without changing command behavior:

  1. Add one concise agent-device snapshot --actions example near the existing
    snapshot examples.
  2. Expand the options table to cover the canonical snapshot-specific options
    shown in the usage line: --diff, -i, -d, -s, --raw, --actions,
    --force-full, and --timeout.
  3. For --actions, state all of these constraints:
    • iOS simulator only;
    • names custom actions merged inside an element;
    • planning/discovery only, not directly invokable;
    • costs an accessibility read per merged element;
    • incompatible with --raw.
  4. Replace lines 25-26 and the oversimplified backend description at lines
    69-72 with an iOS capture behavior section:
    • regular visible capture starts with recursive XCTest and may recover
      through query sweep and private AX when that backend is available;
    • the ladder is bounded and recovery/degradation remains observable through
      quality warnings rather than being presented as an empty UI;
    • raw is the diagnostic strategy and preserves strict capture failures;
    • private AX recovery/custom-action reads are simulator-specific; do not
      promise an equivalent independent backend on physical iOS devices.
  5. Keep visible-first output, off-screen summaries, ref freshness, and Android
    guidance unchanged.

Use the terms regular visible strategy, raw diagnostic strategy,
sparse, recovered, and degraded consistently with ADR 0004. Do not
describe the internal backend ladder as user-selectable CLI backends.

Verify:

rg -n -- '--actions|regular visible|raw diagnostic|sparse|degraded' website/docs/docs/snapshots.md website/docs/docs/commands.md
rg -n 'does not automatically switch to AX' website/docs/docs/snapshots.md

Expected: the first command finds the new guidance in both pages; the second
prints no matches.

Step 4: Build the docs and run the owning gates

Run the direct command-reference gate, the same Rspress build CI uses, and the
affected selector. Do not add a formatter path invocation; Markdown is excluded
from the repository formatter.

Verify:

pnpm check:command-docs && pnpm --dir website build && pnpm check:affected --run

Expected: exit 0. Rspress writes only ignored website/doc_build output. The
affected selector runs tests related to the changed TypeScript gate and reports
any CI-only work.

Step 5: Confirm the handoff contains only source documentation and its gate

Verify: git status --short → only the three in-scope files are listed.
If generated docs output appears as tracked or untracked state, STOP and report
instead of changing ignore rules or deleting broad paths.

Test plan

  • Add one schema-derived command-doc test in
    src/__tests__/command-doc-coverage.test.ts.
  • Prove it red against the current commands.md before updating documentation.
  • Preserve all existing forward/reverse command-name and waiver tests.
  • Build the full Rspress site to catch malformed tables, fences, and links.
  • No device or runner test is needed because no runtime behavior changes.

Done criteria

  • The planned-at excerpts still matched before editing.
  • The schema-derived snapshot usage test failed before the docs edit and its
    failing test name was recorded.
  • commands.md contains the exact canonical snapshot usage from
    buildCommandUsage.
  • Both website pages document --actions as iOS-simulator-only and
    planning-only.
  • The guide no longer claims regular capture never falls back to AX.
  • Regular visible and raw diagnostic behavior matches ADR 0004 and the live
    capture-plan ordering without presenting internal backends as CLI choices.
  • pnpm check:command-docs exits 0.
  • pnpm --dir website build exits 0.
  • pnpm check:affected --run exits 0 for local gates.
  • git status --short lists only the three in-scope files.
  • README, skills, ADRs, runtime code, and plans/README.md are unchanged.

STOP conditions

Stop and report back; do not improvise if:

  • Any in-scope current-state excerpt has drifted since 13bc70f24.
  • buildCommandUsage('snapshot', getCliCommandSchema('snapshot')) no longer
    returns the usage shown in this plan.
  • ADR 0004 and RunnerTests+SnapshotCapturePlan.swift no longer agree on the
    regular strategy or backend order.
  • The red regression passes before commands.md changes.
  • Accurate docs would require adding custom-action invocation, changing
    platform capability, or modifying runtime fallback behavior.
  • The docs build changes tracked generated files or requires lockfile changes.
  • A verification command fails twice after one reasonable correction.
  • Any fix requires touching a file outside the in-scope list.

Maintenance notes

  • Reviewers should compare behavior prose to ADR 0004 and the live capture plan,
    but compare CLI syntax to the schema-derived test. These are different owners.
  • The canonical-usage gate protects commands.md; the snapshot guide remains
    narrative and must be reviewed when user-facing snapshot flags or strategy
    semantics change.
  • Keep custom-action discovery separate from invocation. Runner research at
    RunnerAXSnapshotBridge.h:62-68 says the current runner can read names but
    cannot invoke them; this plan must not imply otherwise.
  • Docs/skills impact is complete within the two website pages. Skills remain
    unchanged because they route to versioned CLI help rather than carrying
    command behavior.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions