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.
This commit is contained in:
teernisse
2026-02-11 16:00:34 -05:00
parent 125938fba6
commit ffd074499a
6 changed files with 1132 additions and 131 deletions

View File

@@ -0,0 +1,177 @@
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.