e2e ยท diff
git:20260515.5b0a0f5 to git:20260815.5a2e1cd
84 added, 143 removed. Audit A to A.
---
name: e2e
- description: Run end-to-end OTA verification for `examples/v0.85.0` with `agent-device`. Use when validating iOS or Android release builds, deploying OTA bundles with `pnpm hot-updater deploy`, checking stable update application, reproducing rollback after a crash bundle, or reading bundle-store metadata and crash history for the v0.85.0 example app.
+ description: Run Release Catalog OTA verification for `examples/v0.85.0` with the route-based example and `agent-device`. Use for release builds, Release/Bundle selection, catalog policy, artifact install, rollout, runtime channels, and crash recovery.
---
- # Hot Updater V0.85 E2E
-
- Use this skill for `examples/v0.85.0` OTA verification only.
+ # Hot Updater V0.85 Release Catalog E2E
- Always load and follow [$agent-device](../agent-device/SKILL.md) for device interaction.
+ Use this skill only for `examples/v0.85.0`. Always load and follow
+ [$agent-device](../agent-device/SKILL.md), then read
+ [references/runtime-targets.md](references/runtime-targets.md).
- Do not encode a fixed test scenario in this skill. The caller provides the scenario. This skill only supplies fixed targets, guardrails, command templates, and inspection helpers for `examples/v0.85.0`.
+ The caller supplies the scenario. Keep its intent and choose assertions at the
+ correct identity layer: Release for selection/policy, Bundle for bytes,
+ patches, manifests, storage, and crash history.
## Rules
- - Run iOS and Android sequentially. Do not overlap platform runs.
- - Complete the full iOS flow or the full Android flow first, then move to the other platform. Never execute both platforms at the same time.
- - Use `agent-device snapshot`; do not use screenshots unless the user explicitly asks.
- - Do not register bundles directly in the standalone DB. Create test bundles only through `pnpm hot-updater deploy ...`.
- - Use release binaries only for OTA validation. Do not use debug builds or Metro-attached runs for this skill.
- - Rebuild the native app after native package changes. `pnpm -w build` alone is not enough for simulator/device validation.
- - Treat `notifyAppReady` as read-only. It must not affect crash detection, rollback, or promotion.
- - Public launch status should only be `STABLE` or `RECOVERED`.
- - For crash-bundle scenarios, the crash must happen at module top level, outside
- the React component. Do not rely on `useEffect`, render-time component code,
- or UI-triggered throws for rollback validation.
-
- ## Fixed Targets
-
- Read [references/runtime-targets.md](references/runtime-targets.md) before running anything.
-
- ## Prerequisites
-
- Before running any caller-provided scenario:
-
- 1. Run `pnpm -w build`.
- 2. Confirm the standalone update server is running by checking `http://localhost:3007/hot-updater/version`.
- 3. Use the exact example workspace: `examples/v0.85.0`.
- 4. Use release artifacts only.
- 5. Choose one platform first. Finish that platform end-to-end before starting the other one.
-
- ## Command Templates
-
- Use these as building blocks. Pick only what the caller's scenario needs.
-
- Run these templates for one platform at a time. Do not keep iOS and Android sessions active in parallel.
-
- ### iOS Build And Install
-
- ```bash
- agent-device ensure-simulator --platform ios --device "iPhone 16" --boot
-
- cd <repo-root>/examples/v0.85.0/ios
-
- pnpx pod-install
-
- xcodebuild -workspace HotUpdaterExample.xcworkspace \
- -scheme HotUpdaterExample \
- -configuration Release \
- -sdk iphonesimulator \
- -destination 'id=<simulator-udid>' \
- -derivedDataPath /tmp/hotupdater-v085-ios-e2e build
-
- agent-device reinstall HotUpdaterExample \
- /tmp/hotupdater-v085-ios-e2e/Build/Products/Release-iphonesimulator/HotUpdaterExample.app \
- --platform ios \
- --device "iPhone 16"
-
- agent-device open org.reactjs.native.example.HotUpdaterExample \
- --platform ios \
- --device "iPhone 16" \
- --session qa-ios-v085 \
- --relaunch
- ```
-
- ### Android Build And Install
-
- ```bash
- cd <repo-root>/examples/v0.85.0/android
-
- ./gradlew :app:assembleRelease --rerun-tasks
-
- agent-device reinstall com.hotupdaterexample \
- <repo-root>/examples/v0.85.0/android/app/build/outputs/apk/release/app-release.apk \
- --platform android \
- --serial <serial>
+ - Run iOS and Android sequentially with release binaries. Never overlap runs or
+ validate through Metro/debug builds.
+ - Run `pnpm -w build` and rebuild the native app after native package changes.
+ - Deploy only through `pnpm hot-updater deploy`; never seed Bundle or Release
+ rows directly.
+ - Capture both `bundleId` and the Release created for it. The Bundle ID remains
+ available in `dist/manifest.json`; resolve the Release through `hot-updater
+ release list/show --json` or the Detox deploy result.
+ - Use `agent-device snapshot -i`; use screenshots only when asked.
+ - Public launch statuses are exactly `UNCHANGED | UPDATE_APPLIED | RECOVERED`.
+ Directional identity is `fromReleaseId`, `fromBundleId`, `toReleaseId`, and
+ `toBundleId`. Do not expect `STABLE`, `PROMOTED`, or `crashedBundleId`.
+ - `notifyAppReady` is read-only. It must not affect crash detection, rollback,
+ or receipt promotion.
+ - Crash bundles must throw at module scope. Do not use `useEffect`, component
+ rendering, or a UI action for the crash.
- agent-device open com.hotupdaterexample \
- --platform android \
- --serial <serial> \
- --session qa-android-v085 \
- --relaunch
- ```
+ ## Fixed Targets And Build Commands
- ### OTA Deploy
+ Use the exact commands and app identifiers in `references/runtime-targets.md`.
+ The standalone server readiness URL is
+ `http://localhost:3007/hot-updater/version`.
- Run deploy from `<repo-root>/examples/v0.85.0`.
+ Deploy from `<repo-root>/examples/v0.85.0`:
```bash
pnpm hot-updater deploy -p ios -t 1.0.x
pnpm hot-updater deploy -p android -t 1.0.x
```
- ### Snapshot And State Inspection
+ ## Route-Based Example Contract
- ```bash
- agent-device snapshot -i
- agent-device diff snapshot -i
- <repo-root>/.agents/skills/e2e/scripts/inspect_ios_state.sh
- <repo-root>/.agents/skills/e2e/scripts/inspect_android_state.sh
- ```
+ The example has one focused target per deep-link route. Open the route that
+ owns the assertion and take a fresh snapshot; do not search a scroll-heavy
+ main page.
- The example UI is scrollable. Capture a top-of-screen snapshot first, then use
- `agent-device scrollintoview "<section title>"` and re-snapshot as each target
- section becomes visible. For most scenarios, inspect sections in this order:
+ | Evidence | Deep link | testID |
+ | --- | --- | --- |
+ | Bundle identity | `hotupdaterexample://e2e/runtime-bundle` | `runtime-bundle-id` |
+ | Release receipt, selection kind, authority, scope, generation, high-water, channel, context | `hotupdaterexample://e2e/runtime-release-state` | `runtime-release-state` |
+ | Manifest bytes | `hotupdaterexample://e2e/runtime-large-asset` | `runtime-large-e2e-asset` |
+ | Scenario marker | `hotupdaterexample://e2e/runtime-marker` | `runtime-scenario-marker` |
+ | Launch status | `hotupdaterexample://e2e/launch-status` | `launch-status-result` |
+ | Directional launch IDs | `hotupdaterexample://e2e/launch-transition` | `launch-transition-result` |
+ | Crash history count | `hotupdaterexample://e2e/crash-history-count` | `crash-history-count` |
+ | Install current channel | `hotupdaterexample://e2e/action/install-current-channel-update` | `action-install-current-channel-update` |
+ | Install runtime channel | `hotupdaterexample://e2e/action/install-runtime-channel-update` | `action-install-runtime-channel-update` |
+ | Update action result | `hotupdaterexample://e2e/update-action-result` | `update-action-result` |
- 1. `Runtime Snapshot`
- 2. `Launch Status`
- 3. `Crash History`
- 4. Optional deeper sections such as `Manifest Assets`, `Runtime Details`, and
- `Actions`
+ The action text distinguishes `installed Release <R> / Bundle <B>`, `adopted
+ Release <R> / Bundle <B>`, `selected EMBEDDED Release <R>`, `selected
+ BUILTIN`, `no-update`, and `skipped`.
- Typical section navigation examples:
+ ## Detox Control Contract
- ```bash
- agent-device snapshot -i
- agent-device scrollintoview "Launch Status"
- agent-device snapshot -i
- agent-device scrollintoview "Crash History"
- agent-device snapshot -i
- ```
+ When driving the repository harness, use:
- ## Assertions
+ - deploy: `POST /e2e/jobs/deploy-bundle`, returning `bundleId`, `releaseId`,
+ `authorityId`, `scopeKey`, and `generation`;
+ - Release policy: `POST /e2e/jobs/patch-release` with `releaseId`;
+ - rollout samples: `POST /e2e/compute-rollout-sample` with `releaseId`;
+ - Bundle artifact assertions: keep using Bundle IDs;
+ - metadata waits/assertions: require Release receipts and catalog high-water;
+ - launch reports: assert directional Release and Bundle IDs;
+ - proxy controls: `/e2e/proxy-control`, `/e2e/proxy-state`, and
+ `/e2e/assert-proxy` for counts, exact-generation capture/freeze/replay, path
+ cardinality, zero-artifact assertions, and catalog/artifact delays.
- Apply these assertions only when they match the caller's scenario:
+ Catalog URLs are shared scope URLs and must not contain current/minimum Release
+ or Bundle IDs, install ID, cohort, or crash state.
- - Only expect public status values `STABLE` or `RECOVERED`.
- - Do not expect `PROMOTED`. Promotion is native-only and should not be surfaced to JS anymore.
- - `reload` must not affect launch outcome state.
- - `notifyAppReady` must be read-only.
- - Prefer asserting both UI snapshot and bundle-store metadata when possible.
- - For rollback checks, verify `crashedBundleId` and `crashed-history.json` together.
+ ## Assertions
- ## Optional Crash Patch Pattern
+ - Assert Release ID plus receipt fields for selection or policy behavior.
+ - Assert Bundle ID plus manifest/storage evidence for byte behavior.
+ - For same-Bundle adoption, assert a new Release receipt, no artifact request,
+ and no reload.
+ - For BUILTIN/EMBEDDED, assert the persisted selection kind and full receipt;
+ Bundle slots may be empty.
+ - For crash recovery, assert Bundle-keyed crash history, full restored receipt,
+ retained high-water, and directional Release+Bundle launch report.
+ - For rollout/target changes, keep the Release ID stable while catalog
+ generation advances and local context selection changes.
+ - For force update, observe the configured automatic reload; do not tap a
+ manual install/reload action.
- If the caller explicitly asks for a crash bundle, use a temporary patch like this and revert it immediately after deploy:
+ ## Crash Patch Pattern
+ Use a temporary module-scope patch and revert it immediately after deploy:
+
```ts
const E2E_SAFE_BUNDLE_IDS = new Set([
"<built-in-bundle-id>",
- "<current-stable-bundle-id>",
+ "<stable-bundle-id>",
]);
- const E2E_CURRENT_BUNDLE_ID = HotUpdater.getBundleId();
-
- if (!E2E_SAFE_BUNDLE_IDS.has(E2E_CURRENT_BUNDLE_ID)) {
+ if (!E2E_SAFE_BUNDLE_IDS.has(HotUpdater.getBundleId())) {
throw new Error("hot-updater e2e crash bundle");
}
```
- Place this patch at module scope, outside `App`, so the OTA bundle crashes
- while the JS module is being evaluated. A crash patch inside `App`,
- `useEffect`, or a button handler is not reliable enough for this rollback
- scenario and may fail to produce the intended crashing bundle.
-
## Reporting
- If the caller asks for a report, include:
-
- - Platform
- - Binary type used. This should always be `Release`.
- - Relevant deployed bundle ids
- - Final visible `status`
- - Final visible `crashedBundleId`, if any
- - Final metadata summary
- - Crash history summary
- - Whether the assertions came from UI snapshot, metadata, or both
-
- ## Notes
-
- - In this skill, `<repo-root>` means the checked-out repository root.
- - The example app already renders launch status and crash history in `examples/v0.85.0/App.tsx`.
- - The iOS installed bundle id is `org.reactjs.native.example.HotUpdaterExample`, even though `hot-updater.config.ts` uses `com.hotupdaterexample` for build config.
+ Report platform, release binary, deployed Release/Bundle pairs, final receipt
+ (kind/authority/scope/generation/high-water/channel/context), public status,
+ directional IDs, crash history, artifact evidence, and whether each assertion
+ came from a route snapshot, native metadata, or both.