docs: record final memory leak audit comb (#3308)

This commit is contained in:
Neil 2026-05-29 13:31:20 -07:00 committed by GitHub
parent 869661cbba
commit ca15aeb466
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
1 changed files with 61 additions and 0 deletions

View File

@ -0,0 +1,61 @@
# Memory Leak Audit Final Comb
Started: 2026-05-29 PDT
Final tracker branch: `nwparker/mem-leak-final-comb-tracker`, based on `origin/main` at `869661cbba` after the final-comb fix PRs merged.
Objective: run one more complete pass across the current Orca tree for missed listener, timer, observer, worker, socket, watcher, subscription, abort, and disposable leaks; open scoped PRs for confirmed stranglers; include risk level and merge low-risk PRs.
## Codebase Inventory
Tracked code files, from `git ls-files`:
| Bucket | Files | Status |
| ----------------- | ----: | ------- |
| `src/renderer` | 1584 | Checked |
| `src/main` | 856 | Checked |
| `src/shared` | 245 | Checked |
| `mobile/src` | 100 | Checked |
| `tests/e2e` | 72 | Checked |
| `src/relay` | 65 | Checked |
| `src/cli` | 65 | Checked |
| `config/scripts` | 33 | Checked |
| `mobile/app` | 16 | Checked |
| `other-code` | 5 | Checked |
| `src/preload` | 6 | Checked |
| `mobile/packages` | 5 | Checked |
| Total | 3052 | Checked |
## Scan Log
- 2026-05-29: Created fresh final-comb branch from current `origin/main`.
- 2026-05-29: Fast-forwarded the final-comb branch as `origin/main` moved; final tracker is based on `869661cbba`.
- 2026-05-29: Counted 3341 broad risk-pattern hits across `src`, `mobile`, `tests`, `config`, and `native` on the final post-fix tree.
- 2026-05-29: Re-ran heuristic buckets after fixes:
- `addEventListener` without same-file `removeEventListener`: 37 remaining. Reviewed as React Native subscriptions with `.remove()`, injected WebView document-lifetime scripts, `{ once: true }` image load handlers, IPC abort-signal test listeners, singleton image-cache invalidation, owned pane-divider DOM, and test fixture listeners.
- `setInterval` without `clearInterval`: 1 remaining, a test comment string.
- `setTimeout` without same-file `clearTimeout`: 233 remaining. Reviewed remaining main-process hits as sleep helpers, intentional app relaunch/exit delays, socket idle timeout ownership, usage-scanner yield points, and startup force-exit behavior. Confirmed final-comb timer findings are fixed in PRs listed below.
- Observers without `disconnect`: 0.
- Workers without `terminate`: 0.
- Abort controllers without `abort`: 1 test-only controller passed through the abortable API under test.
- Watchers without close/unwatch: no production misses; remaining heuristic hits are provider type/comment references.
- 2026-05-29: Re-ran React effect scan and spot-checked candidates. Remaining hits had cleanup returns (`clearTimeout`, `clearInterval`, `removeEventListener`, IPC unsubscribe) or were short one-shot UI focus/open delays.
## Findings
| PR | Risk | Status | Finding | Resolution |
| -- | ---- | ------ | ------- | ---------- |
| [#3305](https://github.com/stablyai/orca/pull/3305) | LOW | Merged | Browser reload fallback timer retained the reload promise closure, webContents reference, and listeners until the 10s fallback fired even after `did-finish-load`/`did-fail-load`. | Clear the fallback timer on early settle, guard duplicate cleanup, and test with fake timers. |
| [#3306](https://github.com/stablyai/orca/pull/3306) | LOW | Merged | Native notification retention timers stayed scheduled after close/click cleanup, retaining notification closures until fallback expiry. | Clear notification fallback timers on release, detach native listeners, and cover dispatch/startup/accessibility notification paths. |
| [#3307](https://github.com/stablyai/orca/pull/3307) | LOW | Merged | Local-network permission UDP prompt kept its 1s fallback timer and socket error listener after the send callback settled first. | Clear the fallback timer, remove the error listener, and test the `developerPermissions:request` local-network path. |
No higher-risk findings remained after the final pass, so no second higher-risk mitigation pass was needed.
## Validation
- `pnpm vitest run --config config/vitest.config.ts src/main/browser/agent-browser-bridge.test.ts`
- `pnpm vitest run --config config/vitest.config.ts src/main/browser/agent-browser-bridge.test.ts src/main/ipc/notifications.test.ts src/main/computer/permissions.test.ts src/main/ipc/developer-permissions.test.ts`
- `pnpm vitest run --config config/vitest.config.ts src/main/ipc/notifications.test.ts src/main/computer/permissions.test.ts`
- `pnpm vitest run --config config/vitest.config.ts src/main/ipc/developer-permissions.test.ts`
- `pnpm exec oxlint src/main/browser/agent-browser-bridge.ts src/main/browser/agent-browser-bridge.test.ts src/main/ipc/notifications.ts src/main/ipc/notifications.test.ts src/main/computer/permissions.ts src/main/computer/permissions.test.ts src/main/ipc/developer-permissions.ts src/main/ipc/developer-permissions.test.ts`
- `pnpm run typecheck:node`