diff --git a/.kilo_workflow/learnings/e2e-slot-release-stopped-another-sections-stack.md b/.kilo_workflow/learnings/e2e-slot-release-stopped-another-sections-stack.md index d7587012eb..a07d751133 100644 --- a/.kilo_workflow/learnings/e2e-slot-release-stopped-another-sections-stack.md +++ b/.kilo_workflow/learnings/e2e-slot-release-stopped-another-sections-stack.md @@ -35,3 +35,15 @@ a `slot-acq` window under a proxy `
-e2e-seed` session and parked a `sleep` to hold it. That both violates the E2E-loop rule and creates a self-deadlock: the verifier polls for a free slot that its own section's sleeper holds, and neither side can progress. + +Victim-side recovery (worked twice in hermes-mem-c716 r1, the section named in +the symptom): the kill is silent for the victim — `pnpm dev:status` just prints +"No dev session running" mid-round and the dev client loses Metro. While the +slot is still held, restart the stack in place: `pnpm dev:start --no-attach +mobile cloud-agent-next kiloclaw event-service` (the same ports return), restart +the CLI relay (`remote-cli.sh exec remote` → `Remote connection enabled.`), +re-prove `session list --pure`, re-anchor the dev client with the deep link, and +re-run only the iteration that was in flight — device-local measurements (e.g. +meminfo) from completed iterations stay valid. The companion `stack=none` shown +by `e2e-slot.sh status` even for live stacks was the #4836 name-mangling bug +(the same mangled session name made `has-session` always fail), already fixed. diff --git a/.kilo_workflow/learnings/mobile-android-maestro-flow-pitfalls.md b/.kilo_workflow/learnings/mobile-android-maestro-flow-pitfalls.md new file mode 100644 index 0000000000..0c94395c10 --- /dev/null +++ b/.kilo_workflow/learnings/mobile-android-maestro-flow-pitfalls.md @@ -0,0 +1,20 @@ +# mobile-android-maestro-flow-pitfalls + +Symptom: a Maestro iteration flow on Android fails or hangs in ways the exit +code does not reveal. + +Cause/fix (three independent traps, all hit in the hermes-mem baseline round): +1. `maestro test` exits 0 even when a flow assertion FAILED (observed on + maestro 2.7.0, Android). Never trust the exit code; grep the log for + `FAILED` after every run. +2. Maestro text matching is full-string regex: the Agents list search field is + `Search sessions...` (with ellipsis), so `visible: 'Search sessions'` never + matches. Use `Search sessions.*` (and generally re-dump and copy exact + strings after any UI change). +3. Under parallel-workflow host load (load avg >100) a cold dev-client launch + can sit on a blank Compose splash for 3-15 min and the emulator throws + `Process system isn't responding` ANR dialogs. `open-app.yaml`'s 30 s wait + is too short. A verifier temp flow needs: a 420 s launch wait, a + `.*isn.t responding.*` → `tapOn: 'Wait'` handler after the launch wait and + after settle, and 60-120 s waits for list/transcript asserts. `dumpsys + meminfo` itself can hit its 10 s service timeout under load — retry it. diff --git a/.kilo_workflow/learnings/mobile-android-stale-claims-explicit-port.md b/.kilo_workflow/learnings/mobile-android-stale-claims-explicit-port.md new file mode 100644 index 0000000000..10f560329f --- /dev/null +++ b/.kilo_workflow/learnings/mobile-android-stale-claims-explicit-port.md @@ -0,0 +1,20 @@ +# mobile-android-stale-claims-explicit-port + +Symptom: `pnpm dev:mobile:android claim emulator-5554` fails with "claimed by +/Users/igor/Projects/.worktrees/" even though the owning +worktree has no live tmux session and the claiming PID is dead. + +Cause: Android claims are per-serial JSON files in +`$TMPDIR/kilo-mobile-android-claims/`. Before 96154f115 ownership was checked +by worktreeRoot equality only, so a claim was never stale while the owning +worktree directory existed, and dead-emulator claims wedged the default +serials (emulator-5554, emulator-5556) permanently. Claims now record the +guest kernel boot id, so a foreign claim self-clears once the emulator that +wrote it no longer answers on the serial — but a *live* foreign emulator on a +default serial still blocks your boot, which lands on the first free serial. + +Fix: boot the AVD on an explicit free even console port so the serial is +unclaimed: `pnpm dev:mobile:android emulator -avd -port 5558 +-no-snapshot-save -no-boot-anim -gpu host` → serial `emulator-5558`, then +`claim emulator-5558`. Never delete another worktree's claim file. Record the +port in the round handoff so the next round reuses the same serial. diff --git a/.kilo_workflow/learnings/mobile-e2e-cli-relay-window-wedge.md b/.kilo_workflow/learnings/mobile-e2e-cli-relay-window-wedge.md new file mode 100644 index 0000000000..c7269ce463 --- /dev/null +++ b/.kilo_workflow/learnings/mobile-e2e-cli-relay-window-wedge.md @@ -0,0 +1,17 @@ +# mobile-e2e-cli-relay-window-wedge + +Symptom: the `relay` window of an orchestrator-prepared +`kilo-e2e-cli-` tmux session shows an idle shell (`pane_current_command` += zsh), echoes typed input, but never executes it (no output, no new prompt); +sending C-c then collapses the window. + +Cause: the pane's shell was wedged (likely a stopped/zombie job state) after +the original `kilo remote` relay process died; the tmux window only looked +alive in `tmux ls`. + +Fix: do not keep probing the wedged pane. Let the window die (or kill it), +recreate it with `tmux new-window -t -n relay`, probe with +`echo OK`, then restart the relay with +`apps/mobile/e2e/remote-cli.sh exec remote` (absolute path) and confirm +`Remote connection enabled.`. The mobile Agents list only discovers the +session while this relay is connected. diff --git a/.kilo_workflow/learnings/mobile-ios-cold-build-shareextension-pods-root.md b/.kilo_workflow/learnings/mobile-ios-cold-build-shareextension-pods-root.md new file mode 100644 index 0000000000..02c1cf5010 --- /dev/null +++ b/.kilo_workflow/learnings/mobile-ios-cold-build-shareextension-pods-root.md @@ -0,0 +1,19 @@ +# mobile-ios-cold-build-shareextension-pods-root + +Symptom: a genuinely cold `pnpm dev:mobile:ios build ` (cache-busted) fails at +link with `(3 failures)` and one root error: +`error: unable to spawn process '/../../../../node_modules/.pnpm/react-native@0.86.0[_patch_hash=...]/node_modules/react-native/scripts/xcode/ccache-clang.sh' (No such file or directory) (in target 'ShareExtension' from project 'Kilo')`. + +Cause: the generated `apps/mobile/ios/Kilo.xcodeproj` sets project-level +`REACT_NATIVE_PATH = "${PODS_ROOT}/../../../../node_modules/...react-native"` and +`CC/CXX/LD/LDPLUSPLUS = "$(REACT_NATIVE_PATH)/scripts/xcode/ccache-clang[++] .sh"`. +`PODS_ROOT` is defined only by Pods target xcconfigs, so for the ShareExtension +target (no Pods xcconfig) `PODS_ROOT` expands empty and the spawn path resolves to +`/node_modules/...`. Warm-cache iOS runs never hit this; the template is +tree-independent (present with or without the Hermes patch). + +Workaround used in the round (temporary, in the gitignored generated project): +replace the project-level Debug `REACT_NATIVE_PATH` line with the absolute correct +path (delete duplicates — a later duplicate key wins). Build then succeeds. +Proper fix candidate for the repo: have the ShareExtension config plugin set an +absolute REACT_NATIVE_PATH (or stop overriding CC/LD) for that target. diff --git a/.kilo_workflow/learnings/mobile-ios-maestro-session-row-and-back.md b/.kilo_workflow/learnings/mobile-ios-maestro-session-row-and-back.md new file mode 100644 index 0000000000..3a0311611a --- /dev/null +++ b/.kilo_workflow/learnings/mobile-ios-maestro-session-row-and-back.md @@ -0,0 +1,18 @@ +# mobile-ios-maestro-session-row-and-back + +Symptom: on iOS, a Maestro flow that matches the Agents session row and navigates +back fails two ways: (1) `visible: ''` never matches even though the +row renders; (2) the `back` command does not leave a pushed session-detail screen. + +Cause: iOS exposes the session row as ONE accessibility element whose label is the +comma-joined summary (`Hermes-mem-c716 baseline session setup, CLOUD, cost 5 cents, +6 hours ago, from CLI`), not the bare title; and Maestro's `back` is a no-op on this +pushed screen — the app renders an explicit `Go back` accessibility element instead. + +Fix: match with a prefix regex (`',.*'`) and tap `Go back` to return. Also +make reruns self-normalizing: start with an optional `Go back` tap and a +Home-tab gate before driving tabs. + +Bonus zsh trap: `"$CLI:relay"` expands as `$CLI` with zsh's `:r` modifier plus +literal `elay` (target becomes `<session>elay`, tmux "can't find pane"). Always +brace: `"${CLI}:relay"`. diff --git a/.kilo_workflow/learnings/mobile-metro-file-map-stale-after-node-modules-relayout.md b/.kilo_workflow/learnings/mobile-metro-file-map-stale-after-node-modules-relayout.md new file mode 100644 index 0000000000..a5763f36da --- /dev/null +++ b/.kilo_workflow/learnings/mobile-metro-file-map-stale-after-node-modules-relayout.md @@ -0,0 +1,20 @@ +# mobile-metro-file-map-stale-after-node-modules-relayout + +Symptom: after a dependency-layout change (e.g. a root patch changes pnpm peer-hash +dirs), the dev client deterministically white-screens and logcat shows +`ReactNativeJS: [runtime not ready]: RangeError: Maximum call stack size exceeded`, +stack `metroRequire` → repeated `get NativeModules@<line>:56`. Metro serves a bundle +in which a proxy module (here `react-native-css/dist/commonjs/components/index.cjs`) +has `require("react-native")` resolved back to itself. + +Cause: Metro's jest-haste-map cache in `$TMPDIR/metro-file-map-expo-*` persists per +project root across `pnpm install`s. Stale entries pointing into old `.pnpm` peer-hash +directories still validate while those dirs exist on disk (pnpm keeps them), so the +resolver serves modules from the stale instance and NativeWind's +"am I inside react-native-css?" exclusion misfires. + +Fix: identify the project file-map (`grep -ac '<worktree-name>'` the +`$TMPDIR/metro-file-map-expo-*` files — only one matches), delete it, restart Metro +(`pnpm dev:restart mobile`), re-fetch the bundle with a cache-bust query param, and +verify the proxy's dep map points at the real `react-native/index.js` module id. +Never diagnose "the patch broke the app" from a bundle served before this check. diff --git a/.kilo_workflow/learnings/mobile-native-build-cache-ignores-root-patches.md b/.kilo_workflow/learnings/mobile-native-build-cache-ignores-root-patches.md new file mode 100644 index 0000000000..ff7082f252 --- /dev/null +++ b/.kilo_workflow/learnings/mobile-native-build-cache-ignores-root-patches.md @@ -0,0 +1,19 @@ +# mobile-native-build-cache-ignores-root-patches + +Symptom: after applying a root-level `patches/` or `pnpm-workspace.yaml` change +(e.g. a `react-native` Hermes pin), `pnpm dev:mobile:android build` / +`pnpm dev:mobile:ios build` still installs a binary that behaves as if the +patch were absent. Easy to conclude "the patch had no effect." + +Cause: the Android and iOS native build wrappers key on an `@expo/fingerprint` +hash computed over `apps/mobile` (plus toolchain) only. Root `patches/`, +`pnpm-workspace.yaml`, and `pnpm-lock.yaml` are outside that root, so the +fingerprint is unchanged and a warm +`~/Library/Caches/Kilo/mobile-android-builds` / +`…/mobile-ios-builds` entry is reused. + +Fix: force a rebuild by deleting `entries/<key>` for the `key` printed by +`pnpm dev:mobile:android fingerprint` (or `pnpm dev:mobile:ios fingerprint`). +Parse with `pnpm --silent … fingerprint` and slice JSON from the first `{`. +Never conclude a root patch was a no-op from a cached binary. EAS and CI build +from a clean checkout and are unaffected. diff --git a/.kilo_workflow/learnings/pnpm-install-noop-leaves-virtual-store-drift.md b/.kilo_workflow/learnings/pnpm-install-noop-leaves-virtual-store-drift.md new file mode 100644 index 0000000000..d1dba6562d --- /dev/null +++ b/.kilo_workflow/learnings/pnpm-install-noop-leaves-virtual-store-drift.md @@ -0,0 +1,19 @@ +# pnpm-install-noop-leaves-virtual-store-drift + +Symptom: `pnpm install` prints "Already up to date" in <1s and does NOT re-apply +patches or recreate deleted `.pnpm` package dirs — even `pnpm install --force` and +removing `node_modules/.modules.yaml` no-op. Hand-edited files under +`node_modules/.pnpm/<pkg>/` stay edited; deleted package dirs stay deleted (symlinks +dangle), and stale duplicate peer-hash instances (react-native-css, nativewind, +react-native) accumulate and poison Metro bundling (see +mobile-metro-file-map-stale-after-node-modules-relayout.md). + +Cause: pnpm v11 short-circuits headless install when +`node_modules/.pnpm-workspace-state-v1.json` matches the lockfile; it never +re-verifies virtual-store contents. Patch re-application only happens during a real +(re)link pass. + +Fix: `rm -f node_modules/.pnpm-workspace-state-v1.json && pnpm install` forces the +full relink (~1 min, re-applies patches, prunes stale peer-hash instances). Verify +with `xxd`/`cat` on the patched files afterwards. The install does not disturb +running dev services; restart Metro afterwards as cheap insurance.