#+TITLE: Improvise Roadmap #+AUTHOR: Edward Langley #+TODO: TODO DOING WAIT | DONE #+STARTUP: overview #+TAGS: epic standalone P0 P1 P2 P3 P4 task feature bug #+PROPERTY: COOKIE_DATA todo recursive Generated from ~bd list --json~. 45 open issues organised as 14 inverted dep-trees: each root is a goal that nothing else depends on; its children are the deps blocking it. Diamonds in the DAG are duplicated so each tree stands alone. * DOING 'o' (add-record-row) broken in fresh data models (standalone) :standalone:P2:bug:@cursor_f4c497bb: :PROPERTIES: :ID: improvise-s0h :TYPE: bug :PRIORITY: P2 :STATUS: in_progress :ASSIGNEE: cursor-f4c497bb :OWNER: el-github@elangley.org :CREATED_BY: spot :CREATED: 2026-04-09 22:18:58 :UPDATED: 2026-04-14 08:07:41 :KIND: standalone :END: ** Details *** Description Pressing 'o' in records mode to add a new record row doesn't work correctly with fresh data models. The keybinding exists (add-record-row + enter-edit-at-cursor sequence) but the behavior is broken. Needs investigation to reproduce and fix. * TODO Virtual views _Records and _Drill should not be persisted to .improv files (standalone) :standalone:P2:task: :PROPERTIES: :ID: improvise-60z :TYPE: task :PRIORITY: P2 :STATUS: open :OWNER: el-github@elangley.org :CREATED_BY: Edward Langley :CREATED: 2026-04-15 11:13:29 :UPDATED: 2026-04-15 11:13:29 :KIND: standalone :END: * TODO Epic: Browser frontend via synchronized Redux-style stores (epic) [0/68] :epic:P2:feature: :PROPERTIES: :ID: improvise-6jk :TYPE: feature :PRIORITY: P2 :STATUS: open :OWNER: el-github@elangley.org :CREATED_BY: spot :CREATED: 2026-04-14 07:21:21 :UPDATED: 2026-04-14 07:21:21 :KIND: epic :END: ** Details *** Description Build a browser frontend for improvise by treating the client as a thin Redux-style peer of the existing server. Commands are the wire format; each side runs a reducer over its own state slice. Server is structurally unchanged (still runs today's full App with ratatui session, effect pipeline, formula eval). Client is a new thin peer: ViewState + render cache + reduce_view + keymap + DOM renderer. Commands flow both directions — upstream (user intent resolved client-side) and downstream (projection commands emitted by the server after model-touching effects). See child issues for sequenced steps. *** Design Client holds ViewState (mode, cursor, scroll, minibuffer, search, yanked, expanded cats, drill buffer, panel cursors) plus a render cache (visible cells, labels, col widths). Server holds full App as today. Wire type: Command enum, serde over websocket. Upstream: user-initiated commands resolved by client-side keymap. Downstream: projection commands (CellsUpdated, ColumnLabelsChanged, etc.) emitted by server after effect application. Client reduce_view pattern-matches commands and applies view-slice effects; client never runs formula eval or touches Model. Server emits projections by walking the effect list after each command and computing per-viewport deltas per connected client. Effect split (model vs view) is a server-internal tag driving projection emission — never crosses the wire. Key→command resolution is client-side (keymap in wasm bundle) for local responsiveness. *** Notes Prereqs from crate-split epic (improvise-xgl): step 2 (improvise-core, improvise-36h) for shared types; step 5 (improvise-command split, improvise-3mm) so wasm client can import keymap + Command + reduce_view without ratatui. Step 4 (Effect enum, improvise-45v) useful but not strictly required. Target bundle: 200-500 KB compressed — formula layer stays server-side. ** DOING Split AppState into ModelState + ViewState (standalone refactor) (standalone) :standalone:P2:feature:@Edward_Langley: :PROPERTIES: :ID: improvise-vb4 :TYPE: feature :PRIORITY: P2 :STATUS: in_progress :ASSIGNEE: Edward Langley :OWNER: el-github@elangley.org :CREATED_BY: spot :CREATED: 2026-04-14 07:21:59 :UPDATED: 2026-04-15 10:24:54 :KIND: standalone :END: *** Details **** Description Refactor the current App struct to make the model/view slice boundary explicit in types. Today App mixes Model with session state (mode, cursor, scroll, buffers, etc.); split them so that ModelState holds document state and ViewState holds per-session UI state. Server continues to own both, but as distinct fields. Valuable independently of the browser epic: cleaner persistence (only model slice serializes), cleaner undo (undo walks model effects only), better test boundaries, and it's the foundational slice separation every downstream issue depends on. **** Design pub struct ModelState { model: Model, file_path: Option, dirty: bool }. pub struct ViewState { mode: AppMode, selected, row_offset, col_offset, search_query, search_mode, yanked, buffers, expanded_cats, help_page, drill_state_session_part, tile_cursor, panel_cursors }. App becomes { model_state: ModelState, view_state: ViewState, layout: GridLayout, ... }. Audit every App field and assign it. Gray zones: Model.views stays in Model (document state). drill_state staging map is session (View); commit flushes to Model. yanked is View. file_path/dirty are Model. **** Acceptance Criteria (1) App contains ModelState and ViewState as typed subfields. (2) No App field lives outside exactly one slice (or is explicitly called out as derived, like layout cache). (3) All existing tests pass. (4) Effect apply methods updated to take &mut the correct slice where obvious, or &mut App where cross-cutting. (5) Audit report in issue notes: every field classified. **** Notes Can start immediately — no dependencies. Does not require the crate-split epic. Purely a refactor of src/ui/app.rs + touchpoints in effects and commands. ** TODO Browser frontend MVP: end-to-end working demo (epic) [0/23] :epic:P2:feature: :PROPERTIES: :ID: improvise-1ey :TYPE: feature :PRIORITY: P2 :STATUS: open :OWNER: el-github@elangley.org :CREATED_BY: spot :CREATED: 2026-04-14 07:24:44 :UPDATED: 2026-04-14 07:24:44 :KIND: epic :END: *** Details **** Description Wire everything together into a working browser demo: start the ws-server, open the HTML shell in a browser, it loads the wasm client, connects to the websocket, receives the initial snapshot, renders the grid, accepts keystrokes, and round-trips commands to the server. This is the milestone where the architecture proves itself end-to-end. Scope: open an existing .improv file server-side, view it in the browser, type a number into a cell, see the server-side value update and the browser's projection arrive with the new value. **** Design HTML shell: minimal index.html with a
for the grid and a