diff options
| author | adamelmore <[email protected]> | 2026-01-08 21:18:24 -0600 |
|---|---|---|
| committer | adamelmore <[email protected]> | 2026-01-09 05:07:16 -0600 |
| commit | 559013e1242fa3681f8362a2f0450c3095eb3513 (patch) | |
| tree | 31fd076d3fb1a458471ace2282ce1cac9366e4d0 /specs/perf-roadmap.md | |
| parent | 8e3ab4afa7687abf7cbf937b680a36352ca9421e (diff) | |
| download | opencode-559013e1242fa3681f8362a2f0450c3095eb3513.tar.gz opencode-559013e1242fa3681f8362a2f0450c3095eb3513.zip | |
docs: perf plans
Diffstat (limited to 'specs/perf-roadmap.md')
| -rw-r--r-- | specs/perf-roadmap.md | 196 |
1 files changed, 196 insertions, 0 deletions
diff --git a/specs/perf-roadmap.md b/specs/perf-roadmap.md new file mode 100644 index 000000000..7d5ac93cb --- /dev/null +++ b/specs/perf-roadmap.md @@ -0,0 +1,196 @@ +## Performance roadmap + +Sequenced delivery plan for app scalability + maintainability + +--- + +### Objective + +Deliver the top 5 app improvements (performance + long-term flexibility) in a safe, incremental sequence that: + +- minimizes regression risk +- keeps changes reviewable (small PRs) +- provides escape hatches (flags / caps) +- validates improvements with targeted measurements + +This roadmap ties together: + +- `specs/01-persist-payload-limits.md` +- `specs/02-cache-eviction.md` +- `specs/03-request-throttling.md` +- `specs/04-scroll-spy-optimization.md` +- `specs/05-modularize-and-dedupe.md` + +--- + +### Guiding principles + +- Prefer “guardrails first”: add caps/limits and do no harm, then optimize. +- Always ship behind flags if behavior changes (especially persistence and eviction). +- Optimize at chokepoints (SDK call wrappers, storage wrappers, scroll-spy module) instead of fixing symptoms at every call site. +- Make “hot paths” explicitly measurable in dev (e.g. via `packages/app/src/utils/perf.ts`). + +--- + +### Phase 0 — Baseline + flags (prep) + +**Goal:** make later changes safe to land and easy to revert. + +**Deliverables** + +- Feature-flag plumbing for: + - persistence payload limits (`persist.payloadLimits`) + - request debouncing/latest-only (`requests.*`) + - cache eviction (`cache.eviction.*`) + - optimized scroll spy (`session.scrollSpyOptimized`) + - shared scoped cache (`scopedCache.shared`) +- Dev-only counters/logs for: + - persist oversize detections + - request aborts/stale drops + - eviction counts and retained sizes + - scroll-spy compute time per second + +**Exit criteria** + +- Flags exist but default “off” for behavior changes. +- No user-visible behavior changes. + +**Effort / risk**: `S–M` / low + +--- + +### Phase 1 — Stop the worst “jank generators” (storage + request storms) + +**Goal:** remove the highest-frequency sources of main-thread blocking and redundant work. + +**Work items** + +- Implement file search debounce + stale-result protection + - Spec: `specs/03-request-throttling.md` + - Start with file search only (lowest risk, easy to observe). +- Add persistence payload size checks + warnings (no enforcement yet) + - Spec: `specs/01-persist-payload-limits.md` + - Focus on detecting oversized keys and preventing repeated write attempts. +- Ship prompt-history “strip image dataUrl” behind a flag + - Spec: `specs/01-persist-payload-limits.md` + - Keep image metadata placeholders so UI remains coherent. + +**Exit criteria** + +- Fast typing in file search generates at most 1 request per debounce window. +- Oversize persisted keys are detected and do not cause repeated blocking writes. +- Prompt history reload does not attempt to restore base64 `dataUrl` on web when flag enabled. + +**Effort / risk**: `M` / low–med + +--- + +### Phase 2 — Bound memory growth (in-memory eviction) + +**Goal:** stabilize memory footprint for long-running sessions and “project hopping”. + +**Work items** + +- Introduce shared LRU/TTL cache helper + - Spec: `specs/02-cache-eviction.md` +- Apply eviction to file contents cache first + - Spec: `specs/02-cache-eviction.md` + - Pin open tabs / active file to prevent flicker. +- Add conservative eviction for global-sync per-directory child stores + - Spec: `specs/02-cache-eviction.md` + - Ensure evicted children are fully disposed. +- (Optional) session/message eviction if memory growth persists after the above + - Spec: `specs/02-cache-eviction.md` + +**Exit criteria** + +- Opening many files does not continuously increase JS heap without bound. +- Switching across many directories does not keep all directory stores alive indefinitely. +- Eviction never removes currently active session/file content. + +**Effort / risk**: `M–L` / med + +--- + +### Phase 3 — Large session scroll scalability (scroll spy) + +**Goal:** keep scrolling smooth as message count increases. + +**Work items** + +- Extract scroll-spy logic into a dedicated module (no behavior change) + - Spec: `specs/04-scroll-spy-optimization.md` +- Implement IntersectionObserver tracking behind flag + - Spec: `specs/04-scroll-spy-optimization.md` +- Add binary search fallback for non-observer environments + - Spec: `specs/04-scroll-spy-optimization.md` + +**Exit criteria** + +- Scroll handler no longer calls `querySelectorAll('[data-message-id]')` on every scroll tick. +- Long sessions (hundreds of messages) maintain smooth scrolling. +- Active message selection remains stable during streaming/layout shifts. + +**Effort / risk**: `M` / med + +--- + +### Phase 4 — “Make it easy to keep fast” (modularity + dedupe) + +**Goal:** reduce maintenance cost and make future perf work cheaper. + +**Work items** + +- Introduce shared scoped-cache utility and adopt in one low-risk area + - Spec: `specs/05-modularize-and-dedupe.md` +- Incrementally split mega-components (one PR per extraction) + - Spec: `specs/05-modularize-and-dedupe.md` + - Prioritize extracting: + - session scroll/backfill logic + - prompt editor model/history + - layout event/shortcut wiring +- Remove duplicated patterns after confidence + one release cycle + +**Exit criteria** + +- Each mega-file drops below a target size (suggestion): + - `session.tsx` < ~800 LOC + - `prompt-input.tsx` < ~900 LOC +- “Scoped cache” has a single implementation used across contexts. +- Future perf fixes land in isolated modules with minimal cross-cutting change. + +**Effort / risk**: `L` / med–high + +--- + +### Recommended PR slicing (keeps reviews safe) + +- PR A: add request helpers + file search debounce (flagged) +- PR B: persist size detection + logs (no behavior change) +- PR C: prompt history strip images (flagged) +- PR D: cache helper + file content eviction (flagged) +- PR E: global-sync child eviction (flagged) +- PR F: scroll-spy extraction (no behavior change) +- PR G: optimized scroll-spy implementation (flagged) +- PR H+: modularization PRs (small, mechanical refactors) + +--- + +### Rollout strategy + +- Keep defaults conservative and ship flags “off” first. +- Enable flags internally (dev builds) to gather confidence. +- Flip defaults in this order: + 1. file search debounce + 2. prompt-history image stripping + 3. file-content eviction + 4. global-sync child eviction + 5. optimized scroll-spy + +--- + +### Open questions + +- What are acceptable defaults for storage caps and cache sizes for typical OpenCode usage? +- Does the SDK support `AbortSignal` end-to-end for cancellation, or do we rely on stale-result dropping? +- Should web and desktop persistence semantics be aligned (even if desktop has async storage available)? |
