Files
shopify-ai-backup/opencode/specs/perf-roadmap.md
2026-02-07 20:54:46 +00:00

197 lines
6.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
## 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**: `SM` / 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` / lowmed
---
### 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**: `ML` / 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` / medhigh
---
### 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)?