git:20260915.50ff4c3 to git:20260918.ccad9f6

39 added, 164 removed. Audit B to B.

---
name: test-t3-mobile
- description: Launch and test T3 Code Mobile on an iOS Simulator or Android Emulator against disposable local T3 environments, including Metro and dev-client reuse, native rebuild decisions, per-client pairing, seeded projects, semantic UI control, screenshots, and iOS serve-sim streaming. Use after mobile UI or native changes, when reproducing phone or tablet behavior, pairing an emulator to isolated state, or verifying mobile behavior on macOS, Linux, or Windows.
+ description: Test T3 Code's native iOS and Android app through its Device panel and returned AgentDevice command. Use for mobile verification, native-client builds, Metro launch, and mobile pairing against isolated development state.
---
# Test T3 Mobile
- Run one focused, end-to-end mobile verification pass against disposable T3 state. Use the sibling [`test-t3-app`](../test-t3-app/SKILL.md) skill as the detailed reference for pairing-token semantics and SQLite fixtures.
-
- Command examples use POSIX shell syntax. On Windows, use PowerShell equivalents: set variables with `$env:NAME = "value"`, use an explicit temporary directory from `[System.IO.Path]::GetTempPath()`, and run multiline examples on one line or with PowerShell backticks. Use `$env:ANDROID_HOME\platform-tools\adb.exe` when `adb` is not already on `PATH`.
-
- ## Select a viable platform
-
- Inspect the host and the affected code before launching processes:
-
- - On macOS with Xcode, prefer one representative iOS Simulator when the change is cross-platform so the user can watch through serve-sim. Load and follow [`ios-debugger-agent`](../ios-debugger-agent/SKILL.md), and load [`ios-simulator-browser`](../ios-simulator-browser/SKILL.md) when live streaming is available.
- - On macOS, Linux, or Windows with the Android SDK, use one Android Emulator when Android is the affected surface or iOS tooling is unavailable.
- - When the change is platform-specific, test that platform. When neither platform is viable, report the missing SDK or emulator prerequisite rather than claiming verification. A missing development client is a build step, not a blocker.
-
- Do not treat unavailable iOS tooling as a blocker when Android is a valid representative target.
-
- ## Ensure a compatible native client
-
- Authorized mobile verification includes building and installing a development client. A missing, stale, or unknown native client is not a reason to skip verification or leave a PR in draft. Build and install it, then continue. Respect an explicit user instruction not to rebuild; otherwise do not ask for separate permission.
-
- Run this from the checkout being tested, on the machine that hosts the selected simulator or emulator. Select and boot one explicit iOS UDID or Android emulator serial first:
-
- ```bash
- node scripts/mobile-native-client.ts ensure ios <simulator-udid>
- node scripts/mobile-native-client.ts ensure android <emulator-serial>
- ```
-
- `ensure` compares the checkout's local Expo development fingerprint and the installed app's binary contents against the last successful build record. It reuses a matching client; otherwise it runs a clean prebuild, builds and installs the development app, and records the successful result. It does not start Metro. Start Metro below after it succeeds. On hosts with an `agent-job` requirement, run the entire `ensure` command through that queue.
-
- For a read-only decision, use `check` in place of `ensure`. Exit 0 means compatible, 2 means build required, and 1 means an operational error. An app installed outside this helper is initially unknown and gets rebuilt once. Records are local to the simulator host under `~/.cache/t3code/native-clients` and work across checkouts. Do not copy records between machines or write them manually.
-
- A JavaScript-only diff, bundle identifier, app version, or recent install date does not prove native compatibility. Always check the whole checkout. Expo fingerprints are computed locally with `APP_VARIANT=development`; no EAS credentials or cloud build are required. Generated `ios/` and `android/` directories are excluded by `.fingerprintignore`, so edit native source modules or config plugins rather than generated output.
-
- The development identity is `T3 Code Dev`, bundle/package `com.t3tools.t3code.dev`, scheme `t3code-dev`. If a build fails, investigate the build error and fix the local prerequisites. Report the concrete failure if it cannot be resolved, not “no compatible client.”
-
- ## Start one disposable T3 environment
-
- Run backend commands from the repository root. Use the ignored, worktree-local `.t3` directory or create a fresh directory with the host OS's temporary-directory mechanism. An explicit base directory stores state in `<base-dir>/userdata`; never point testing at shared `~/.t3` state.
-
- Seed a small number of meaningful Git projects before starting the backend:
-
- ```bash
- node apps/server/src/bin.ts project add <git-workspace> \
- --base-dir <base-dir> \
- --title <project-title>
- ```
-
- Running `project add` before the backend starts gives it exclusive offline database access. If a backend is already running, wait until it is ready so the CLI dispatches through the live server; never run offline mutations concurrently with the server.
-
- Use direct SQLite mutation only for disposable projection fixtures. Follow `test-t3-app` and stop the backend before writing.
-
- Start a headless backend after seeding:
-
- ```bash
- node apps/server/src/bin.ts serve \
- --host 127.0.0.1 \
- --port <server-port> \
- --base-dir <base-dir> \
- --no-browser
- ```
-
- Use these client origins:
-
- - iOS Simulator: `http://127.0.0.1:<server-port>`
- - Android Emulator: `http://10.0.2.2:<server-port>`
- - Physical device: bind the backend to `0.0.0.0` and use the host's reachable LAN origin
-
- Enter the complete `http://` origin to make the test transport explicit. Bare IP addresses default to HTTP, while bare hostnames default to HTTPS. When testing web and mobile together, run `vp run dev --home-dir <base-dir> --host 127.0.0.1` instead and do not launch a second backend over the same base directory.
-
- ## Start or reuse Metro safely
-
- Run Metro from `apps/mobile`.
-
- 1. Inspect any process on the intended Metro port and its `/status` response. Reuse it only when it is healthy, belongs to this worktree, and matches `APP_VARIANT=development`, `--dev-client`, and scheme `t3code-dev`.
- 2. Never kill another worktree's Metro. Use a free explicit port when necessary.
- 3. Run `vp run dev:client` on the standard port. For another port, retain the complete development identity:
+ ## Open the device
- ```bash
- APP_VARIANT=development vp exec expo start \
- --dev-client \
- --scheme t3code-dev \
- --lan \
- --port <metro-port>
- ```
+ Call `device_list`, then `device_open` with the selected host and device IDs.
+ T3 boots the device and shows its live stream in the Device panel. Follow its
+ returned `quickStart`, using the exact `agentDevice.command` and all `targetArgs`
+ on every operation. Use `device_screenshot` to inspect the screen.
- In PowerShell, set `$env:APP_VARIANT = "development"` first and then run the `vp exec expo start ...` command without the leading assignment.
+ If T3 device tools or the selected device are unavailable, report the blocker
+ and stop verification. Do not install or switch to another automation system.
- 4. Open the exact development-client URL for the selected device and confirm the loaded bundle belongs to this worktree and Metro port.
+ ## Use an isolated backend
- ### iOS launch
+ Reuse this task's healthy backend. Otherwise run `vp run dev` from the
+ repository root, retain its terminal session, and read the actual backend port
+ from the dev-runner output. Use the worktree's ignored `.t3` state. Never run
+ against `~/.t3/userdata`. The Browser panel is not required for this workflow.
- Use `ios-debugger-agent` to select one UDID and set these XcodeBuildMCP session defaults:
+ Test with meaningful project and thread data. Read the shared
+ [SQLite fixture reference](../test-t3-app/references/sqlite-fixtures.md) only
+ when inspecting or seeding SQLite. Stop the test server before fixture writes.
- - Workspace: `<repo>/apps/mobile/ios/T3CodeDev.xcworkspace`
- - Scheme: `T3CodeDev`
- - Configuration: `Debug`
- - Simulator ID: the selected UDID
- - Bundle ID: `com.t3tools.t3code.dev`
+ ## Launch T3 Code Dev
- After `ensure` succeeds, open the Metro URL:
+ From the checkout being tested on the selected device host, run:
```bash
- xcrun simctl openurl <simulator-udid> <printed-dev-client-url>
+ node scripts/mobile-native-client.ts ensure <ios|android> <device-id>
```
- Accept the iOS confirmation prompt and dismiss the developer menu when it obscures the app.
-
- ### Android launch
-
- Use the emulator serial already checked by `ensure`:
-
- ```bash
- adb -s <emulator-serial> reverse tcp:<metro-port> tcp:<metro-port>
- adb -s <emulator-serial> shell am start -W \
- -a android.intent.action.VIEW \
- -d '<printed-dev-client-url>' \
- com.t3tools.t3code.dev
- ```
+ This reuses a matching native client or builds and installs one. Authorized
+ mobile verification includes that build step unless the user prohibits it.
- Do not start, stop, erase, or reconfigure an emulator owned by another task. Track and later stop only processes owned by this test.
+ Start `vp run dev:client` from `apps/mobile`, or reuse a healthy Metro belonging
+ to this checkout. Open its printed development-client URL with AgentDevice
+ `open com.t3tools.t3code.dev <url>` and all returned target arguments.
+ The device must be able to reach both Metro and the isolated backend.
- ## Pair each client once
+ ## Pair and verify
- Use the bundled helper from the repository root. It issues a fresh credential against the running backend's exact base directory, opens the existing Add Environment route with the credential in an encoded query parameter, and asks that route to connect once:
+ Use the helper from the repository root, with the returned executable and target
+ arguments stored in `agent_device_command` and the Bash array
+ `agent_device_target_args`:
```bash
.agents/skills/test-t3-mobile/scripts/pair-client.sh \
- ios <simulator-udid> <server-port> <base-dir>
-
- .agents/skills/test-t3-mobile/scripts/pair-client.sh \
- android <emulator-serial> <server-port> <base-dir>
- ```
-
- Run only the command for the selected platform. The helper uses `http://127.0.0.1:<server-port>` for iOS and `http://10.0.2.2:<server-port>` for Android. Pass a fifth argument only when testing a non-development URL scheme.
-
- The helper opens this registered route:
-
- ```text
- t3code-dev://connections/new?pairingUrl=<encoded-pairing-url>&autoConnect=1
+ <server-port> <base-dir> <device-reachable-backend-origin> \
+ "$agent_device_command" "${agent_device_target_args[@]}"
```
- The Add Environment route owns the behavior: `pairingUrl` prefills its normal host and token inputs, while `autoConnect=1` submits once in development builds and returns to Home after success. Without `autoConnect`, the same route only prefills the form for manual inspection.
-
- Do not enter pairing hosts or tokens through simulator keyboard automation. Xcode's semantic typer sends HID-style key events through the simulator's active keyboard state, which can corrupt uppercase tokens and punctuation even when the host Mac uses a U.S. input source. The one-shot route is the deterministic pairing path. Use the visible form only as a fallback, and paste credentials rather than typing them character by character.
-
- Verify the expected seeded projects appear before exercising the affected flow.
-
- Pairing credentials are secret, short-lived, and single-use. Create a different credential for every simulator, emulator, physical device, or browser. If an attempt fails, issue a new credential rather than retrying the old one. Do not expose tokens in screenshots, commits, or final responses.
-
- ## Drive and observe the affected flow
-
- ### iOS
-
- Use `snapshot_ui` and current element references from XcodeBuildMCP for taps and typing. Stream the same UDID through `ios-simulator-browser` so the user can watch in T3 Code when the host supports it. Use the stream as a visual feed rather than a reason to switch to fragile browser coordinates.
-
- ### Android
-
- Prefer semantic Android automation exposed by the current agent host. Otherwise inspect the current hierarchy with `adb shell uiautomator dump`, target stable resource IDs, content descriptions, text, or bounds, and use scoped `adb shell input` actions. Refresh the hierarchy after navigation. Capture the final state with `adb exec-out screencap -p`.
-
- Android does not use serve-sim. Use a browser-compatible Android mirror when the host already provides one; otherwise return focused emulator screenshots as evidence rather than installing unrelated streaming infrastructure during verification.
-
- ## Verify and clean up
-
- Exercise only the affected flow on one representative device unless the change specifically concerns platform, OS version, or screen size. Before finishing:
-
- 1. Confirm the app connected to the intended disposable environment instead of merely rendering an empty disconnected state.
- 2. Capture the relevant final state.
- 3. Remove the disposable environment from T3 Code Dev.
- 4. Remove any `adb reverse` rule created for this test with `adb -s <emulator-serial> reverse --remove tcp:<metro-port>`.
- 5. Stop only the serve-sim, Metro, backend, emulator, and log processes started by this test.
- 6. Remove only base directories and temporary Git repositories deliberately created for this test. Preserve them when they contain useful reproduction evidence.
-
- Keep local verification focused. Do not turn this workflow into a full repository test run.
-
- ## Troubleshoot predictable failures
+ It issues a fresh credential and opens T3 Code Dev's existing pairing route
+ through AgentDevice. For a backend on the device host, use
+ `http://127.0.0.1:<server-port>` on iOS or `http://10.0.2.2:<server-port>`
+ on Android. For a remote backend, use its reachable origin.
- - **Old UI or an old error appears:** verify Metro's worktree, variant, URL, and port before diagnosing the app.
- - **Metro serves stale or invalid transforms after those checks:** stop the owned Metro process and run `vp run dev:client:reset` once on the standard port. For a custom port, add `--clear` to the complete explicit `expo start` command above.
- - **The environment remains empty:** verify the platform-specific HTTP origin, use a fresh token, and confirm project seeding used the identical base directory.
- - **A second client cannot pair:** pairing tokens are single-use; issue another token.
- - **The pairing form opens but does not connect:** confirm the deep link uses the existing `connections/new` route, includes `autoConnect=1`, and carries a freshly minted encoded `pairingUrl`.
- - **Pairing text changes case or punctuation:** do not retry semantic typing. Use `scripts/pair-client.sh`; the simulator keyboard layout and HID input path are not reliable for credentials.
- - **iOS semantic actions fail:** set explicit XcodeBuildMCP defaults and refresh with `snapshot_ui`.
- - **Android cannot reach Metro:** verify `adb reverse` for the exact Metro port and relaunch the development-client URL.
- - **Android cannot reach the backend:** use `10.0.2.2`, not `127.0.0.1`, for the Android Emulator.
+ Confirm the intended projects appear, exercise the affected flow, and capture
+ evidence. Retain the app and environment while iterating. At teardown, remove
+ the disposable connection, close the AgentDevice session, call `device_close`,
+ and stop only your backend and Metro processes.