Files
gitlore/plans/tui-prd-v2-frankentui.feedback-11.md
teernisse ffd074499a docs: update TUI PRD, time-decay scoring, and plan-to-beads plans
TUI PRD v2 (frankentui): Rounds 10-11 feedback refining the hybrid
Ratatui terminal UI approach — component architecture, keybinding
model, and incremental search integration.

Time-decay expert scoring: Round 6 feedback on the weighted scoring
model for the `who` command's expert mode, covering decay curves,
activity normalization, and bot filtering thresholds.

Plan-to-beads v2: Draft specification for the next iteration of the
plan-to-beads skill that converts markdown plans into dependency-
aware beads with full agent-executable context.
2026-02-12 11:21:32 -05:00

177 lines
9.6 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.
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
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<Vec<IssueListRow>, LoreError>
+ pub fn fetch_issues(conn: &Connection, scope: &ScopeContext, filter: &IssueFilter) -> Result<Vec<IssueListRow>, 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.