peachsim 0.1.527
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +22 -0
- package/README.md +640 -0
- package/cli/app-config.ts +82 -0
- package/cli/app-fonts.ts +388 -0
- package/cli/app-project.ts +59 -0
- package/cli/app-splash.ts +171 -0
- package/cli/app-state-reset.ts +26 -0
- package/cli/auth.ts +184 -0
- package/cli/bin.ts +59 -0
- package/cli/bridge-diagnostics.ts +226 -0
- package/cli/bridge-flow-runner.ts +2806 -0
- package/cli/browser-backend.ts +44 -0
- package/cli/browser-evals.ts +96 -0
- package/cli/cli-update.ts +261 -0
- package/cli/cloud-client.ts +1530 -0
- package/cli/cloud-dispatch.ts +206 -0
- package/cli/cloud-session.ts +227 -0
- package/cli/command-contract.ts +221 -0
- package/cli/command-registry.ts +304 -0
- package/cli/commands/agent-wrapper.ts +1048 -0
- package/cli/commands/agent.ts +439 -0
- package/cli/commands/app-fonts.ts +99 -0
- package/cli/commands/assert.ts +542 -0
- package/cli/commands/auth.ts +71 -0
- package/cli/commands/box/bundle-plane.ts +71 -0
- package/cli/commands/box/checkout-plane.ts +256 -0
- package/cli/commands/box/plane-share.ts +208 -0
- package/cli/commands/box/rnx-command.ts +60 -0
- package/cli/commands/box/search-command.ts +157 -0
- package/cli/commands/box.ts +925 -0
- package/cli/commands/camera.ts +266 -0
- package/cli/commands/cleanup.ts +169 -0
- package/cli/commands/compat.ts +176 -0
- package/cli/commands/config.ts +34 -0
- package/cli/commands/control.ts +2154 -0
- package/cli/commands/cpu-profile.ts +941 -0
- package/cli/commands/daemon-mac-app.ts +165 -0
- package/cli/commands/daemon.ts +800 -0
- package/cli/commands/debug.ts +751 -0
- package/cli/commands/desktop.ts +39 -0
- package/cli/commands/detect.ts +201 -0
- package/cli/commands/detox.ts +481 -0
- package/cli/commands/device.ts +134 -0
- package/cli/commands/diagnose.ts +589 -0
- package/cli/commands/do-chain.ts +408 -0
- package/cli/commands/electron.ts +94 -0
- package/cli/commands/film.ts +379 -0
- package/cli/commands/flow.ts +1240 -0
- package/cli/commands/inspect/actions.ts +516 -0
- package/cli/commands/inspect/core.ts +2086 -0
- package/cli/commands/inspect/count.ts +17 -0
- package/cli/commands/inspect/describe.ts +119 -0
- package/cli/commands/inspect/env.ts +25 -0
- package/cli/commands/inspect/find.ts +169 -0
- package/cli/commands/inspect/get-layout.ts +53 -0
- package/cli/commands/inspect/keyboard.ts +54 -0
- package/cli/commands/inspect/list.ts +175 -0
- package/cli/commands/inspect/memory.ts +215 -0
- package/cli/commands/inspect/redaction.ts +39 -0
- package/cli/commands/inspect/resolve-target.ts +77 -0
- package/cli/commands/inspect/screens.ts +78 -0
- package/cli/commands/inspect/settle.ts +32 -0
- package/cli/commands/inspect/settling.ts +197 -0
- package/cli/commands/inspect/shared.ts +259 -0
- package/cli/commands/inspect/sleep.ts +15 -0
- package/cli/commands/inspect/tree.ts +23 -0
- package/cli/commands/inspect/url.ts +17 -0
- package/cli/commands/inspect/wait-event.ts +211 -0
- package/cli/commands/inspect/wait-idle.ts +25 -0
- package/cli/commands/inspect/wait-ready.ts +87 -0
- package/cli/commands/inspect/wait-selector.ts +59 -0
- package/cli/commands/inspect/wait.ts +32 -0
- package/cli/commands/inspect.ts +4738 -0
- package/cli/commands/install-cli.ts +275 -0
- package/cli/commands/install-desktop.ts +385 -0
- package/cli/commands/login.ts +357 -0
- package/cli/commands/logout.ts +24 -0
- package/cli/commands/maestro-generate.ts +375 -0
- package/cli/commands/maestro.ts +536 -0
- package/cli/commands/mode.ts +58 -0
- package/cli/commands/no-bridge-hint.ts +80 -0
- package/cli/commands/perf.ts +67 -0
- package/cli/commands/permissions.ts +203 -0
- package/cli/commands/platform.ts +410 -0
- package/cli/commands/preview.ts +103 -0
- package/cli/commands/profile.ts +106 -0
- package/cli/commands/react.ts +353 -0
- package/cli/commands/record.ts +1435 -0
- package/cli/commands/report-issue.ts +305 -0
- package/cli/commands/reset.ts +89 -0
- package/cli/commands/runtime.ts +348 -0
- package/cli/commands/screenshot-command.ts +106 -0
- package/cli/commands/screenshot-layers.ts +144 -0
- package/cli/commands/screenshot-mode.ts +38 -0
- package/cli/commands/screenshot.ts +492 -0
- package/cli/commands/screenshots-capture.ts +608 -0
- package/cli/commands/screenshots.ts +127 -0
- package/cli/commands/serve.ts +139 -0
- package/cli/commands/setup.ts +416 -0
- package/cli/commands/shell-boolean-mode.ts +82 -0
- package/cli/commands/skills.ts +468 -0
- package/cli/commands/slides.ts +357 -0
- package/cli/commands/state.ts +94 -0
- package/cli/commands/storage.ts +58 -0
- package/cli/commands/telemetry.ts +55 -0
- package/cli/commands/test.ts +535 -0
- package/cli/commands/three-mode.ts +771 -0
- package/cli/commands/timeline.ts +121 -0
- package/cli/commands/upgrade.ts +167 -0
- package/cli/commands/upload.ts +1203 -0
- package/cli/commands/version.ts +63 -0
- package/cli/commands/welcome.ts +17 -0
- package/cli/commands/what-happened.ts +328 -0
- package/cli/current-sim.ts +217 -0
- package/cli/desktop-companion.ts +315 -0
- package/cli/drivers/electron.ts +70 -0
- package/cli/drivers/index.ts +20 -0
- package/cli/drivers/playwright-provisioning.ts +184 -0
- package/cli/drivers/playwright-sim-host.ts +537 -0
- package/cli/drivers/playwright.ts +209 -0
- package/cli/drivers/registry.ts +65 -0
- package/cli/drivers/types.ts +102 -0
- package/cli/flow-export.ts +55 -0
- package/cli/flow-file.ts +142 -0
- package/cli/flow-live-status.ts +126 -0
- package/cli/flow-session.ts +140 -0
- package/cli/help-core.ts +143 -0
- package/cli/help.ts +44 -0
- package/cli/hidden-runtime-alias.ts +19 -0
- package/cli/hints.ts +214 -0
- package/cli/inspect-notice-state.ts +114 -0
- package/cli/internal-child.ts +176 -0
- package/cli/maestro-js.ts +323 -0
- package/cli/main.ts +704 -0
- package/cli/open-url.ts +8 -0
- package/cli/outbound-endpoints.ts +830 -0
- package/cli/parent-pid.ts +204 -0
- package/cli/parse-args.ts +189 -0
- package/cli/privacy.ts +53 -0
- package/cli/prompt.ts +56 -0
- package/cli/recording-access.ts +108 -0
- package/cli/registry.ts +2 -0
- package/cli/resolve-assets.ts +63 -0
- package/cli/rnx-in-process.ts +98 -0
- package/cli/run-registry.ts +226 -0
- package/cli/run-rnx-core.ts +148 -0
- package/cli/run-rnx.ts +137 -0
- package/cli/runtime-notes.ts +66 -0
- package/cli/runtime-summary.ts +25 -0
- package/cli/secure-file.ts +31 -0
- package/cli/self-invocation.ts +58 -0
- package/cli/send-to-box.ts +109 -0
- package/cli/setup-repository.ts +191 -0
- package/cli/shell-init.ts +98 -0
- package/cli/standalone.ts +4 -0
- package/cli/telemetry.ts +84 -0
- package/cli/ui.ts +68 -0
- package/cli/ws-bridge.ts +1020 -0
- package/detox/attempt-events.cjs +23 -0
- package/detox/colors.ts +54 -0
- package/detox/config-loader.ts +135 -0
- package/detox/element-types.ts +48 -0
- package/detox/expectations.ts +534 -0
- package/detox/gestures.ts +501 -0
- package/detox/index.ts +2694 -0
- package/detox/jest-preset.cjs +29 -0
- package/detox/jest-setup-after-env.cjs +22 -0
- package/detox/matchers.ts +30 -0
- package/detox/motion-change.cjs +109 -0
- package/detox/motion-change.d.cts +35 -0
- package/detox/navigation-lifecycle.ts +290 -0
- package/detox/navigation.ts +43 -0
- package/detox/proof-frame.cjs +114 -0
- package/detox/record-block-execution.cjs +78 -0
- package/detox/screenshots/animated-color-test-rest-norngh.png +0 -0
- package/detox/screenshots/color-test-after-drag-norngh.png +0 -0
- package/detox/screenshots/color-test-rest-norngh.png +0 -0
- package/detox/screenshots/theme-blue-toggle.png +0 -0
- package/detox/screenshots/theme-blue.png +0 -0
- package/detox/screenshots/theme-red-toggle.png +0 -0
- package/detox/screenshots/theme-red.png +0 -0
- package/dist-lib/agent-daemon-client.cjs +502 -0
- package/dist-lib/agent-events.cjs +48 -0
- package/dist-lib/agent-identity.cjs +53 -0
- package/dist-lib/agent-sessions.cjs +759 -0
- package/dist-lib/attached-projects.cjs +526 -0
- package/dist-lib/auth/shared-session.cjs +208 -0
- package/dist-lib/backend-origin.cjs +88 -0
- package/dist-lib/beta.cjs +41 -0
- package/dist-lib/beta.mjs +13 -0
- package/dist-lib/bridge-constants.cjs +161 -0
- package/dist-lib/bridge-contract-input.cjs +451 -0
- package/dist-lib/bridge-contract-input.mjs +414 -0
- package/dist-lib/bridge-contract.cjs +130 -0
- package/dist-lib/bridge-contract.mjs +94 -0
- package/dist-lib/capture-contract.cjs +220 -0
- package/dist-lib/capture-contract.mjs +190 -0
- package/dist-lib/cli-constants.cjs +32 -0
- package/dist-lib/cloud-contract.cjs +194 -0
- package/dist-lib/cloud-contract.mjs +145 -0
- package/dist-lib/cloud.cjs +670 -0
- package/dist-lib/cloud.mjs +639 -0
- package/dist-lib/config.cjs +96 -0
- package/dist-lib/detox/index.cjs +3789 -0
- package/dist-lib/detox/jest-preset.cjs +29 -0
- package/dist-lib/dev-bundle-resolution.cjs +290 -0
- package/dist-lib/home-paths.cjs +638 -0
- package/dist-lib/host/bridge-host.cjs +10903 -0
- package/dist-lib/host/fetch-proxy-handler.cjs +421 -0
- package/dist-lib/host/fetch-proxy-overrides.cjs +63 -0
- package/dist-lib/host/fetch-proxy-overrides.mjs +37 -0
- package/dist-lib/host/replacement-module-handler.cjs +469 -0
- package/dist-lib/host/websocket-proxy.cjs +298 -0
- package/dist-lib/index.cjs +4268 -0
- package/dist-lib/jump-to-source-babel.cjs +93 -0
- package/dist-lib/jump-to-source-native.cjs +112 -0
- package/dist-lib/menu.cjs +646 -0
- package/dist-lib/menu.mjs +604 -0
- package/dist-lib/metro-fingerprint-registry.cjs +186 -0
- package/dist-lib/metro-fingerprint-registry.mjs +156 -0
- package/dist-lib/metro-production-bundle.cjs +329 -0
- package/dist-lib/metro-production-bundle.mjs +295 -0
- package/dist-lib/metro.cjs +904 -0
- package/dist-lib/profiles.cjs +246 -0
- package/dist-lib/public-brand.cjs +39 -0
- package/dist-lib/react-native-host-modules.cjs +51 -0
- package/dist-lib/react-native-host-modules.mjs +25 -0
- package/dist-lib/render-mode.cjs +54 -0
- package/dist-lib/scripts/dev-server-scanner.cjs +1232 -0
- package/dist-lib/sdk.cjs +2433 -0
- package/dist-lib/sdk.mjs +2336 -0
- package/dist-lib/skills.cjs +39132 -0
- package/dist-lib/swift-submit.cjs +92 -0
- package/dist-lib/swift-submit.mjs +65 -0
- package/dist-lib/swift.cjs +1646 -0
- package/dist-lib/vite.cjs +1591 -0
- package/package.json +290 -0
- package/scripts/dev-server-scanner.ts +1291 -0
- package/scripts/optional-demo-registry.ts +113 -0
- package/skills/contrast/SKILL.md +165 -0
- package/skills/rnx-debug/SKILL.md +433 -0
- package/skills/rnx-perf/SKILL.md +399 -0
- package/skills/rnx-setup/SKILL.md +172 -0
- package/skills/rnx-test/SKILL.md +321 -0
- package/skills/rnx-visual/SKILL.md +126 -0
- package/src/agent-daemon-client.ts +410 -0
- package/src/agent-events.ts +71 -0
- package/src/agent-identity.ts +23 -0
- package/src/agent-prompt.ts +71 -0
- package/src/agent-sessions.ts +580 -0
- package/src/app-url.ts +39 -0
- package/src/attached-projects.ts +539 -0
- package/src/auth/shared-session.ts +235 -0
- package/src/backend-origin.ts +70 -0
- package/src/beta.ts +19 -0
- package/src/bridge-constants.ts +175 -0
- package/src/bridge-contract-input.ts +502 -0
- package/src/bridge-contract.ts +558 -0
- package/src/browser-cache.ts +16 -0
- package/src/capture-contract.ts +587 -0
- package/src/cli-constants.ts +1 -0
- package/src/cli-version.ts +40 -0
- package/src/cloud-contract.ts +274 -0
- package/src/cloud.ts +762 -0
- package/src/codex-client.ts +234 -0
- package/src/config.ts +132 -0
- package/src/connect.ts +101 -0
- package/src/dev-bundle-resolution.ts +346 -0
- package/src/dev-server-open.ts +198 -0
- package/src/disk-cleanup.ts +540 -0
- package/src/flow-timeout-scale.ts +15 -0
- package/src/home-paths.ts +806 -0
- package/src/host/agent-host.ts +666 -0
- package/src/host/bridge-host.ts +2788 -0
- package/src/host/fetch-proxy-handler.ts +449 -0
- package/src/host/fetch-proxy-overrides.ts +51 -0
- package/src/host/open-url.ts +89 -0
- package/src/host/plane-host.ts +203 -0
- package/src/host/replacement-module-handler.ts +158 -0
- package/src/host/websocket-proxy.ts +315 -0
- package/src/index.ts +71 -0
- package/src/jump-to-source-babel.ts +135 -0
- package/src/jump-to-source-native.ts +102 -0
- package/src/menu.ts +777 -0
- package/src/metro-fingerprint-registry.ts +302 -0
- package/src/metro-plugin.ts +341 -0
- package/src/metro-production-bundle.ts +471 -0
- package/src/native-dev-bundle-url.ts +118 -0
- package/src/native-seam-manifest.ts +341 -0
- package/src/playwright-host-log.ts +16 -0
- package/src/plist.ts +27 -0
- package/src/poll-until.ts +123 -0
- package/src/profiles.ts +179 -0
- package/src/public-brand.ts +9 -0
- package/src/react-native-host-modules.ts +26 -0
- package/src/render-mode.ts +27 -0
- package/src/rolldown-plugin-swift.ts +240 -0
- package/src/runtime-assets.ts +233 -0
- package/src/runtime-delivery.ts +54 -0
- package/src/screenshots/compose.ts +422 -0
- package/src/screenshots/frame-compose.ts +514 -0
- package/src/screenshots/orchestrate.ts +256 -0
- package/src/screenshots/org-deck.ts +91 -0
- package/src/screenshots/registry.ts +58 -0
- package/src/screenshots/schema.ts +364 -0
- package/src/sdk.ts +15 -0
- package/src/settings-bundle.ts +418 -0
- package/src/shell-bridge-identity.ts +15 -0
- package/src/sim-client.ts +697 -0
- package/src/skills/builtin/a11y-review.ts +132 -0
- package/src/skills/builtin/compat-check.ts +71 -0
- package/src/skills/builtin/maestro-test.ts +121 -0
- package/src/skills/builtin/perf-profile.ts +90 -0
- package/src/skills/builtin/screenshot-all.ts +52 -0
- package/src/skills/builtin/visual-diff.ts +100 -0
- package/src/skills/registry.ts +107 -0
- package/src/skills/types.ts +41 -0
- package/src/swift-submit.ts +185 -0
- package/src/swift.ts +7 -0
- package/src/team-machine-prompt.ts +73 -0
- package/src/vite-plugin-one.ts +264 -0
- package/src/vite-plugin-swift.ts +620 -0
- package/src/vite-plugin.ts +1946 -0
- package/src/worklets-babel.ts +250 -0
|
@@ -0,0 +1,399 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: rnx-perf
|
|
3
|
+
description: Optimize rnx engine and app performance — scroll jank, dropped frames, slow animation, idle CPU, memory growth, and "smooth normally but laggy under load" (video calls, busy machines). Covers measuring on the right thread with the right browser, proving each perf tier actually engages via its counters, a CPU-contention test harness, and the map of existing perf machinery so you improve it instead of reinventing it. For general app debugging load /rnx-debug first.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# rnx performance
|
|
7
|
+
|
|
8
|
+
optimize performance in rnx: the shell frame pipeline, the compositor
|
|
9
|
+
tiers, and the guest app. this skill exists because every real perf win in
|
|
10
|
+
this engine followed the same loop — measure on the right thread, read the
|
|
11
|
+
counters that prove machinery engaged, fix the one thing the counters
|
|
12
|
+
indict, remeasure — and every wasted week came from skipping a step.
|
|
13
|
+
|
|
14
|
+
> needs a connected, pinned sim (`/rnx-setup`). general "what's wrong"
|
|
15
|
+
> triage lives in `/rnx-debug`; this skill goes deeper on perf only.
|
|
16
|
+
|
|
17
|
+
## the four laws (each paid for by a real incident)
|
|
18
|
+
|
|
19
|
+
1. **measure the worker that painted it, in the right browser.** the tenant
|
|
20
|
+
hasn't painted since the two-worker split, so never read a tenant sampler
|
|
21
|
+
(the one reporting `avg 0.48ms (2069 fps)` for a visibly janky scroll was
|
|
22
|
+
removed). but "the shell" is no longer the whole answer either: the
|
|
23
|
+
compositor worker owns `home`, `app:one` and `app:two`, so **every guest-app
|
|
24
|
+
draw call, paint boundary and raster-tier decision is in the compositor's
|
|
25
|
+
render profile, not the shell's.** `perf shell stop` prints both, labelled
|
|
26
|
+
by worker — read the compositor block for anything inside an app. for
|
|
27
|
+
months it printed only the shell's, and a dense token-list fling
|
|
28
|
+
therefore reported `raster tier: 0 promotions / 0 blits` while the
|
|
29
|
+
compositor was blitting ~14 rows a frame; the giveaway was `node visits: 7`
|
|
30
|
+
next to `app:one 1014 paints`. if a render-profile block describes a
|
|
31
|
+
handful of nodes while an app surface is painting hundreds of times, you
|
|
32
|
+
are reading the wrong worker.
|
|
33
|
+
browser matters just as much: playwright's bundled headless chromium has
|
|
34
|
+
NO GPU — CanvasKit falls back to software rendering and every number lies
|
|
35
|
+
high. launch a dedicated GPU-backed Chrome executable with a disposable
|
|
36
|
+
profile and an owning process supervisor that terminates its exact process
|
|
37
|
+
tree. never automate the user's own browser profile.
|
|
38
|
+
2. **machinery silently not engaging is the default failure mode.** the
|
|
39
|
+
raster tier compiled, gated, and did *nothing* for months — zero
|
|
40
|
+
promotions on its textbook case — until per-gate rejection counters
|
|
41
|
+
existed. the frame-demand gate was blind to commit storms. the vsync
|
|
42
|
+
pump flapped 100 msgs/s at rest. never assume a tier works because it's
|
|
43
|
+
wired; read its counter during the exact workload.
|
|
44
|
+
3. **check reclaimable memory and sampled CPU before blaming code.** an OOM or
|
|
45
|
+
busy machine mimics every perf and infra failure. on macOS, read
|
|
46
|
+
`memory_pressure -Q` and take multiple `iostat -c 3` CPU samples; on Linux,
|
|
47
|
+
read `MemAvailable` from `/proc/meminfo` and sample CPU idle over time. keep
|
|
48
|
+
the busiest sample. raw macOS `freemem()` and load average are not admission
|
|
49
|
+
signals. attribute browser processes with `ps -eo pid,ppid,args` before
|
|
50
|
+
treating one as abandoned or stopping an exact pid.
|
|
51
|
+
4. **never trade animation fidelity for CPU.** perpetual sub-frame animation
|
|
52
|
+
must keep its authored cadence. attack per-frame cost (layers, caching,
|
|
53
|
+
damage), never cadence or fidelity.
|
|
54
|
+
|
|
55
|
+
## measuring
|
|
56
|
+
|
|
57
|
+
### presentation proof must stay outside the simulator
|
|
58
|
+
|
|
59
|
+
Performance acceptance must not use `rnx record`, `liveComposite`,
|
|
60
|
+
`captureBitmaps`, Chrome screencast, or another in-page frame-copy path. Those
|
|
61
|
+
paths add work to the simulator or browser and can change the cadence being
|
|
62
|
+
measured. Record the visible window with the operating system's native screen
|
|
63
|
+
capture instead.
|
|
64
|
+
|
|
65
|
+
Use an operating-system-owned window recorder. Target the exact browser window
|
|
66
|
+
rather than the display when the platform supports it, start recording before
|
|
67
|
+
normal user input, preserve the movie, and record the operating system and
|
|
68
|
+
recorder version. Confirm that the recorder process, not the browser or
|
|
69
|
+
simulator, owns capture and encoding. If native window capture is unavailable,
|
|
70
|
+
report the proof as blocked instead of substituting an in-page capture path.
|
|
71
|
+
|
|
72
|
+
The visual run contains only normal user input. Do not query the performance,
|
|
73
|
+
debug, or test bridge while it records. Treat that video as visual evidence of
|
|
74
|
+
frame progression. Collect worker paint, flush, delivery, and tier counters in
|
|
75
|
+
a separate run with screen capture off. The two runs answer different questions
|
|
76
|
+
without making the simulator measure its own recording overhead.
|
|
77
|
+
|
|
78
|
+
Open the sim with `?debug=framestamp` to make that video machine-readable.
|
|
79
|
+
Every surface paint then draws its `Date.now()` low 20 bits as a 23-cell
|
|
80
|
+
barcode — `home` and `app:*` at 45% of the surface height, `shell-overlay` on
|
|
81
|
+
its own row at 55% so overlay paints (keyboard, native UI) are attributable
|
|
82
|
+
separately. Decode the documented 23-cell barcode with a compatible framestamp
|
|
83
|
+
decoder to report, per presented frame, which paint it shows and how late that
|
|
84
|
+
paint presented. If no decoder is available, keep the recording as qualitative
|
|
85
|
+
evidence and make no numeric presentation-latency claim from it.
|
|
86
|
+
|
|
87
|
+
This is the only way to separate a frame the compositor never produced from one
|
|
88
|
+
it produced and the browser never presented.
|
|
89
|
+
|
|
90
|
+
**Screen capture is not presentation-neutral, so the decoded timing expires.**
|
|
91
|
+
Starting a ScreenCaptureKit window capture flips the 120hz `OffscreenCanvas`
|
|
92
|
+
out of latest-wins presentation into sequential presentation, which falls behind
|
|
93
|
+
roughly 0.5ms for every 1ms of capture. A capture started mid-activity begins
|
|
94
|
+
near zero latency and climbs from there. A recording is therefore truthful about
|
|
95
|
+
content and trajectory for its whole length, and truthful about timing for
|
|
96
|
+
roughly its first 500ms; latency growth past that is the capture, not the
|
|
97
|
+
engine. Live uncaptured presentation stays latest-wins and current. Never report
|
|
98
|
+
a late-recording latency as an engine number, and never compare two recordings
|
|
99
|
+
of different lengths.
|
|
100
|
+
|
|
101
|
+
Worker counters and presentation are different claims, and a green counter never
|
|
102
|
+
licenses a smoothness claim. A capture can report a perfect 120hz worker cadence
|
|
103
|
+
for motion the user never sees move: the overscroll release shipped exactly that
|
|
104
|
+
way, with the compositor stepping on schedule while the presented frames showed
|
|
105
|
+
a clamped fling instead of the bounce spring. Counters prove a tier engaged;
|
|
106
|
+
only a framestamp decode of an out-of-process recording proves what presented.
|
|
107
|
+
|
|
108
|
+
When an external transform control is smooth but the simulator is not, inspect
|
|
109
|
+
every animation on the presented element. A separate Web Animation object does
|
|
110
|
+
not isolate paint work: animating `box-shadow`, `filter`, or another paint-only
|
|
111
|
+
property on the transform owner can move the whole trajectory to the browser's
|
|
112
|
+
main thread. Paint stable decoration once or give it a distinct layer.
|
|
113
|
+
|
|
114
|
+
```sh
|
|
115
|
+
rnx perf shell start # arm shell frame capture (clears prior)
|
|
116
|
+
# reproduce — e.g. 8 fling swipes:
|
|
117
|
+
# for i in {1..8}; do rnx do swipe 196 650 196 250 8 8 --no-wait; sleep 0.9; done
|
|
118
|
+
rnx perf shell stop # report (add --json for scripting)
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
the report and how to read it:
|
|
122
|
+
|
|
123
|
+
- `painted frames / avg / p50 p95 p99 / jank` — work-per-painted-frame.
|
|
124
|
+
budget: 8ms at 120hz, 16.7ms at 60hz; p95 > 20ms is visible jank.
|
|
125
|
+
- `surfaces` — per-surface layout/render/flush split. `layout` spikes on a
|
|
126
|
+
scroll capture mean shell-side yoga re-layout when virtualized rows
|
|
127
|
+
materialize (mid-fling commit), not steady-state cost.
|
|
128
|
+
- `boundaries: N records / M replays` — layer compositor health. healthy
|
|
129
|
+
scroll: replays >> records, record cost near zero. records ≈ replays
|
|
130
|
+
means invalidation is defeating the cache (the SkPicture attempt-1
|
|
131
|
+
failure shape: `records: 1525, replays: 35`).
|
|
132
|
+
the `why recorded` line under it splits those records three ways, and each
|
|
133
|
+
one is a different bug: `invalidated` means something dirtied the boundary's
|
|
134
|
+
content (the usual culprit, and usually a style write that did not change a
|
|
135
|
+
value), `moved` means the boundary's record origin shifted so the cached
|
|
136
|
+
picture no longer lines up, and `first-record` is a boundary that had no
|
|
137
|
+
picture yet. a scroll dominated by `invalidated` is an invalidation bug; one
|
|
138
|
+
dominated by `first-record` is a warm-up problem, so look at whether the
|
|
139
|
+
idle pre-record reaches that content.
|
|
140
|
+
- `raster tier: promotions / blits` — blits per scrolled frame > 0 or the
|
|
141
|
+
tier is not firing; `raster skips` names the first gate each candidate
|
|
142
|
+
failed (rebuild / animated / cacheable). zero blits on a feed scroll is
|
|
143
|
+
a bug, not a tuning matter — but check you are reading the compositor's
|
|
144
|
+
block first (law 1), because the shell's is legitimately zero for an app
|
|
145
|
+
workload.
|
|
146
|
+
**before widening any skip bucket, read the `also fail a later gate`
|
|
147
|
+
line under it.** the counters name only the FIRST failed gate, so a big
|
|
148
|
+
bucket can be entirely blocked a second time and unwidenable: on one dense
|
|
149
|
+
token-list fling all 8298 `animated` skips also carried a style transform
|
|
150
|
+
or a non-cacheable chunk, and narrowing the animated gate moved 6007 to
|
|
151
|
+
`transform` and 2350 to `cacheable` while promoting nothing. a bucket is
|
|
152
|
+
worth attacking when its also-blocked share is small.
|
|
153
|
+
and blits firing is not the same as the tier paying for itself: on that same
|
|
154
|
+
token list the tier blits every visible row and costs 70MB of GPU
|
|
155
|
+
cache for no frame-time change, while the retained row boundaries under it
|
|
156
|
+
cost 2.4ms a frame. the discriminator is per-row draw density, so check
|
|
157
|
+
`draw calls` in the same block before concluding a cache is earning its
|
|
158
|
+
keep.
|
|
159
|
+
- `worst frames` — read the layout/render split of each; they are usually
|
|
160
|
+
a different problem than the average.
|
|
161
|
+
|
|
162
|
+
three runs minimum; single-run p95 is noise. a fresh `perf start` between
|
|
163
|
+
runs clears the buffer.
|
|
164
|
+
|
|
165
|
+
### browser-site interaction matrices
|
|
166
|
+
|
|
167
|
+
for a browser-level regression, use three fresh documents per browser engine.
|
|
168
|
+
within each document, capture cold then warm versions of the same interaction;
|
|
169
|
+
do not call two independent fresh documents "cold versus warm." wait for the
|
|
170
|
+
home surface's first compositor paint before starting—the compositor-ready flag
|
|
171
|
+
only proves worker bootstrap and can precede the first visible layout.
|
|
172
|
+
|
|
173
|
+
during a measured transition, use a fixed observation window. do not poll the
|
|
174
|
+
shell state, test tree, or perf bridge while the animation is running; verify
|
|
175
|
+
the positive control once after profiling stops. query a targeted id or text on
|
|
176
|
+
large virtualized apps, never the full tree, because enumeration can dominate
|
|
177
|
+
or terminate the browser process. for a remotely populated list, require the
|
|
178
|
+
same scroll-container identity and content extent for a quiet window before the
|
|
179
|
+
gesture; "a row exists" can still be true while the app replaces the tree.
|
|
180
|
+
keep pointer down, moves, release, and the fixed settle window inside one
|
|
181
|
+
uninterrupted profile. stopping or querying between drag and release changes
|
|
182
|
+
velocity, cache state, and worker scheduling.
|
|
183
|
+
|
|
184
|
+
the minimum browser matrix is home drag plus snapback, a cold/warm built-in app
|
|
185
|
+
open, and a cold/warm app-switcher open. add one quiet heavy-app screen, one
|
|
186
|
+
navigation transition, and one long-list scroll when those surfaces are in
|
|
187
|
+
scope. use GPU-backed Chrome for Chromium claims. use installed WebKit in a
|
|
188
|
+
visible nonpersistent WKWebView for Safari-engine claims; Playwright WebKit is
|
|
189
|
+
not the installed Safari engine.
|
|
190
|
+
|
|
191
|
+
every receipt must carry the exact page and frame URLs, browser user agent,
|
|
192
|
+
browser executable path and content hash,
|
|
193
|
+
harness-source identity, capture time, engine build identity and generation,
|
|
194
|
+
runtime bundle receipt, sampled host capacity at run start, runtime errors, and
|
|
195
|
+
any partial failure. use the shared host-capacity sampler; do not record raw
|
|
196
|
+
`freemem()` or decide from macOS load average.
|
|
197
|
+
partial artifacts remain inadmissible until every requested run number for that
|
|
198
|
+
scenario exists with one harness, browser executable, engine, seed, and
|
|
199
|
+
viewport identity. browser
|
|
200
|
+
comparisons use the same root/target viewport tuple and backing scale. for a
|
|
201
|
+
wrapper or embedded surface, first prove the target has nonzero presented
|
|
202
|
+
geometry; a finite host viewport that responsively hides the target measures a
|
|
203
|
+
different surface. direct and embedded modes may intentionally have different
|
|
204
|
+
tuples, but browsers within one mode may not. finite but different device pixel
|
|
205
|
+
ratios are not comparable. if setup reloads only the child frame, replay the
|
|
206
|
+
parent's presentation control and wait for the new child to acknowledge it. a
|
|
207
|
+
selected parent toggle can outlive its child and is not proof of the child's
|
|
208
|
+
mode.
|
|
209
|
+
the profile intentionally blocks Graphite cache cleanup, so its cache snapshot
|
|
210
|
+
is not a terminal memory verdict. require a capture-local post-profile
|
|
211
|
+
compositor snapshot with before, after, and delta cleanup counters. an
|
|
212
|
+
over-limit profiled Context needs fresh submitted-work attempt and
|
|
213
|
+
successful-completion deltas; an over-limit profiled Recorder also needs a
|
|
214
|
+
fresh cleanup in that capture. classify Context and Recorder independently as
|
|
215
|
+
within-limit, locked-over-limit, or purgeable-over-limit; never compare their
|
|
216
|
+
aggregate, and never admit purgeable overage. a cache with zero purgeable bytes
|
|
217
|
+
can still hold a returned-resource queue: settled maintenance releases completed
|
|
218
|
+
Recorder resources, then budget enforcement evicts
|
|
219
|
+
least-recently-used overage before the next paint or resource insertion can
|
|
220
|
+
inherit the synchronous work. perpetual renderer
|
|
221
|
+
animation is not finite interaction demand; finite motion, readbacks, and
|
|
222
|
+
profiling must still block cleanup.
|
|
223
|
+
the host-clock `displayFrames`/`timerFrames` and shell-link
|
|
224
|
+
`displayPumps`/`timerPumps` counters prove whether the visible-rAF fallback
|
|
225
|
+
engaged. preserve failed receipts instead of retrying them out of the data set.
|
|
226
|
+
|
|
227
|
+
### confirm which build you measured, every time
|
|
228
|
+
|
|
229
|
+
Against a dev-source sim, the FIRST reload after an engine edit serves the
|
|
230
|
+
PREVIOUS module. The sim reports ready, the app runs, the numbers look real, and
|
|
231
|
+
they describe the build before yours. Two screenshots were read as a fidelity
|
|
232
|
+
regression this way before the cause was found.
|
|
233
|
+
|
|
234
|
+
So make every capture say which build it came from, rather than assuming the
|
|
235
|
+
reload took. Put a marker in something the capture already returns - a counter
|
|
236
|
+
name in `saveLayerReasons`, a debug event, a log line - and treat a capture with
|
|
237
|
+
no marker as a capture of the wrong build. Reload twice and re-read the marker.
|
|
238
|
+
|
|
239
|
+
This costs one line and it is the difference between a measurement and a guess.
|
|
240
|
+
The same rule covers any A/B where you edit between arms: an arm you cannot
|
|
241
|
+
identify from its own output is not evidence.
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
deeper tools when the frame report isn't enough:
|
|
245
|
+
|
|
246
|
+
```sh
|
|
247
|
+
rnx maestro test .maestro/scroll.yaml --profile # per-step + frame stats
|
|
248
|
+
rnx perf cpu --duration 5 --output /tmp/t.cpuprofile # sampled CPU
|
|
249
|
+
rnx open 8089 --new --driver playwright --cdp-port 9222 # cpu-profile a driveable sim
|
|
250
|
+
rnx debug enable layout,render && rnx debug recent layout 40
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
`rnx perf cpu` writes one profile for the page and one for every attached
|
|
254
|
+
worker, plus a manifest that labels shell, compositor, tenant, worklet, and
|
|
255
|
+
unknown workers. exit zero requires page, shell, compositor, and tenant plus
|
|
256
|
+
every other discovered target, with each covering at least 99% of the requested
|
|
257
|
+
window. inspect start/stop offsets as well as sample counts; a late-attached
|
|
258
|
+
near-empty profile is incomplete. a profile of only the tenant—or a helper
|
|
259
|
+
that relabels the busiest worker as tenant—cannot distinguish CPU saturation
|
|
260
|
+
from sparse browser scheduling.
|
|
261
|
+
|
|
262
|
+
for an automated interaction, pass `--interaction-barrier` and start the cpu
|
|
263
|
+
command during the runner's pre-workload attachment delay, and give the runner
|
|
264
|
+
a post-workload delay long enough to remain open through profiler stop. the
|
|
265
|
+
pre-workload delay alone is not synchronization: it can end the profile while
|
|
266
|
+
the workload is still preparing. barrier mode pauses the workload before its
|
|
267
|
+
first measured capture until every discovered target is profiling, then rejects
|
|
268
|
+
the manifest unless the workload publishes its completion marker, every expected
|
|
269
|
+
capture label, and action timestamps inside the capture interval. retain its
|
|
270
|
+
browser executable, engine build and generation, root and target viewports, and
|
|
271
|
+
workload source identity in the CPU manifest. the barrier also has a bounded
|
|
272
|
+
page-side lease so an interrupted
|
|
273
|
+
profiler cannot strand the workload; lease expiry releases the runner but
|
|
274
|
+
invalidates the profile.
|
|
275
|
+
|
|
276
|
+
### the cadence block: frames that never happened
|
|
277
|
+
|
|
278
|
+
work-per-painted-frame cannot see a frame that was never delivered because a
|
|
279
|
+
worker was descheduled or its resilient clock fell back late. the report shows
|
|
280
|
+
low avg and zero jank while the user sees stutter.
|
|
281
|
+
the `cadence` section of `perf shell stop` measures the delivery side and
|
|
282
|
+
attributes a missing frame to its hop:
|
|
283
|
+
|
|
284
|
+
- `display clock / host rAF interval` — stretch here (gaps >1.5x median)
|
|
285
|
+
means the page thread's rAF starved or was throttled, upstream of the
|
|
286
|
+
shell worker entirely.
|
|
287
|
+
- `delivery lag` — vsync postMessage receipt latency above the run's
|
|
288
|
+
best case; jitter here means the shell worker was descheduled or its
|
|
289
|
+
queue was busy.
|
|
290
|
+
- `paint interval` — the end-to-end cadence the user perceives.
|
|
291
|
+
- `idle breaks` — gaps >250ms, excluded from all three: demand-gated
|
|
292
|
+
quiesce is legitimate, not starvation.
|
|
293
|
+
|
|
294
|
+
the compositor `compositorHostFrameClock` keeps its historical name and reports
|
|
295
|
+
display/timer ticks consumed by the compositor worker's resilient clock during
|
|
296
|
+
the acknowledged profile window. `published` is null because renderer-main no
|
|
297
|
+
longer publishes compositor frames. sparse consumed ticks with low production
|
|
298
|
+
time identifies worker scheduling starvation. many consumed ticks with sparse
|
|
299
|
+
paints can be legitimate dirty-gating; correlate the frame series before
|
|
300
|
+
treating it as a regression. shell cadence comes from its worker frame and paint
|
|
301
|
+
series.
|
|
302
|
+
|
|
303
|
+
compare baseline vs contended captures of the same scripted window; also
|
|
304
|
+
compare **painted-frame counts**, the crudest and most robust signal.
|
|
305
|
+
|
|
306
|
+
the compositor cadence lines separate worker delivery from work submitted by
|
|
307
|
+
the worker:
|
|
308
|
+
|
|
309
|
+
- `engine-empty rAF` includes only sustained intervals where adjacent frames
|
|
310
|
+
have no engine demand, input message, shared-slot demand epoch change,
|
|
311
|
+
paint, prewarm pass, or CanvasKit flush.
|
|
312
|
+
- `rAF with CanvasKit flush` and `rAF after CanvasKit flush` isolate the frame
|
|
313
|
+
that called `Surface.flush()` and the next delivered frame.
|
|
314
|
+
- `CanvasKit submission` measures intervals between final `Surface.flush()`
|
|
315
|
+
completions on frames that submitted at least one surface. The JSON
|
|
316
|
+
`frameSeries` preserves each phase flag and exact count for correlation.
|
|
317
|
+
|
|
318
|
+
these are engine-owned boundaries. Playwright exposes raw CDP sessions only
|
|
319
|
+
for Chromium, and WebKit's public Inspector timeline exposes a WebCore
|
|
320
|
+
`Composite` record without a RemoteLayerTree transaction id or commit event.
|
|
321
|
+
Do not label CanvasKit flush or compositor rAF as a RemoteLayerTree commit.
|
|
322
|
+
|
|
323
|
+
## the contention harness ("smooth alone, laggy on a zoom call")
|
|
324
|
+
|
|
325
|
+
low-load numbers do not predict feel under real-world CPU pressure. run the
|
|
326
|
+
same scripted capture twice, once with synthetic load, self-terminating so
|
|
327
|
+
it can't leak:
|
|
328
|
+
|
|
329
|
+
```sh
|
|
330
|
+
# 6 cores of load for 30s, self-terminating
|
|
331
|
+
for i in 1 2 3 4 5 6; do
|
|
332
|
+
(perl -e 'my $end=time()+30; while(time()<$end){my $x=0; $x+=rand() for 1..10000}' &)
|
|
333
|
+
done
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
compare: painted-frame count (cadence), avg/p95 (work), layout spikes. the
|
|
337
|
+
diagnostic split:
|
|
338
|
+
|
|
339
|
+
- **work grows under load** (avg/p95 way up) → paint path too heavy;
|
|
340
|
+
attack per-frame cost (layers, damage, raster, draw calls).
|
|
341
|
+
- **work flat but frames missing** (counts drop, avg barely moves) →
|
|
342
|
+
delivery starvation: the host-rAF → postMessage → shell hop chain and
|
|
343
|
+
worker scheduling. browsers give no thread priorities, so the only
|
|
344
|
+
levers are fewer hops on the frame-critical path, less work per hop, and
|
|
345
|
+
keeping motion (scroll, native anims) as close to the paint site as
|
|
346
|
+
possible.
|
|
347
|
+
- also remember GPU contention is real (video calls encode on the GPU);
|
|
348
|
+
webkit-lane numbers are Metal, chrome numbers are its GL/Metal stack.
|
|
349
|
+
|
|
350
|
+
## the perf machinery map (improve, don't reinvent)
|
|
351
|
+
|
|
352
|
+
every tier below exists and has a counter. before optimizing, identify
|
|
353
|
+
which tier *should* absorb your cost and prove whether it does.
|
|
354
|
+
|
|
355
|
+
| tier | what it absorbs | proof it engaged |
|
|
356
|
+
| --- | --- | --- |
|
|
357
|
+
| demand-gated frames + visibility re-marking | idle costs nothing; invisible animations quiesce | `+N skipped idle ticks`; `queryStats().needsVsync` false at rest |
|
|
358
|
+
| per-surface dirty scoping | one app's commit/animation repaints only its surface | idle repaints ≈ commit rate, owning surface only |
|
|
359
|
+
| dirty-tracked layout + tiered text measurement | color/opacity/transform commits skip yoga; repeated strings skip shaping | `layout: 0` on steady frames |
|
|
360
|
+
| layer compositor (`paint-boundary.ts`) | animating a child never re-records ancestors | replays >> records |
|
|
361
|
+
| idle boundary pre-record | the first drag replays instead of recording; cold records happen while the surface is quiet | `pre-recorded: N boundaries at idle` in the report, and the first interaction's record cost near its warm cost |
|
|
362
|
+
| damage rects (`damage-rect.ts`) | repaint clips to changed region (opaque-backdrop gated) | worst-frame render bounded during small updates |
|
|
363
|
+
| raster tier | stable rows become GPU textures; scroll skips recording | compositor block: promotions > 0 once warm, blits ≈ one per visible row on a dense feed |
|
|
364
|
+
| flood guard, pointer coalescing, vsync hysteresis | message-storm and pump-thrash protection | msgs/s sane during gestures and at rest |
|
|
365
|
+
| worker-owned resilient frame clocks | renderer-main stalls do not stop shell or compositor motion | compositor consumed display/timer frames plus shell worker frame and paint cadence |
|
|
366
|
+
|
|
367
|
+
there is no whole-screen scroll blit. one existed for a few hours in June
|
|
368
|
+
2026 and was reverted (`6706f3a014`): it shifted a surface RECTANGLE, so a
|
|
369
|
+
full-surface feed with floating translucent chrome dragged its bars along with
|
|
370
|
+
the content and smeared their old pixels through the feed. scroll rides the
|
|
371
|
+
layer, damage, and raster machinery above instead, and any future blit has to
|
|
372
|
+
own a scroll SUBTREE with provable backdrop correctness rather than a screen
|
|
373
|
+
rect. do not look for `blitBlocked`; it does not exist.
|
|
374
|
+
|
|
375
|
+
if a workload's cost lands in a tier that shows zero activity, the fix is
|
|
376
|
+
almost always "why didn't it engage" (a gate, a shape, an eligibility
|
|
377
|
+
rule), not new machinery. the area-gate fix that finally made the raster
|
|
378
|
+
tier fire on feeds came entirely from rejection counters.
|
|
379
|
+
|
|
380
|
+
## guest-app-side causes (fix the app, or fix the engine honestly)
|
|
381
|
+
|
|
382
|
+
- dynamic format strings (`` `${n} messages` ``) bust the shaping LRU —
|
|
383
|
+
split number and label into separate `<Text>` nodes.
|
|
384
|
+
- `Animated.Value` on `width`/`height` forces layout per frame — use
|
|
385
|
+
`transform` (scale/translate).
|
|
386
|
+
- per-frame React work from reanimated-style code is an engine conformance
|
|
387
|
+
bug (valid worklet apps must not commit per frame) — fix rnx core,
|
|
388
|
+
never add a divergent fast-path (upstream alignment overrides perf; see
|
|
389
|
+
the `shouldFreezeOffscreenStackContent` incident).
|
|
390
|
+
- render-storm loops (poll → remount) show up as commit-rate repaints and
|
|
391
|
+
RSS growth; check `debug state animations` and the timeline.
|
|
392
|
+
|
|
393
|
+
## closing the loop
|
|
394
|
+
|
|
395
|
+
done means: a named hot path + the counter or split that indicts it + the
|
|
396
|
+
same capture re-run showing the number moved + no new errors (`get errors`)
|
|
397
|
+
+ nothing torn down left running (close sims you opened, kill load loops).
|
|
398
|
+
for engine changes, run the affected integration tests exposed by the installed
|
|
399
|
+
rnx version and capture stable screenshots of surfaces you touched.
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: rnx-setup
|
|
3
|
+
description: Get rnx connected to your React Native app with no project setup
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# rnx setup
|
|
7
|
+
|
|
8
|
+
you want to drive a React Native app with rnx from the CLI. this skill
|
|
9
|
+
takes you from a running development server to a connected, pinned sim that
|
|
10
|
+
every other rnx skill assumes exists. rnx requires no project setup or per-app
|
|
11
|
+
install. if
|
|
12
|
+
`rnx describe` already
|
|
13
|
+
returns a tree, you're past this skill — load `/rnx-debug` for
|
|
14
|
+
debugging or `/rnx-test` for writing tests.
|
|
15
|
+
|
|
16
|
+
## anti-patterns (read first)
|
|
17
|
+
|
|
18
|
+
- **never `rnx claim --force` a sim held by another CLI.** the lease
|
|
19
|
+
exists for a reason. forcing strands the other agent and corrupts the
|
|
20
|
+
bridge state. use `rnx open --new` to start a fresh sim instead.
|
|
21
|
+
- **don't switch sims mid-investigation.** pin once with `rnx use
|
|
22
|
+
<id>` and keep it pinned. an unpinned command refuses to choose when more
|
|
23
|
+
than one driveable sim is live.
|
|
24
|
+
- **an empty `rnx list` is not "broken rnx".** it usually means the
|
|
25
|
+
daemon is down, the dev server port is wrong, or the runtime is missing.
|
|
26
|
+
walk the recovery checklist before reinstalling.
|
|
27
|
+
- **keep one sim for your whole session.** the first `rnx open <port>`
|
|
28
|
+
launches Chrome for Testing with an isolated profile. later opens reuse the
|
|
29
|
+
saved sim and navigate it in place. use `rnx do reload` when the target
|
|
30
|
+
has not changed:
|
|
31
|
+
|
|
32
|
+
```sh
|
|
33
|
+
rnx open 8086 # first call creates your isolated sim
|
|
34
|
+
rnx open 8090 # same sim, different app
|
|
35
|
+
rnx do reload # same sim, same app
|
|
36
|
+
rnx close <id> # dispose it when you are done
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
`--new`, `--profile`, and `--ephemeral` create another isolated browser
|
|
40
|
+
tree. use them only when separate storage or a genuinely concurrent sim is
|
|
41
|
+
required. repeated new trees consume enough memory and CPU to starve other
|
|
42
|
+
work on a shared machine.
|
|
43
|
+
- **pin the sim before driving it.** `rnx open` records the new sim for the
|
|
44
|
+
current CLI identity. read its id and pin it explicitly before a longer flow:
|
|
45
|
+
|
|
46
|
+
```sh
|
|
47
|
+
rnx open 8086
|
|
48
|
+
rnx list
|
|
49
|
+
rnx use <id>
|
|
50
|
+
rnx describe --sim <id>
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
- **never retry-loop `rnx open` against a wedged or slow stack.** a
|
|
54
|
+
connect timeout means diagnose the stack. do not retry. if the first launch
|
|
55
|
+
never connects, each retry can create another browser tree before there is a
|
|
56
|
+
saved sim to reuse. verify the development server and rnx runtime, then
|
|
57
|
+
retry once after fixing the cause.
|
|
58
|
+
|
|
59
|
+
## first move
|
|
60
|
+
|
|
61
|
+
```sh
|
|
62
|
+
rnx daemon status # the persistent service makes agent commands much faster
|
|
63
|
+
rnx daemon install # enable it when missing on a supported personal machine
|
|
64
|
+
rnx compat --json # scan the app's native package compatibility
|
|
65
|
+
rnx open 8081 # load a metro/expo dev server
|
|
66
|
+
rnx list # confirm exactly one sim is reachable
|
|
67
|
+
rnx use <id> # pin it for the rest of the workflow
|
|
68
|
+
rnx describe # smoke test — should print a render tree
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
the background service keeps the local bridge and runtime ready between
|
|
72
|
+
commands. without it, rnx still works by starting an on-demand bridge, but
|
|
73
|
+
inspect, interaction, and test commands pay repeated startup cost. if the user
|
|
74
|
+
declined it during onboarding, `rnx daemon install` is the direct way to enable
|
|
75
|
+
it. CI does not need or install the service.
|
|
76
|
+
|
|
77
|
+
bare `rnx` opens ConnectRN for a human to choose among local apps. agents and
|
|
78
|
+
scripts should use `rnx open <port-or-url>` so the target is explicit.
|
|
79
|
+
|
|
80
|
+
if you do not know the port, run `rnx open` with no target and pick from
|
|
81
|
+
the detected dev servers. for hosted or unusual targets, pass the URL
|
|
82
|
+
explicitly:
|
|
83
|
+
|
|
84
|
+
```sh
|
|
85
|
+
rnx open 8081 # load a metro dev server
|
|
86
|
+
rnx open https://my-app.local # load a hosted bundle
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## you're done when
|
|
90
|
+
|
|
91
|
+
- `rnx list` shows your sim and no orphans
|
|
92
|
+
- `rnx describe` returns a render tree, not an error
|
|
93
|
+
- the same sim id appears in `rnx describe`, `rnx find`, and
|
|
94
|
+
every subsequent command
|
|
95
|
+
- `rnx get errors 5` and `rnx get requests 5` are quiet (or the
|
|
96
|
+
warnings are ones you understand)
|
|
97
|
+
- the compatibility scan's partial, unsupported, unknown, and version-mismatched
|
|
98
|
+
packages have been summarized without treating its aggregate score as a pass/fail gate
|
|
99
|
+
|
|
100
|
+
## compatibility feedback requires approval
|
|
101
|
+
|
|
102
|
+
run `rnx compat --json` from the app project root during setup. if the scan
|
|
103
|
+
identifies a plausible missing rnx seam, or the running app gives concrete
|
|
104
|
+
evidence that behavior is missing or broken specifically in rnx, summarize
|
|
105
|
+
the package, expected behavior, actual behavior, and runtime evidence for the
|
|
106
|
+
user. then offer to send that finding with `rnx report-issue`.
|
|
107
|
+
|
|
108
|
+
**never submit a report automatically or behind the user's back.** wait for an
|
|
109
|
+
explicit yes. only then run this from the app project root:
|
|
110
|
+
|
|
111
|
+
```sh
|
|
112
|
+
rnx report-issue --yes "<package; expected behavior; actual behavior; runtime evidence>"
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
the command automatically attaches the local compatibility scan plus bounded
|
|
116
|
+
CLI, runtime, operating-system, and architecture metadata. it does not attach
|
|
117
|
+
source files, environment variables, terminal output, logs, screenshots, git
|
|
118
|
+
data, or app data. `--dry-run` previews the attachment summary without sending.
|
|
119
|
+
do not use `--yes` merely because the agent believes a report would be useful;
|
|
120
|
+
it records the user's approval after the offer.
|
|
121
|
+
|
|
122
|
+
## recovery — common failure modes
|
|
123
|
+
|
|
124
|
+
**`rnx list` is empty.** walk this checklist in order:
|
|
125
|
+
|
|
126
|
+
```sh
|
|
127
|
+
rnx daemon status # is the bridge daemon up?
|
|
128
|
+
rnx runtime list # is at least one engine runtime installed?
|
|
129
|
+
rnx open <port> # does loading explicitly work?
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
if the daemon is not installed: run `rnx daemon install`. if the registered
|
|
133
|
+
daemon is down, run `rnx daemon restart`, or `rnx serve` in another shell for
|
|
134
|
+
a foreground bridge. if no runtime is installed, `rnx open` installs it
|
|
135
|
+
before launching. if open errors with "port unreachable": confirm your dev
|
|
136
|
+
server is actually serving — the bundler has to be up before rnx can
|
|
137
|
+
attach.
|
|
138
|
+
|
|
139
|
+
**two sims appear unexpectedly.** an earlier `rnx claim` didn't
|
|
140
|
+
release on exit. close the orphan explicitly:
|
|
141
|
+
|
|
142
|
+
```sh
|
|
143
|
+
rnx list # note the stale id
|
|
144
|
+
rnx close <id> # release it cleanly
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
**`rnx open` errors with "no runtime".** the engine binary isn't installed.
|
|
148
|
+
Run `rnx runtime install`, then retry `rnx open <port>`.
|
|
149
|
+
|
|
150
|
+
**`rnx open` times out ("timed out waiting for opened sim to connect").**
|
|
151
|
+
do not retry in a loop. verify the development server first: `__soot/` must
|
|
152
|
+
respond and the engine watchers must be running. inspect the driver diagnostic
|
|
153
|
+
path printed by the failed command. restart the broken development stack at its
|
|
154
|
+
supervisor, then retry once. rnx owns the isolated browser profile and its
|
|
155
|
+
process tree; do not open the shell URL through an operating-system browser.
|
|
156
|
+
|
|
157
|
+
**bridge disconnects mid-sim.** the WebSocket dropped (laptop slept,
|
|
158
|
+
network blip). re-pin: `rnx use <id>`. the daemon retries reconnection
|
|
159
|
+
automatically; you usually just need to re-issue the command.
|
|
160
|
+
|
|
161
|
+
**"sim held by another CLI".** another agent or your own previous CLI
|
|
162
|
+
process has the lease. find it (`rnx list`), close it (`rnx close
|
|
163
|
+
<id>`), or start a clean sim (`rnx open --new`) — do **not**
|
|
164
|
+
`rnx claim --force`.
|
|
165
|
+
|
|
166
|
+
## related
|
|
167
|
+
|
|
168
|
+
- `/rnx-debug` — once setup is good, this is where you debug
|
|
169
|
+
rendering, performance, and accessibility issues.
|
|
170
|
+
- `/rnx-test` — write or run automated flows against the connected
|
|
171
|
+
sim.
|
|
172
|
+
- `/rnx-visual` — pixel-level rendering comparisons.
|