Files
gitlore/plans/tui-prd-v2-frankentui.feedback-11.md
teernisse 740607e06d perf: force partial index for DiffNote queries (26-75x), batch stats counts (1.7x)
who.rs: Add INDEXED BY idx_notes_diffnote_path_created to all DiffNote
query paths (expert, expert_details, reviews, path probes, suffix_probe).
SQLite planner was choosing idx_notes_system (106K rows, 38%) over the
partial index (26K rows, 9.3%) when LIKE predicates are present.
Measured: expert 1561ms->59ms (26x), reviews ~1200ms->16ms (75x).

stats.rs: Replace 12+ sequential COUNT(*) queries with conditional
aggregates (SUM(CASE WHEN...)) and use FTS5 shadow table
(documents_fts_docsize) instead of virtual table for counting.
Measured: warm 109ms->65ms (1.68x).
2026-02-12 10:02:48 -05:00

9.6 KiB
Raw Blame History

I reviewed the full PRD and avoided everything listed under ## Rejected Recommendations.
These are the highest-impact revisions Id 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 --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.
  1. 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 --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.
  1. 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 --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);
  1. 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 --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)
  1. 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 --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.
  1. 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 --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.
  1. 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 --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<Vec<IssueListRow>, LoreError>
+ pub fn fetch_issues(conn: &Connection, scope: &ScopeContext, filter: &IssueFilter) -> Result<Vec<IssueListRow>, LoreError>
  1. 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 --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.
  1. 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 --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.