--- name: qv-pr-test description: Plan and run local PR validation for tetherto/qvac PRs. Reuses the shared PR worktree, discovers touched packages and package.json scripts, recommends a test tier, and analyzes results. Use when testing a PR or invoking /qv-pr-test. disable-model-invocation: true --- # PR Test Manual-trigger local PR validation for any GitHub PR in `tetherto/qvac`. The skill prepares an isolated PR worktree, discovers changed packages and test options, recommends a tier, and then runs or proposes the selected validation steps according to package type. High-level flow: 1. Discover package-local setup, examples, tests, and related validation targets from committed PR state. 2. Present a recommended tier plus any related examples/tests as part of the same proposal. 3. Execute agent-owned steps inside the isolated PR worktree when safe. 4. For validation that must be user-run, print exact commands and inspect reports/logs afterward. ## When to use this skill Use when: - User asks to test a PR or provides a PR URL for validation. - User invokes `/qv-pr-test`. - A PR review/status flow needs local verification before reviewers are pinged. ## Inputs - **Required**: PR URL, e.g. `https://github.com/tetherto/qvac/pull/1234`. - **Optional**: user focus area, preferred mobile platform (`android` or `ios`), desired tier. If PR URL is missing, ask for it. Do not ask other questions until discovery has produced a concrete recommendation. ## Safety rules This skill must not touch the user's local working tree. Forbidden against the user's main repo: - `git switch`, `git checkout`, `git reset`, `git restore` - `git stash`, `git pull`, `git merge`, `git rebase`, `git cherry-pick` - `git clean` - `gh pr checkout` - Any package manager, build, or test command ### Worktree carve-out The shared script `worktree-prepare.mjs` is allowed to operate only inside `~/.cache/qvac-pr-review/pr-/`. It may fetch PR refs, add/remove worktrees, reset tracked files, and clean untracked artifacts on SHA drift. The agent may run non-e2e package manager/build/test commands only inside the prepared worktree path printed by `worktree-prepare.mjs`. For every selected tier, agent-owned package validation must prepare the touched package root before examples or non-e2e tests run. If discovery reports `commands.install` or `commands.build`, include those setup commands first in the proposed command plan and execute them first from the package `cwd`. ## Workflow Track this checklist: ```text - [ ] 0a. Prepare worktree with worktree-prepare.mjs - [ ] 0b. Discover packages/scripts/tests with pr-test-discover.mjs - [ ] 1. Present recommendation and tier menu - [ ] 2. Ask user to select tier and mobile platform when needed - [ ] 3. Print proposed command sequence - [ ] 4a. Run agent-owned setup/examples when safe and applicable - [ ] 4b. If SDK e2e is included: stop and ask user to run the printed e2e setup + e2e command block - [ ] 4c. If SDK e2e is not included: ask approval, then execute remaining commands - [ ] 5. Analyze logs/reports - [ ] 6. Summarize pass/fail and next action ``` ### 0a. Prepare worktree Run: ```bash node .agents/skills/_lib/pr-skills/worktree-prepare.mjs ``` Parse stdout: ```text WORKTREE_PATH= HEAD_SHA= PATCH_PATH= BASE_REF=/ ``` If stderr contains `WORKTREE_FALLBACK=`, use fallback mode: - Fetch/read files via GitHub API if needed. - Let `pr-test-discover.mjs` fetch the patch with `gh pr diff --patch` into the platform temp directory when `PATCH_PATH` is unavailable. - Tell the user that worktree preparation failed and local command execution is unavailable unless they want to retry. ### 0b. Discover test options Run: ```bash node .agents/skills/_lib/pr-skills/pr-test-discover.mjs --worktree --head-sha --patch ``` The helper emits a JSON manifest with: - `recommendation.recommendedTier` - `recommendation.recommendationReason` - `touchedPackages[]` - `touchedPackages[].scripts` - `touchedPackages[].commands` - `touchedPackages[].addedOrModifiedExamples` - `touchedPackages[].exampleCommands` - `touchedPackages[].relatedExampleCommands` - `touchedPackages[].addedOrModifiedTests` - `touchedPackages[].relatedTests` - `touchedPackages[].sdkE2eSetup` — on the SDK package, and also on `packages/inference` if it's touched (a local inference build only reaches e2e through the SDK's setup, not a standalone inference build) Discovery is based on committed PR state only. Do not run `git diff`, `git status`, or `git ls-files --modified` inside the worktree for classification. Use `touchedPackages[].commands.install` and `touchedPackages[].commands.build` as package-root setup steps for all executable tiers. These setup commands belong before changed examples, related examples, non-SDK tests, or SDK manual e2e command blocks. ## Tier Ladder All tiers include necessary install/build setup for the touched package roots. - **T1 - examples**: run package-root install/build setup, then added/modified examples. If no examples were added or modified, mark the examples step `not applicable`. - **T2 - changed e2e/tests on desktop**: SDK runs changed `e2e` tests on desktop. Non-SDK runs the smallest unit-level package script (`test:unit` or `test`), or first available `test:*`. - **T3 - changed e2e/tests on mobile**: SDK adds changed e2e on selected mobile platform (`android` or `ios`). Non-SDK uses mobile scripts only if package.json exposes them. - **T4 - smoke desktop**: SDK runs `--suite smoke` on desktop. Non-SDK advances to the next least-to-most-complete script if one exists. - **T5 - smoke mobile**: SDK runs `--suite smoke` on selected mobile platform. Non-SDK uses mobile scripts only if package.json exposes them. - **T6 - full desktop**: SDK runs the full desktop suite. Non-SDK runs `test:all` if present, otherwise all applicable `test:*` scripts in increasing completeness order. - **T7 - full mobile**: SDK runs the full selected mobile suite. Non-SDK uses mobile/full scripts only if package.json exposes them. T2 and every higher tier are additive over T1. If `exampleCommands` is non-empty, the proposed command plan for T1/T2/T3/T4/T5/T6/T7 MUST include package-root install/build setup first, then every changed example command before the e2e/smoke/full test command. Do not summarize examples as "applicable" without emitting runnable commands. Changed helper files under examples, such as `shared.ts` or `utils.ts`, should be listed as supporting files but not emitted as runnable commands. Related examples and tests are bundled into the existing tiers as proposal items, not separate options: - `relatedExampleCommands` are examples that appear semantically related to the changed paths. Prefer safe examples first: no obvious required input/device and no obvious output-file generation. Present them after changed examples as "related examples proposed by discovery", and let the user deselect them before agent execution. - `relatedTests` are existing SDK e2e filters related to the changed paths. If no e2e files changed, use the highest-scoring related filter as the proposed T2 filter. If e2e files did change, show related filters as optional additions. - Example: a transcription SDK change should propose transcription examples and the `transcription` e2e filter even if the PR did not edit those files directly. Changed examples are agent-run steps after package-root install/build setup succeeds. SDK `e2e` setup is **not** agent-run; hand it to the user together with the e2e command because it requires npm auth. T6/T7 replace the smoke step from T4/T5. T1-T3 still run unchanged. ## Recommendation policy Always show the recommendation before the tier prompt. The user can override it. - **SDK (`packages/sdk`) default**: recommend **T2**. This covers install/build, changed examples if present, and changed e2e on desktop. Mobile is opt-in because it is slower and usually covered by CI. - **Non-SDK default**: recommend the smallest tier that includes at least unit-level validation. Usually T2. - **`packages/inference` touched**: discovery attaches `sdkE2eSetup` / `sdkE2eCwd` to it, but inference has no e2e or examples of its own, so the non-SDK default above would leave the setup command with nothing to run after it. Pair it with an SDK e2e run in `sdkE2eCwd` and recommend **T4** (`--suite smoke` on desktop) — that is what CI runs for an inference change, and with no changed e2e files T2 has no filter to work from. If the PR also touches `packages/sdk/e2e`, use that package's changed tests / `relatedTests` filter instead. - **No examples**: if no changed or related examples are discovered, mark examples `not applicable`. - **No tests discovered**: recommend install/build only and ask the user to confirm build-only validation. - **Mixed PRs**: recommend the highest minimum required by any touched package. Example: SDK + addon changes means SDK T3 plus addon unit scripts. Use `AskQuestion` for tier selection. Ask for `android` or `ios` only when the recommended or selected tier includes mobile (`T3`, `T5`, or `T7`). The tier prompt MUST include `T1` whenever `exampleCommands` or `relatedExampleCommands` is non-empty, even when the recommended tier is higher. Do not hide lower additive tiers. If examples are absent, show T1 as `not applicable` or omit it with an explicit "no changed or related examples" note in the plan. Before executing examples, show both changed and related example commands. Related examples are proposed, not mandatory; use `AskQuestion` to let the user choose which related examples to include when any are present. ## SDK-specific handling SDK changed examples may be agent-run inside the prepared worktree after the SDK package root has been installed and built. SDK `e2e` setup and e2e commands are manual/user-run: - `npm run install:build` - `npm run install:build:full` - `npx qvac-test run:local:*` Do not execute those agentically. `e2e` setup needs npm/GitHub Packages auth that is not available in the agent context, and SDK e2e commands are device/broker-dependent and may run for a long time. ## SDK e2e setup For any SDK e2e command, run setup from `packages/sdk/e2e` first, using the exact command from `touchedPackages[].sdkE2eSetup.command` in the discovery manifest — do not re-derive it from which files changed. It resolves to `install:build:full` whenever the PR touches `packages/sdk` outside `e2e/` or `packages/inference` at all, even if `packages/inference` itself has no diff lines: CI always builds `packages/inference` from the branch for SDK e2e (`inference-source: branch` is unconditional in `on-pr-test-sdk.yml`), because the checked-out `packages/inference` can already be ahead of the last npm publish from unrelated merged PRs — testing the branch's SDK against the *published* range (what `install:build` alone would do) can silently diverge from what CI tests. Only a PR limited to `packages/sdk/e2e/` resolves to the lighter `install:build`. Do not skip setup based on assumed previous state. The PR worktree is treated as clean/synchronized, and SDK e2e validation must prepare the test package explicitly. Do not separately run `bun install` or `bun run build` in `packages/sdk` before SDK e2e unless the chosen tier also includes non-e2e SDK example validation that specifically needs it. ## SDK e2e manual execution For SDK e2e tiers, print the `e2e` setup command and e2e command for the user to run manually. The agent must not run `npm run install:build`, `npm run install:build:full`, or `npx qvac-test run:local:*` from `packages/sdk/e2e`. Generate commands for the user's shell/OS. Do not assume POSIX-only utilities or paths. In particular: - Use paths emitted by the discovery manifest; they are platform-specific. - Use `mkdir -p` only for POSIX shells. For PowerShell, use `New-Item -ItemType Directory -Force`. - Prefer environment variable syntax for the user's shell (`export NAME=...` for POSIX, `$env:NAME = "..."` for PowerShell). - If unsure which shell the user will run manually, provide both POSIX and PowerShell variants. Run ID format: ```text pr---- ``` Report directory: ```text /packages/sdk/e2e/reports// ``` Manual command block shape for POSIX shells: ```sh export QVAC_PR_TEST_RUN_ID=pr-1234-abcdef0-t3-android export QVAC_PR_TEST_REPORT_DIR=/packages/sdk/e2e/reports/$QVAC_PR_TEST_RUN_ID mkdir -p $QVAC_PR_TEST_REPORT_DIR/logs cd /packages/sdk/e2e npm run install:build:full npx qvac-test run:local:desktop --filter vision- --runId $QVAC_PR_TEST_RUN_ID --report-dir $QVAC_PR_TEST_REPORT_DIR npx qvac-test run:local:android --filter vision- --runId $QVAC_PR_TEST_RUN_ID --report-dir $QVAC_PR_TEST_REPORT_DIR ``` Manual command block shape for PowerShell: ```powershell $env:QVAC_PR_TEST_RUN_ID = "pr-1234-abcdef0-t3-android" $env:QVAC_PR_TEST_REPORT_DIR = "/packages/sdk/e2e/reports/$env:QVAC_PR_TEST_RUN_ID" New-Item -ItemType Directory -Force "$env:QVAC_PR_TEST_REPORT_DIR/logs" Set-Location "/packages/sdk/e2e" npm run install:build:full npx qvac-test run:local:desktop --filter vision- --runId $env:QVAC_PR_TEST_RUN_ID --report-dir $env:QVAC_PR_TEST_REPORT_DIR npx qvac-test run:local:android --filter vision- --runId $env:QVAC_PR_TEST_RUN_ID --report-dir $env:QVAC_PR_TEST_REPORT_DIR ``` Agent-owned SDK setup and changed-example command shape for POSIX shells: ```sh cd /packages/sdk bun install bun run build bun run examples/.ts ``` Agent-owned SDK setup and changed-example command shape for PowerShell: ```powershell Set-Location "/packages/sdk" bun install bun run build bun run examples/.ts ``` The user runs the `e2e` setup command and the `qvac-test run:local:*` commands. The agent may run changed examples separately only after the required SDK package-root install/build state exists or has been prepared without `e2e` npm auth. Do not use `script` for log capture. It is not portable in this agent environment. For agent-run example steps, rely on terminal output. For user-run setup/e2e, rely on qvac-test's structured `--report-dir` output first; ask the user to paste terminal output only if setup fails before report files are produced or report files are missing/incomplete. Keep the `--runId` unchanged. When the user says the commands finished: 1. Inspect `/packages/sdk/e2e/reports//` first. Prefer qvac-test's structured report files over terminal logs. 2. Read supplemental terminal output only if the agent captured any for setup/example steps, or ask the user to paste terminal output if report files are missing/incomplete. 3. Summarize failures first, then passes and skipped/not-applicable steps. ## Non-SDK execution For non-SDK packages, show the proposed command list and ask for approval before execution. Each step must show: - `cwd` - command - why it is included - expected log path Run commands one at a time inside the worktree. Capture logs to: ```text /qvac-pr-test/pr-//.log ``` Abort on first non-zero exit unless the user explicitly opted into continuing after failures. ## Output format Before executing or asking the user to run anything, print: ```markdown ## PR # - test plan Recommended tier: Reason: Touched packages: - `` - , Changed examples: - `` - runnable/not runnable Related examples proposed: - `` - safe/needs input/writes output, include by default? Related e2e filters proposed: - `` - why Proposed commands: 1. `` - `` - Manual-run required: ``` After execution or log analysis, print: ```markdown ## PR # - test results ### Failed ### Passed ### Not applicable Logs: `` ``` ## References - Shared worktree prep: `.agents/skills/_lib/pr-skills/worktree-prepare.mjs` - Discovery helper: `.agents/skills/_lib/pr-skills/pr-test-discover.mjs` - Generic discovery helpers: `.agents/skills/_lib/pr-skills/pr-test-generic.mjs` - SDK-specific discovery heuristics: `.agents/skills/_lib/pr-skills/pr-test-sdk.mjs` - Shared worktree library: `.agents/skills/_lib/pr-skills/worktree.mjs` - SDK e2e guidance: `packages/sdk/e2e/AGENTS.md` - SDK e2e scripts: `packages/sdk/e2e/package.json` - SDK e2e docs: `packages/sdk/e2e/README.md`