Comprehensive product requirements document for the gitlore TUI built on
FrankenTUI's Elm architecture (Msg -> update -> view). The PRD (7800+
lines) covers:
Architecture: Separate binary crate (lore-tui) with runtime delegation,
Elm-style Model/Cmd/Msg, DbManager with closure-based read pool + WAL,
TaskSupervisor for dedup/cancellation, EntityKey system for type-safe
entity references, CommandRegistry as single source of truth for
keybindings/palette/help.
Screens: Dashboard, IssueList, IssueDetail, MrList, MrDetail, Search
(lexical/hybrid/semantic with facets), Timeline (5-stage pipeline),
Who (expert/workload/reviews/active/overlap), Sync (live progress),
CommandPalette, Help overlay.
Infrastructure: InputMode state machine, Clock trait for deterministic
rendering, crash_context ring buffer with redaction, instance lock,
progressive hydration, session restore, grapheme-safe text truncation
(unicode-width + unicode-segmentation), terminal sanitization (ANSI/bidi/
C1 controls), entity LRU cache.
Testing: Snapshot tests via insta, event-fuzz, CLI/TUI parity, tiered
benchmark fixtures (S/M/L), query-plan CI enforcement, Phase 2.5
vertical slice gate.
9 plan-refine iterations (ChatGPT review -> Claude integration):
Iter 1-3: Connection pool, debounce, EntityKey, TaskSupervisor,
keyset pagination, capability-adaptive rendering
Iter 4-6: Separate binary crate, ANSI hardening, session restore,
read tx isolation, progressive hydration, unicode-width
Iter 7-9: Per-screen LoadState, CommandRegistry, InputMode, Clock,
log redaction, entity cache, search cancel SLO, crash diagnostics
Also includes the original tui-prd.md (ratatui-based, superseded by v2).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
163 lines
8.0 KiB
Markdown
163 lines
8.0 KiB
Markdown
I excluded everything already listed in `## Rejected Recommendations`.
|
||
These are the highest-impact net-new revisions I’d make.
|
||
|
||
1. **Enforce Entity Identity Consistency End-to-End (P0)**
|
||
Analysis: The PRD defines `EntityKey`, but many code paths still pass bare `iid` (`IssueSelected(item.iid)`, timeline refs, search refs). In multi-project datasets this will cause wrong-entity navigation and subtle data corruption in cached state. Make `EntityKey` mandatory in every navigation message and add compile-time constructors.
|
||
```diff
|
||
@@ 4.3 Core Types
|
||
pub struct EntityKey {
|
||
pub project_id: i64,
|
||
pub iid: i64,
|
||
pub kind: EntityKind,
|
||
}
|
||
+impl EntityKey {
|
||
+ pub fn issue(project_id: i64, iid: i64) -> Self { Self { project_id, iid, kind: EntityKind::Issue } }
|
||
+ pub fn mr(project_id: i64, iid: i64) -> Self { Self { project_id, iid, kind: EntityKind::MergeRequest } }
|
||
+}
|
||
|
||
@@ 10.10 state/issue_list.rs
|
||
- .map(|item| Msg::IssueSelected(item.iid))
|
||
+ .map(|item| Msg::IssueSelected(EntityKey::issue(item.project_id, item.iid)))
|
||
|
||
@@ 10.10 state/mr_list.rs
|
||
- .map(|item| Msg::MrSelected(item.iid))
|
||
+ .map(|item| Msg::MrSelected(EntityKey::mr(item.project_id, item.iid)))
|
||
```
|
||
|
||
2. **Make TaskSupervisor Mandatory for All Background Work (P0)**
|
||
Analysis: The plan introduces `TaskSupervisor` but still dispatches many direct `Cmd::task` calls. That will reintroduce stale updates, duplicate queries, and priority inversion under rapid input. Centralize all background task creation through one spawn path that enforces dedupe, cancellation tokening, and generation checks.
|
||
```diff
|
||
@@ 4.5.1 Task Supervisor (Dedup + Cancellation + Priority)
|
||
-The supervisor is owned by `LoreApp` and consulted before dispatching any `Cmd::task`.
|
||
+The supervisor is owned by `LoreApp` and is the ONLY allowed path for background work.
|
||
+All task launches use `LoreApp::spawn_task(TaskKey, TaskPriority, closure)`.
|
||
|
||
@@ 4.4 App — Implementing the Model Trait
|
||
- Cmd::task(move || { ... })
|
||
+ self.spawn_task(TaskKey::LoadScreen(screen.clone()), TaskPriority::Navigation, move |token| { ... })
|
||
```
|
||
|
||
3. **Remove the Sync Streaming TODO and Make Real-Time Streaming a GA Gate (P0)**
|
||
Analysis: Current text admits sync progress is buffered with a TODO. That undercuts one of the main value props. Make streaming progress/log delivery non-optional, with bounded buffers and dropped-line accounting.
|
||
```diff
|
||
@@ 4.4 start_sync_task()
|
||
- // TODO: Register rx as subscription when FrankenTUI supports it.
|
||
- // For now, the task returns the final Msg and progress is buffered.
|
||
+ // Register rx as a live subscription (`Subscription::from_receiver` adapter).
|
||
+ // Progress and logs must render in real time (no batch-at-end fallback).
|
||
+ // Keep a bounded ring buffer (N=5000) and surface `dropped_log_lines` in UI.
|
||
|
||
@@ 9.3 Phase 0 — Toolchain Gate
|
||
+11. Real-time sync stream verified: progress updates visible during run, not only at completion.
|
||
```
|
||
|
||
4. **Upgrade List/Search Data Strategy to Windowed Keyset + Prefetch (P0)**
|
||
Analysis: “Virtualized list” alone does not solve query/transfer cost if full result sets are loaded. Move to fixed-size keyset windows with next-window prefetch and fast first paint; this keeps latency predictable on 100k+ records.
|
||
```diff
|
||
@@ 5.2 Issue List
|
||
- Pagination: Virtual scrolling for large result sets
|
||
+ Pagination: Windowed keyset pagination (window=200 rows) with background prefetch of next window.
|
||
+ First paint uses current window only; no full-result materialization.
|
||
|
||
@@ 5.4 MR List
|
||
+ Same windowed keyset pagination strategy as Issue List.
|
||
|
||
@@ 9.3 Success criteria
|
||
- 7. p95 list page fetch latency < 75ms using keyset pagination on synthetic fixture (10k issues, 5k MRs)
|
||
+ 7. p95 first-paint latency < 50ms and p95 next-window fetch < 75ms on synthetic fixture (100k issues, 50k MRs)
|
||
```
|
||
|
||
5. **Add Resumable Sync Checkpoints + Per-Project Fault Isolation (P1)**
|
||
Analysis: If sync is interrupted or one project fails, current design mostly falls back to cancel/fail. Add checkpoints so long runs can resume, and isolate failures to project/resource scope while continuing others.
|
||
```diff
|
||
@@ 3.1 Risk Matrix
|
||
+| Interrupted sync loses progress | High | Medium | Persist phase checkpoints and offer resume |
|
||
|
||
@@ 5.9 Sync
|
||
+Running mode: failed project/resource lanes are marked degraded while other lanes continue.
|
||
+Summary mode: offer `[R]esume interrupted sync` from last checkpoint.
|
||
|
||
@@ 11 Assumptions
|
||
-16. No new SQLite tables needed (but required indexes must be verified — see Performance SLOs).
|
||
+16. Add minimal internal tables for reliability: `sync_runs` and `sync_checkpoints` (append-only metadata).
|
||
```
|
||
|
||
6. **Add Capability-Adaptive Rendering Modes (P1)**
|
||
Analysis: Terminal compatibility is currently test-focused, but runtime adaptation is under-specified. Add explicit degradations for no-truecolor, no-unicode, slow SSH/tmux paths to reduce rendering artifacts and support incidents.
|
||
```diff
|
||
@@ 3.4 Terminal Compatibility Testing
|
||
+Add capability matrix validation: truecolor/256/16 color, unicode/ascii glyphs, alt-screen on/off.
|
||
|
||
@@ 10.19 CLI Integration
|
||
+Tui {
|
||
+ #[arg(long, default_value="auto")] render_mode: String, // auto|full|minimal
|
||
+ #[arg(long)] ascii: bool,
|
||
+ #[arg(long)] no_alt_screen: bool,
|
||
+}
|
||
```
|
||
|
||
7. **Harden Browser/Open and Log Privacy (P1)**
|
||
Analysis: `open_current_in_browser` currently trusts stored URLs; sync logs may expose tokens/emails from upstream messages. Add host allowlisting and redaction pipeline by default.
|
||
```diff
|
||
@@ 4.4 open_current_in_browser()
|
||
- if let Some(url) = url { ... open ... }
|
||
+ if let Some(url) = url {
|
||
+ if !self.state.security.is_allowed_gitlab_url(&url) {
|
||
+ self.state.set_error("Blocked non-GitLab URL".into());
|
||
+ return;
|
||
+ }
|
||
+ ... open ...
|
||
+ }
|
||
|
||
@@ 5.9 Sync
|
||
+Log stream passes through redaction (tokens, auth headers, email local-parts) before render/storage.
|
||
```
|
||
|
||
8. **Add “My Workbench” Screen for Daily Pull (P1, new feature)**
|
||
Analysis: The PRD is strong on exploration, weaker on “what should I do now?”. Add a focused operator screen aggregating assigned issues, requested reviews, unresolved threads mentioning me, and stale approvals. This makes the TUI habit-forming.
|
||
```diff
|
||
@@ 5. Screen Taxonomy
|
||
+### 5.12 My Workbench
|
||
+Single-screen triage cockpit:
|
||
+- Assigned-to-me open issues/MRs
|
||
+- Review requests awaiting action
|
||
+- Threads mentioning me and unresolved
|
||
+- Recently stale approvals / blocked MRs
|
||
|
||
@@ 8.1 Global
|
||
+| `gb` | Go to My Workbench |
|
||
|
||
@@ 9.2 Phases
|
||
+section Phase 3.5 — Daily Workflow
|
||
+My Workbench screen + queries :p35a, after p3d, 2d
|
||
```
|
||
|
||
9. **Add Rollout, SLO Telemetry, and Kill-Switch Plan (P0)**
|
||
Analysis: You have implementation phases but no production rollout control. Add explicit experiment flags, health telemetry, and rollback criteria so risk is operationally bounded.
|
||
```diff
|
||
@@ Table of Contents
|
||
-11. [Assumptions](#11-assumptions)
|
||
+11. [Assumptions](#11-assumptions)
|
||
+12. [Rollout & Telemetry](#12-rollout--telemetry)
|
||
|
||
@@ NEW SECTION 12
|
||
+## 12. Rollout & Telemetry
|
||
+- Feature flags: `tui_experimental`, `tui_sync_streaming`, `tui_workbench`
|
||
+- Metrics: startup_ms, frame_render_p95_ms, db_busy_rate, panic_free_sessions, sync_drop_events
|
||
+- Kill-switch: disable `tui` feature path at runtime if panic rate > 0.5% sessions over 24h
|
||
+- Canary rollout: internal only -> opt-in beta -> default-on
|
||
```
|
||
|
||
10. **Strengthen Reliability Pack with Event-Fuzz + Soak Tests (P0)**
|
||
Analysis: Current tests are good but still light on prolonged event pressure. Add deterministic fuzzed key/resize/paste streams and a long soak to catch rare deadlocks/leaks and state corruption.
|
||
```diff
|
||
@@ 9.2 Phase 5.5 — Reliability Test Pack
|
||
+Event fuzz tests (key/resize/paste interleavings) :p55g, after p55e, 1d
|
||
+30-minute soak test (no panic, bounded memory) :p55h, after p55g, 1d
|
||
|
||
@@ 9.3 Success criteria
|
||
+12. Event-fuzz suite passes with zero invariant violations across 10k randomized traces.
|
||
+13. 30-minute soak: no panic, no deadlock, memory growth < 5%.
|
||
```
|
||
|
||
If you want, I can produce a single consolidated unified diff of the full PRD text next (all edits merged, ready to apply as v3). |