| 📦 Turbo Go 3d7798b k33g 11h ago | 1 | # Handoff — 2026-08-31 — terminal windows |
| 2 | |
| 3 | ## State |
| 4 | |
| 5 | **Terminal windows are done and green.** `F8`, or **Window ▸ New terminal**, opens a window running a real shell in a real pseudo-terminal. Ticket 0007. |
| 6 | |
| 7 | - New package `internal/terminal`: `Session` (pty + process), `Parser` + `Screen` (VT/ANSI emulation, scrollback, alternate screen), `Encode` (keys → terminal bytes), `View` (the `ui` widget). Coverage 95.7 %. |
| 8 | - Wired into `app` via `terminals.go`; `app` coverage went from ~71 % to 82.8 %. |
| 9 | - Two theme keys added, `terminal.text` and `terminal.cursor`, set in all three shipped themes. The theme suite fails if a shipped theme misses one, so that is enforced rather than remembered. |
| 10 | - Whole suite green under `-race` across eight consecutive full runs. |
| 11 | - Quality gate **PASS**: 0 errors, 0 warnings, 0 smells, complexity 1023. |
| 12 | - Docs complete in EN and FR — three new pages each, six existing pages updated each. `docs/diagrams/packages.drawio` was regenerated and then **checked against `go list` programmatically**: it matches the real import graph edge for edge. |
| 13 | - Ticket `0015` created for the Windows/ConPTY port. |
| 14 | |
| 15 | **Nothing has been committed.** The working tree carries the whole feature, the docs, the memory update and the new ticket. |
| 16 | |
| 17 | ## In flight |
| 18 | |
| 19 | Nothing. The feature is finished through Phase 8 of `methodical-dev`. |
| 20 | |
| 21 | ## Next steps |
| 22 | |
| 23 | 1. **Commit.** Suggested message and file list are in the session's final summary; `git status` shows `.tickets/`, `.vscode/` and `kits/` as untracked from before this work — decide what belongs in the repository before staging everything. |
| 24 | 2. **Try a terminal window on a real terminal.** Everything here was verified against a real pty, but nobody has yet opened one inside a running `turbo-go` on a physical terminal emulator and run `vim` or `htop`. That is the check most likely to find something. |
| 25 | 3. **Decide about ticket 0007.** It is the terminal-window ticket and is still `state: open`; closing it was left to the user. |
| 26 | |
| 27 | ## Open questions / blockers |
| 28 | |
| 29 | - **Should `F1`…`F12` be reachable inside a terminal?** They are currently reserved by the editor, so `htop`'s function-key menu cannot be used. The reasoning is written up in `docs/*/explanation/terminal-windows.md`; if the user disagrees, the change is one predicate — `editorOwnedKey` in `internal/app/app.go`. |
| 30 | - **`internal/terminal/pty_darwin.go` has never been run.** It compiles and passes `go vet`, and uses the documented `TIOCPTYGRANT` / `TIOCPTYUNLK` / `TIOCPTYGNAME` ioctls, but this sandbox is Linux. The first Mac run is the test. |
| 31 | - **The tickets' `tasks:` schema is unknown.** Every existing ticket has `tasks: []`, so `0015`'s checklist went into the `body` rather than into an invented task shape. If IssueSpec defines one, move it. |
| 32 | |
| 33 | ## Watch out for |
| 34 | |
| 35 | - **A pseudo-terminal echoes the command line.** A test that types `echo red` and waits for `red` on screen passes *before* the shell has run anything — it matched the echo. Wait for something only the output can produce: a colour, or a string the typed line spells differently (`echo turbo''-go-works` produces `turbo-go-works`). This is the same class of mistake as the gopls-answers-from-disk trap from 2026-08-30. |
| 36 | - **Never assert on a screen cell while a live shell is writing to it.** A drawing test doing that passed by luck and was hiding a real fault: the cell it sampled, (0,0), is where the *cursor* is drawn on a fresh screen, not the text. `newOfflineView` in `view_test.go` builds a `View` with no session behind it — `Draw` needs none — and is the deterministic way to test drawing. |
| 37 | - **`tcell.KeyCtrlC` is 67, not 3.** tcell reports a control byte as `KeyCtrlSpace + b`, and `KeyCtrlSpace` is 64. Code testing `key < 0x20` for a control key matches nothing, silently, and every Ctrl-key would send no bytes at all. |
| 38 | - **The routing order in `App.keyLayers()` is load-bearing.** A focused terminal deliberately sits *above* the global shortcuts. Move it below and `Ctrl-W` closes the window instead of deleting a word — there is a test for exactly that, `TestAFocusedTerminalKeepsTheKeysAShellNeeds`. |
| 39 | - **`terminal.*` theme keys do not fall back to `editor.*`.** Dotted fallback runs along the dots and stops at `default`. A new theme must set both groups. |
| 40 | - **`internal/app/README.md`'s file table was stale** — it listed an `actions.go` that has not existed for some time. It is corrected now; the lesson is that a table of files rots silently. |