I reviewed the full PRD and avoided everything listed under `## Rejected Recommendations`. These are the highest-impact revisions I’d make. 1. Stable list pagination via snapshot fences Why this improves the plan: your keyset cursor is deterministic for sort/filter, but still vulnerable to duplicates/skips if sync writes land between page fetches. Add a per-browse snapshot fence so one browse session sees a stable dataset. Tradeoff: newest rows are hidden until refresh, which is correct for deterministic triage. ```diff diff --git a/docs/plans/gitlore-tui-prd-v2.md b/docs/plans/gitlore-tui-prd-v2.md @@ 5.2 Issue List - **Pagination:** Windowed keyset pagination with explicit cursor state. + **Pagination:** Windowed keyset pagination with explicit cursor state. + **Snapshot fence:** On list entry, capture `snapshot_upper_updated_at` (ms) and pin all + list-page queries to `updated_at <= snapshot_upper_updated_at`. This guarantees no duplicate + or skipped rows during scrolling even if sync writes occur concurrently. + A "new data available" badge appears when a newer sync completes; `r` refreshes the fence. @@ 5.4 MR List - **Pagination:** Same windowed keyset pagination strategy as Issue List. + **Pagination:** Same strategy plus snapshot fence (`updated_at <= snapshot_upper_updated_at`) + for deterministic cross-page traversal under concurrent sync writes. @@ 4.7 Navigation Stack Implementation + Browsing sessions carry a per-screen `BrowseSnapshot` token to preserve stable ordering + until explicit refresh or screen re-entry. ``` 2. Query budgets and soft deadlines Why this improves the plan: currently “slow query” is handled mostly by cancellation and stale-drop. Add explicit latency budgets so UI responsiveness stays predictable under worst-case filters. Tradeoff: sometimes user gets partial/truncated results first, followed by full results on retry/refine. ```diff diff --git a/docs/plans/gitlore-tui-prd-v2.md b/docs/plans/gitlore-tui-prd-v2.md @@ 4.5 Async Action System + #### 4.5.2 Query Budgets and Soft Deadlines + Each query type gets a budget: + - list window fetch: 120ms target, 250ms hard deadline + - detail phase-1 metadata: 75ms target, 150ms hard deadline + - search lexical/hybrid: 250ms hard deadline + On hard deadline breach, return `QueryDegraded { truncated: true }` and show inline badge: + "results truncated; refine filter or press r to retry full". + Implementation uses SQLite progress handler + per-task interrupt deadline. @@ 9.3 Phase 0 — Toolchain Gate + 26. Query deadline behavior validated: hard deadline cancels query and renders degraded badge + without blocking input loop. ``` 3. Targeted cache invalidation and prewarm after sync Why this improves the plan: `invalidate_all()` after sync throws away hot detail cache and hurts the exact post-sync workflow you optimized for. Invalidate only changed keys and prewarm likely-next entities. Tradeoff: slightly more bookkeeping in sync result handling. ```diff diff --git a/docs/plans/gitlore-tui-prd-v2.md b/docs/plans/gitlore-tui-prd-v2.md @@ 4.1 Module Structure - entity_cache.rs # Bounded LRU cache ... Invalidated on sync completion. + entity_cache.rs # Bounded LRU cache with selective invalidation by changed EntityKey + # and optional post-sync prewarm of top changed entities. @@ 4.4 App — Implementing the Model Trait (Msg::SyncCompleted) - // Invalidate entity cache — synced data may have changed. - self.entity_cache.invalidate_all(); + // Selective invalidation: evict only changed entities from sync delta. + self.entity_cache.invalidate_keys(&result.changed_entity_keys); + // Prewarm top N changed/new entities for immediate post-sync triage. + self.enqueue_cache_prewarm(&result.changed_entity_keys); ``` 4. Exact “what changed” navigation without new DB tables Why this improves the plan: your summary currently uses timestamp filter; this can include unrelated updates and miss edge cases. Keep an in-memory delta ledger per sync run and navigate by exact IDs. Tradeoff: small memory overhead per run; no schema migration required. ```diff diff --git a/docs/plans/gitlore-tui-prd-v2.md b/docs/plans/gitlore-tui-prd-v2.md @@ 5.9 Sync (Summary mode) -- `i` navigates to Issue List pre-filtered to "since last sync" (using `sync_status.last_completed_at` timestamp comparison) -- `m` navigates to MR List pre-filtered to "since last sync" (using `sync_status.last_completed_at` timestamp comparison) +- `i` navigates to Issue List filtered by exact issue IDs changed in this sync run +- `m` navigates to MR List filtered by exact MR IDs changed in this sync run + (fallback to timestamp filter only if run delta not available) @@ 10.1 New Files +crates/lore-tui/src/sync_delta_ledger.rs # In-memory per-run exact changed/new IDs (issues/MRs/discussions) ``` 5. Adaptive render governor (runtime performance safety) Why this improves the plan: capability detection is static; you also need dynamic adaptation when frame time/backpressure worsens (SSH, tmux nesting, huge logs). Tradeoff: visual richness may step down automatically under load. ```diff diff --git a/docs/plans/gitlore-tui-prd-v2.md b/docs/plans/gitlore-tui-prd-v2.md @@ 3.4.1 Capability-Adaptive Rendering +#### 3.4.2 Adaptive Render Governor +Runtime monitors frame time and stream pressure: +- if frame p95 > 40ms or sync drops spike, switch to lighter profile: + plain markdown, reduced tree guides, slower spinner tick, less frequent repaint. +- when stable for N seconds, restore previous profile. +CLI override: +`lore tui --render-profile=auto|quality|balanced|speed` @@ 9.3 Phase 0 — Toolchain Gate +27. Frame-time governor validated: under induced load, UI remains responsive and input latency +stays within p95 < 75ms while auto-downgrading render profile. ``` 6. First-run/data-not-ready screen (not an init wizard) Why this improves the plan: empty DB or missing indexes will otherwise feel broken. A dedicated read-only readiness screen improves first impression and self-recovery. Tradeoff: one extra lightweight screen/state. ```diff diff --git a/docs/plans/gitlore-tui-prd-v2.md b/docs/plans/gitlore-tui-prd-v2.md @@ 4.3 Core Types (Screen enum) Sync, Stats, Doctor, + Bootstrap, @@ 5.11 Doctor / Stats (Info Screens) +### 5.12 Bootstrap (Data Readiness) +Shown when no synced projects/documents are present or required indexes are missing. +Displays concise readiness checks and exact CLI commands to recover: +`lore sync`, `lore migrate`, `lore --robot doctor`. +Read-only; no auto-execution. ``` 7. Global project scope pinning across screens Why this improves the plan: users repeatedly apply the same project filter across dashboard/list/search/timeline/who. Add a global scope pin to reduce repetitive filtering and speed triage. Tradeoff: must show clear “scope active” indicator to avoid confusion. ```diff diff --git a/docs/plans/gitlore-tui-prd-v2.md b/docs/plans/gitlore-tui-prd-v2.md @@ 4.1 Module Structure + scope.rs # Global project scope context (all-projects or pinned project set) @@ 8.1 Global (Available Everywhere) +| `P` | Open project scope picker / toggle global scope pin | @@ 4.10 State Module — Complete +pub global_scope: ScopeContext, // Applies to dashboard/list/search/timeline/who queries @@ 10.11 Action Module — Query Bridge - pub fn fetch_issues(conn: &Connection, filter: &IssueFilter) -> Result, LoreError> + pub fn fetch_issues(conn: &Connection, scope: &ScopeContext, filter: &IssueFilter) -> Result, LoreError> ``` 8. Concurrency correctness tests for pagination and cancellation races Why this improves the plan: current reliability tests are good, but missing a direct test for duplicate/skip behavior under concurrent sync writes while paginating. Tradeoff: additional integration test complexity. ```diff diff --git a/docs/plans/gitlore-tui-prd-v2.md b/docs/plans/gitlore-tui-prd-v2.md @@ 9.2 Phases (Phase 5.5 — Reliability Test Pack) + Concurrent pagination/write race tests :p55j, after p55h, 1d + Query deadline cancellation race tests :p55k, after p55j, 0.5d @@ 9.3 Phase 0 — Toolchain Gate +28. Concurrent pagination/write test proves no duplicates/skips within a pinned browse snapshot. +29. Cancellation race test proves no cross-task interrupt bleed and no stuck loading state. ``` 9. URL opening policy v2: allowlisted GitLab entity paths Why this improves the plan: host validation is necessary but not always sufficient. Restrict default browser opens to known GitLab entity paths and require confirmation for unusual paths on same host. Tradeoff: occasional extra prompt for uncommon but valid URLs. ```diff diff --git a/docs/plans/gitlore-tui-prd-v2.md b/docs/plans/gitlore-tui-prd-v2.md @@ 3.1 Risk Matrix -| Malicious URL in entity data opened in browser | Medium | Low | URL host validated against configured GitLab instance before `open`/`xdg-open` | +| Malicious URL in entity data opened in browser | Medium | Low | Validate scheme+host+port and path pattern allowlist (`/-/issues/`, `/-/merge_requests/`, project issue/MR routes). Unknown same-host paths require explicit confirm modal. | @@ 10.4.1 Terminal Safety — Untrusted Text Sanitization - pub fn is_safe_url(url: &str, allowed_origins: &[AllowedOrigin]) -> bool + pub fn classify_safe_url(url: &str, policy: &UrlPolicy) -> UrlSafety + // UrlSafety::{AllowedEntityPath, AllowedButUnrecognizedPath, Blocked} ``` These 9 changes are additive, avoid previously rejected ideas, and materially improve determinism, responsiveness, post-sync usefulness, and safety without forcing a big architecture reset.