Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,15 @@ a `slot-acq` window under a proxy `<section>-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.
20 changes: 20 additions & 0 deletions .kilo_workflow/learnings/mobile-android-maestro-flow-pitfalls.md
Original file line number Diff line number Diff line change
@@ -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.
Original file line number Diff line number Diff line change
@@ -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/<other-worktree>" 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 <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.
17 changes: 17 additions & 0 deletions .kilo_workflow/learnings/mobile-e2e-cli-relay-window-wedge.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# mobile-e2e-cli-relay-window-wedge

Symptom: the `relay` window of an orchestrator-prepared
`kilo-e2e-cli-<worktree>` 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 <cli-session> -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.
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# mobile-ios-cold-build-shareextension-pods-root

Symptom: a genuinely cold `pnpm dev:mobile:ios build <udid>` (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.
Original file line number Diff line number Diff line change
@@ -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: '<session title>'` 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 (`'<title>,.*'`) 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"`.
Original file line number Diff line number Diff line change
@@ -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.
Original file line number Diff line number Diff line change
@@ -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.
Original file line number Diff line number Diff line change
@@ -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.
Loading