aboutsummaryrefslogtreecommitdiff
path: root/docs/design/vterm-to-ghostel-migration-spec.org
diff options
context:
space:
mode:
Diffstat (limited to 'docs/design/vterm-to-ghostel-migration-spec.org')
-rw-r--r--docs/design/vterm-to-ghostel-migration-spec.org420
1 files changed, 0 insertions, 420 deletions
diff --git a/docs/design/vterm-to-ghostel-migration-spec.org b/docs/design/vterm-to-ghostel-migration-spec.org
deleted file mode 100644
index 5974445ad..000000000
--- a/docs/design/vterm-to-ghostel-migration-spec.org
+++ /dev/null
@@ -1,420 +0,0 @@
-#+TITLE: Migration: vterm → ghostel (single terminal engine)
-#+AUTHOR: Craig Jennings
-#+DATE: 2026-06-04
-
-* Status
-
-READY. Review incorporated (external review, 2026-06-04). Supersedes the
-EAT-consolidation direction in =todo.org= (task "Migrate all terminals from
-vterm to ghostel"). Research background:
-[[file:../2026-05-25-emacs-terminal-comparison.org][docs/2026-05-25-emacs-terminal-comparison.org]].
-
-* Goal
-
-Replace vterm with [[https://github.com/dakra/ghostel][ghostel]] (a native Emacs module over libghostty-vt, the
-Ghostty terminal engine) as the single terminal engine across every
-workflow, and rename the AI-agent launcher =ai-vterm= → =ai-term=. When the
-migration lands, vterm and vterm-toggle are removed from the config.
-
-Why ghostel over the prior EAT plan: ghostel is the most faithful Claude
-Code TUI renderer and the fastest engine (≈81 vs vterm 34 vs eat 4.9 MB/s),
-and an audit confirmed it exposes an analog for every vterm primitive this
-config uses. EAT's washed colors, its scroll-pop / stuck-input bug under
-Claude Code, and its slowest throughput made it the weaker single-engine
-pick. One engine beats running two.
-
-* What the spike established (2026-06-04, read-only)
-
-Sandbox: =/tmp/ghostel-spike= via =emacs --init-directory=, nothing touched
-in the real config. Emacs 30.2 GTK, x86_64, modules supported.
-
-- *Install / multi-machine*: ghostel installs from MELPA; the native module
- auto-downloaded (=v0.33.0 ghostel-module-x86_64-linux.so=) and loaded with
- no toolchain. Confirms the per-machine prebuilt-binary story works
- (x86_64-linux covers velox). Only a non-prebuilt arch needs the Zig build.
-- *tmux pty (linchpin)*: a spawned ghostel reports =process-tty-name
- "/dev/pts/1"=. The tmux pane-id lookup in the current vterm-config keys on
- exactly that, so the tmux copy-mode / history machinery ports unchanged.
-- *Colorization model*: =ghostel-color-palette= is a vector of 16 named
- faces, but =ghostel--apply-palette= RESOLVES those faces (+ =ghostel-default=
- fg/bg) to hex and pushes them to the native module
- (=ghostel--set-palette= / =ghostel--set-default-colors=); the module bakes
- the colors into the grid. Theme changes are handled by =ghostel-sync-theme=
- (hooked to =enable-theme-functions= / =load-theme= advice), which
- re-resolves and re-pushes. *Consequence:* buffer-local =face-remap= does
- NOT dim a ghostel buffer, and there is no per-window color hook. This
- drives Decision D1.
-- *TTY frames*: no =display-graphic-p= / =window-system= guards in
- =ghostel.el= — it renders text + faces and only kitty inline-graphics
- degrade in a TTY. ghostel works in terminal frames (Decision D4).
-- *copy-mode*: a read-only input-mode toggle (=ghostel-copy-mode=) with
- standard Emacs nav / mark; =q= / =C-g= exit, =M-w= copies and stays. The
- vterm copy-mode contract maps near-free.
-- *F8 / key forwarding (diagnostic)*: ghostel's default semi-char mode
- forwards unlisted keys to the terminal program; only
- =ghostel-keymap-exceptions= (default =C-c C-x C-u C-h M-x M-: C-\=) reach
- Emacs. Unlike vterm, binding F9/F12 in =ghostel-mode-map= is NOT enough:
- =ghostel-semi-char-mode-map= is rebuilt from =ghostel-keymap-exceptions= and
- outranks the major-mode map, so a key not in the exceptions is sent to the
- pty before the mode-map binding can fire. The F9 family, F12, and C-; must be
- added to =ghostel-keymap-exceptions= AND the semi-char map rebuilt
- (=ghostel--rebuild-semi-char-keymap=; =add-to-list= alone updates the list
- but not the already-built map). (Shipped wrong in the first cut — F9 did
- nothing in agent buffers until the keys were added to the exceptions.)
-- *GUI / TTY visual*: Craig confirmed the Claude Code TUI and a TTY frame
- both render great. dupre chrome applies; the 16 ANSI terminal faces are
- ghostel defaults (dupre does not theme them) — Decision D2.
-
-* Agreed decisions
-
-All confirmed by Craig 2026-06-04 (incorporating the external review).
-
-- *D1 — auto-dim*: terminal buffers do NOT participate in unfocused-window
- dimming in v1. =auto-dim-config.el= drops its entire vterm integration
- (~140 lines of =vterm--get-color= advice + redraw scheduling). Rationale:
- ghostel bakes the palette per-terminal, not per-window, so vterm's
- per-window dim is not achievable; a buffer-wide palette re-push on
- focus-loss is more code, forces repaints, and only works when the buffer is
- in one window — not worth it.
-- *D2 — dupre ANSI palette*: a follow-up, not v1. The 16 =ghostel-color-*=
- faces (+ =ghostel-default=) get themed in dupre later, unless the engine
- swap exposes visibly poor colors during verification.
-- *D3 — eshell*: out of scope. =ghostel-eshell= adoption is a separate
- follow-up task; eshell stays the shell.
-- *D4 — TTY refuse-guard*: dropped. =cj/--ai-vterm-refuse-in-terminal= and
- its echo-area refusal message are removed; F9 launches in a terminal frame.
- Its manual-verify test is removed too (it asserted the refusal).
-- *D5 — module names*: =vterm-config.el= → =term-config.el=; =ai-vterm.el= →
- =ai-term.el=; =cj/vterm-*= → =cj/term-*=; =cj/ai-vterm-*= → =cj/ai-term-*=.
- The "agent [" buffer prefix is unchanged.
-- *D6 — module-failure behavior*: ghostel degrades with a warning rather than
- failing startup. Load it guarded (=(require 'ghostel nil t)=) and, on
- failure, emit a =display-warning= and leave the terminal commands defined
- but inert. Rationale: the daemon serves many frames across machines, and
- the project idiom is graceful degradation (the =(when (require 'foo nil t)
- ...)= rule and =cj/executable-find-or-warn=); hard-failing startup on a
- machine missing the prebuilt module is worse than a warned degrade. Tests
- stub ghostel and never require the native module. (Modifies the reviewer's
- recommendation of "fail loudly" — see Review dispositions.)
-- *D7 — scrollback value*: =ghostel-max-scrollback= set to =10 MB= (=(* 10
- 1024 1024)=) as a defcustom, the byte analog of the prior =100000=-line
- intent (~100 bytes/line). Verified under heavy output during manual
- testing.
-
-* Primitive mapping (vterm → ghostel)
-
-| vterm | ghostel | note |
-|--------------------------------+-------------------------------------------+------|
-| =(vterm NAME)= | =(ghostel)= + rename to NAME | via =ghostel-buffer-name-function= or post-create rename |
-| =vterm-send-string= | =ghostel-send-string= | public; confirmed |
-| =vterm-send-return= | =(ghostel-send-string "\n")= | |
-| =vterm-mode= | =ghostel-mode= | all major-mode checks |
-| =vterm-mode-map= | =ghostel-mode-map= | F9 + F12 rebind, C-; install |
-| =vterm-keymap-exceptions= | =ghostel-keymap-exceptions= | add =C-;= |
-| =vterm-copy-mode= | =ghostel-copy-mode= | read-only input mode |
-| =vterm-copy-mode-map= bindings | input-mode (q/C-g exit, M-w copies-stays) | near-free parity |
-| =vterm-clear-scrollback= | =ghostel-clear-scrollback= | C-; x l |
-| =vterm-next-prompt= | =ghostel-next-prompt= | C-; x n |
-| =vterm-previous-prompt= | =ghostel-previous-prompt= | C-; x p |
-| =vterm-send-next-key= | =ghostel-send-next-key= | C-; x q |
-| =vterm-yank= | =ghostel-yank= | C-y |
-| =vterm-reset-cursor-point= | drop (renderer owns point) | decided: no analog needed |
-| =vterm-other-window= | =(ghostel)= + other-window display | thin wrapper |
-| =vterm-max-scrollback= (lines) | =ghostel-max-scrollback= = 10 MB (D7) | unit change lines→bytes |
-| =vterm-kill-buffer-on-exit= | =ghostel-kill-buffer-on-exit= | |
-| =vterm-timer-delay= (nil hack) | =ghostel-timer-delay= / adaptive-fps | hacks DROP |
-| =cj/vterm--send-mouse-wheel= | drop (ghostel forwards SGR natively) | net deletion; verify under tmux/Claude/lazygit |
-| =cj/vterm-send-escape= | =(ghostel-send-string "\e")= if needed | re-check =<escape>= global conflict |
-| =vterm--get-color= advice | none (D1) | auto-dim integration deleted |
-| =vterm-always-compile-module= | =ghostel-module-auto-install= | + D6 guarded load |
-| tmux pane-id via =process-tty-name= | unchanged | confirmed /dev/pts |
-
-* Surface to change
-
-Audited file set.
-
-** Main modules
-- =modules/vterm-config.el= (~540L) → =modules/term-config.el=. Ports with
- renamed primitives; deletes the mouse-wheel forwarding and the
- =vterm-timer-delay= hacks; renames =cj/vterm-*= → =cj/term-*= (no
- compatibility shim). Keeps the tmux history / copy-mode-dwim logic pure
- around =process-tty-name= and =tmux= process calls (engine-agnostic — the
- part most worth preserving). =cj/vterm-map= (C-; x) → =cj/term-map=;
- which-key label "vterm menu" → "terminal menu".
-- =modules/ai-vterm.el= (~978L) → =modules/ai-term.el=. Only ~6 call sites
- are vterm-specific (=vterm= / =vterm-send-string= / =vterm-send-return=,
- the suppress-tmux coupling, the =vterm-mode-map= F9 rebind, the
- declare-functions). The ~970L of picker / MRU / crash-recovery / display
- chain / dispatch / geometry is engine-agnostic and renames cleanly
- (=cj/ai-vterm-*= → =cj/ai-term-*=). Buffer prefix "agent [" stays. The
- refuse-in-terminal guard is deleted (D4).
-
- *tmux-suppression invariant (contract).* =cj/--ai-term-show-or-create= must
- preserve exactly one tmux launch path for agent buffers: the dynamic
- binding of the suppress flag around =(ghostel)= keeps the generic
- auto-tmux hook from sending a bare =tmux\n= before the project-named
- =tmux new-session -A= command runs. Porting must not introduce a second
- launch path.
-
-** Satellites
-- =modules/auto-dim-config.el= — per D1, delete the vterm color advice +
- redraw scheduling entirely (no ghostel replacement in v1).
-- =modules/ui-config.el= — =vterm-mode= / =vterm-copy-mode= cursor/modeline
- check → ghostel equivalents (live ghostel = writeable cursor state;
- =ghostel-copy-mode= = read-only).
-- =modules/dashboard-config.el= — launcher lambda → =(ghostel)=; label
- "Launch VTerm" → "Launch Terminal".
-- =modules/cj-window-geometry-lib.el=, =modules/cj-window-toggle-lib.el= —
- vterm only in comments; update doc references.
-- =init.el= — =(require 'ai-vterm)= → =(require 'ai-term)=; add term-config
- require (guarded per D6).
-
-** Docs (active references only — historical notes stay)
-- =todo.org= current task link (already updated to this -spec path).
-- =docs/design/module-inventory.org=, =docs/design/init-load-graph.org= —
- update active =vterm-config= / =ai-vterm= references to the new names.
-
-** Tests (~35 files)
-- 24 =test-ai-vterm--*.el= are mostly engine-agnostic logic (buffer-name,
- candidates, sort, dispatch, geometry, MRU) → rename to =test-ai-term--*.el=
- mechanically, only after a green baseline; assertions stand.
-- Coupled, need rework: =testutil-vterm-buffers.el= (→ stub ghostel),
- =test-ai-vterm--f9-in-vterm.el=, =test-ai-vterm--show-or-create.el=,
- =test-vterm-copy-mode-cursor.el=, =test-vterm-tmux-history.el=,
- =test-vterm-toggle--*.el= (×3).
-- Cross-cutting touch: =test-auto-dim-config.el= (delete vterm-integration
- tests per D1), =test-ui-config--buffer-cursor-state.el=,
- =test-dashboard-config-launchers.el=, =test-init-module-headers.el=,
- =test-cj-window-toggle-lib.el=.
-
-* Dependency / module failure behavior (D6)
-
-- ghostel is a required MELPA package. It loads guarded:
- =(unless (require 'ghostel nil t) (display-warning 'term "..."))=.
-- On a prebuilt arch the native module auto-downloads
- (=ghostel-module-auto-install=). On a non-prebuilt arch the user installs
- Zig 0.15.2 and builds per ghostel's instructions; until then the warning
- fires and terminal commands are inert (defined but no-op / user-error),
- never breaking startup or other frames.
-- Tests stub ghostel in the test-util layer and never require the native
- module, so the suite runs on any machine and in CI/batch.
-
-* Key & menu ownership (per phase)
-
-To avoid order-dependent duplicate bindings, ownership transfers cleanly:
-
-- *Before*: =vterm-config= owns F12, =C-; x=, the vterm display rule, and the
- which-key labels.
-- *Phase 1*: =term-config= is added and immediately becomes the owner of F12
- and =C-; x= (and the terminal display rule). =vterm-config= is no longer
- required, so its bindings do not co-install. The vterm package remains
- installed only as a fallback engine until Phase 4.
-- *Phase 2*: =ai-term= owns the F9 family (global + in =ghostel-mode-map=);
- =ai-vterm= is no longer required.
-- *Phase 4*: vterm / vterm-toggle packages removed; no vterm ownership
- remains anywhere.
-
-* Implementation phases (TDD, green at each step)
-
-Each phase is a shippable deliverable; the suite + byte-compile stay green at
-every step.
-
-- *Phase 0 — characterization baseline.* Before any port, add/confirm
- characterization tests for the behaviors that must survive: F12
- dispatch/display, tmux pane-id + history-buffer replacement, AI
- show-or-create tmux launch command, F9 from inside terminal mode,
- cursor-state classification, dashboard launcher action. Green baseline.
- Deliverable: characterization tests committed; no behavior change.
-- *Phase 1 — ghostel + term-config.* Add ghostel (use-package, MELPA,
- guarded per D6). New =term-config.el= owning F12, =cj/term-map= (C-; x),
- copy-mode parity, tmux history/copy-mode-dwim (pure =process-tty-name=
- path), which-key "terminal menu", =ghostel-max-scrollback= 10 MB,
- =ghostel-keymap-exceptions= incl. =C-;=. =vterm-config= dropped from the
- require list (ownership transfers). Tests for the new module + ghostel
- stubs. Deliverable: F12 general terminal runs on ghostel.
-- *Phase 2 — ai-term.* Rename =ai-vterm.el= → =ai-term.el=; swap the ~6 vterm
- call sites to ghostel; F9/C-F9/M-F9 on global + =ghostel-mode-map=; drop
- the refuse-in-terminal guard (D4); preserve the tmux-suppression invariant.
- Rename engine-agnostic tests to =test-ai-term--*= (after green); rework the
- coupled ones; add D4 regression tests (no refusal path; F9 installed in
- =ghostel-mode-map=) and a negative test that agent buffers are excluded
- from F12 toggling under the new names. Deliverable: agents run on ghostel.
-- *Phase 3 — satellites.* auto-dim vterm integration deleted (D1);
- ui-config cursor/modeline check ported; dashboard launcher + label;
- geometry/toggle-lib doc refs; init.el requires; active doc references.
- Deliverable: no module references vterm except the package itself.
-- *Phase 4 — remove vterm.* Delete vterm + vterm-toggle packages, dead
- config, the mouse-wheel / timer hacks. Full test sweep + byte-compile +
- manual smoke after a daemon restart (the restart is an acceptance gate —
- see below). Deliverable: vterm gone; ghostel is the only terminal engine.
-
-** Follow-up / vNext (not this series)
-- D2 — theme the 16 =ghostel-color-*= + =ghostel-default= faces in dupre.
-- D3 — evaluate =ghostel-eshell= as eshell's visual backend.
-- Evaluate =ghostel-compile= against the F4 dev-fkeys compile flow.
-- =ghostel-comint= for =M-x shell= / REPL output fidelity (optional).
-
-* Acceptance criteria
-
-The migration is complete when all hold:
-
-1. =init.el= requires =term-config= and =ai-term=; nothing in the config
- requires =vterm-config= or =ai-vterm=.
-2. vterm / vterm-toggle packages and their keybindings are removed, after
- ghostel parity is green.
-3. F12 normal-terminal toggle excludes agent buffers and preserves saved
- geometry.
-4. F9 / C-F9 / M-F9 work from normal buffers AND inside =ghostel-mode=
- buffers.
-5. AI project launch reuses/reattaches the named =aiv-= tmux session and does
- NOT receive the generic auto-tmux launch.
-6. =C-; x c= and =C-; x h= preserve the tmux copy / history behavior.
-7. Live ghostel buffers report a writeable cursor state; ghostel copy-mode
- reports read-only.
-8. Terminal-frame F9 launches (the refusal path and its test are gone).
-9. ghostel-unavailable degrades with a warning, not a startup failure (D6).
-10. Full test suite, byte-compile, and manual smoke all pass after a daemon
- restart.
-
-* Test strategy
-
-- *Characterization first* (Phase 0): capture current behavior before porting
- so parity is measurable.
-- *Stub ghostel* in the test-util layer; tests never require the native
- module (runs in batch/CI on any machine).
-- *Rename mechanically after green*: only rename engine-agnostic
- =test-ai-vterm--*= → =test-ai-term--*= once the baseline is green.
-- *Regression tests for D4*: no terminal-frame refusal path remains; F9
- bindings are installed in =ghostel-mode-map=.
-- *Negative test*: agent buffers are excluded from F12 normal-terminal
- toggling under the new buffer/mode names.
-
-* Manual-verify test matrix
-
-Per =verification.md=, filed under "Emacs Manual Testing and Validation" at
-Phase 4, run again after a daemon restart. Each: steps + expected.
-
-- Claude Code TUI in ghostel (GUI): colors true, flicker-free under heavy
- stream, box-drawing + cursor correct.
-- Claude Code TUI in a TTY frame (velox-style =emacs -nw=): renders as
- text+color, layout intact; inline images absent (expected).
-- F9 / C-F9 / M-F9 dispatch: toggle, pick-project, close — same behavior as
- the vterm era, on ghostel, including from a terminal frame (now launches).
-- tmux: agent launches in its named session; second F9 reattaches; close
- kills the session; =C-; x h= captures tmux history; =C-; x c= enters tmux
- copy-mode.
-- copy-mode parity: =M-w= copies and stays, =q= / =C-g= exit.
-- mouse wheel inside tmux / Claude Code / lazygit scrolls correctly (this was
- a prior explicit vterm fix being removed — confirm ghostel's native SGR
- forwarding covers it).
-- lazygit, htop/btop, a heavy-output build, ssh to a remote: render + behave.
-- Crash recovery: kill Emacs with a live =aiv-= tmux session, restart, the
- picker flags it =[detached]= and reattaches.
-
-* Risks / notes
-
-- *Daemon module reload*: a loaded native module needs a daemon restart to
- upgrade; the Phase 4 restart is an acceptance gate before deleting vterm
- (plus the gold-standard full-launch smoke per CLAUDE.md after =:config=
- edits).
-- *Buffer naming*: forcing "agent [basename]" goes through
- =ghostel-buffer-name-function= or a post-create rename — confirm the exact
- hook in Phase 2.
-- *<escape> global rebind*: vterm needed a custom escape forwarder because
- =<escape>= is globally =keyboard-escape-quit=; re-check whether ghostel in
- semi-char mode forwards it or needs the same treatment.
-- *ssh terminfo*: ghostel advertises =TERM=xterm-ghostty=; outbound ssh to
- hosts lacking that terminfo may need =ghostel-ssh-install-terminfo= or a
- fallback =ghostel-term=. Covered by the ssh manual-verify row.
-- *ANSI palette*: until D2 lands, terminal ANSI colors are ghostel defaults.
-
-* Implementation tasks (drop-in for todo.org)
-
-#+begin_src org
-*** TODO [#B] Phase 0: terminal characterization baseline :terminal:ghostel:tests:
-Characterization tests for F12 dispatch/display, tmux pane-id + history replacement, AI show-or-create launch command, F9-in-terminal, cursor-state classification, dashboard launcher. Green baseline, no behavior change.
-*** TODO [#B] Phase 1: add ghostel + term-config.el :terminal:ghostel:
-ghostel use-package (MELPA, guarded per D6); term-config.el owns F12 + C-; x + copy-mode + tmux history; which-key "terminal menu"; ghostel-max-scrollback 10MB; C-; in ghostel-keymap-exceptions. Drop vterm-config from requires. Tests + ghostel stubs.
-*** TODO [#B] Phase 2: rename ai-vterm→ai-term on ghostel :terminal:ghostel:
-Swap the 6 vterm call sites; F9 family on global + ghostel-mode-map; drop refuse-in-terminal guard (D4); preserve tmux-suppression invariant. Rename engine-agnostic tests after green; rework coupled tests; add D4 + F12-excludes-agent regression tests.
-*** TODO [#B] Phase 3: port satellites to ghostel :terminal:ghostel:
-Delete auto-dim vterm integration (D1); port ui-config cursor check; dashboard launcher + "Launch Terminal" label; geometry/toggle-lib doc refs; init.el requires; module-inventory + init-load-graph doc refs.
-*** TODO [#B] Phase 4: remove vterm and vterm-toggle :terminal:ghostel:
-Delete packages + dead config + mouse-wheel/timer hacks. Full suite + byte-compile + manual smoke after daemon restart (acceptance gate). Run the manual-verify matrix.
-*** TODO [#C] Follow-up: theme ghostel ANSI faces in dupre :terminal:ghostel:dupre:
-D2 — set the 16 ghostel-color-* + ghostel-default faces in dupre-faces/palette.
-*** TODO [#C] Follow-up: evaluate ghostel-eshell + ghostel-compile :terminal:ghostel:eval:
-D3 — ghostel-eshell as eshell visual backend; ghostel-compile against F4 dev-fkeys.
-#+end_src
-
-* Review dispositions
-
-Only the *modified* recommendations are listed; everything else in the external
-review was accepted as written.
-
-- *Module-failure behavior (modified).* The reviewer recommended ghostel be required
- and "startup may fail loudly" if the package/module can't load. Modified to
- degrade-with-warning (D6): guarded require + =display-warning=, terminal
- commands inert, startup unaffected. Reason: the daemon serves many frames
- across machines and the project idiom is graceful degradation; hard-failing
- startup on a machine missing the prebuilt module is worse than a warned
- degrade. The rest of the recommendation (ghostel required; non-prebuilt
- needs Zig; tests stub the module) is accepted.
-- *Scrollback value (modified → concretized).* The reviewer asked for a concrete
- byte value or a defcustom. Chose =10 MB= as a defcustom (D7), the byte
- analog of 100000 lines, verified under heavy output. (Not a disagreement —
- filling the gap the review flagged.)
-
-Everything else accepted as written: D1-D5 baked as Agreed decisions;
-Implementation phases + Acceptance criteria + Dependency-failure + Test
-strategy sections added; key/menu ownership made explicit per phase;
-tmux-suppression stated as a contract; UX changes (TTY-refusal removal,
-"Launch Terminal", "terminal menu"); architecture (rename =cj/vterm-*= →
-=cj/term-*=, keep tmux fns pure, no vterm-private-redraw port); doc cleanup
-for active references; mouse-wheel manual verify; daemon-restart acceptance
-gate.
-
-* Review and iteration history
-
-** 2026-06-04 Thursday @ 23:17:54 -0500 — reviewer
-
-- *What changed or was recommended:* Ran the spec-review workflow after
- renaming this file to the required =-spec.org= suffix. Wrote a companion
- review with a =Not ready= rubric: D1-D5 still need acceptance, the handoff
- needs an =Implementation phases= section, acceptance criteria are missing,
- and ghostel package/native-module failure behavior needs an explicit v1
- contract.
-- *Why:* The migration direction is sound, but the current draft still leaves
- implementation-affecting decisions and completion criteria for the builder
- to infer.
-- *Artifacts:* review file (deleted on incorporation).
-
-** 2026-06-04 Thursday @ 23:24:28 -0500 — responder
-
-- *What changed:* Incorporated the external review via the spec-response
- workflow. Craig accepted D1-D5; baked them (plus D6 module-failure and D7
- scrollback) into a new "Agreed decisions" section and out of "Open
- decisions." Added Implementation phases, Acceptance criteria, Dependency /
- module failure behavior, Test strategy, explicit per-phase key/menu
- ownership, the tmux-suppression contract, and an Implementation-tasks
- drop-in block. Applied the UX, architecture, doc-cleanup, and
- manual-verify additions. Status raised DRAFT → READY.
-- *Why:* Close the "Not ready" findings — resolve the open decisions,
- give the builder phases + acceptance criteria, and define
- ghostel-unavailable behavior — so a reader can implement from this file.
-- *Modified vs the review:* module-failure = degrade-with-warning, not
- fail-loud (D6 rationale); scrollback concretized to 10 MB (D7). See Review
- dispositions. Everything else accepted as written.
-- *Artifacts:* This spec; review file deleted; =todo.org= task link updated.
-
-** 2026-06-04 Thursday @ 23:30:18 -0500 — reviewer
-
-- *What changed or was recommended:* Re-reviewed the incorporated spec and
- assigned a =Ready= rubric. No further blocking review notes. The prior
- blockers are closed: D1-D7 are accepted decisions, implementation phases and
- acceptance criteria are present, ghostel-unavailable behavior is explicit,
- key/menu ownership is phased, and implementation tasks are enumerated.
-- *Why:* Confirm the spec-response pass left an implementable handoff rather
- than just adding prose.
-- *Artifacts:* This history entry; no new review file because the spec is
- implementation-ready.