# Handoff — 2026-08-31 — the Go menu, and a data race it exposed ## State **Ticket 0017 is partly done and green**, on branch `feature/go-format-lint`, **uncommitted**. `Alt-G` opens a **Go** menu built from `.turbo-go/tools.toml`. Each entry says where its output goes — `popup` (the default), `terminal`, or `editor` — and files the command rewrote that have no unsaved changes are re-read afterwards. **Go ▸ Create tools file** writes a starter file holding the five Go commands, four `popup` and `Run` `terminal`. ``` … Window Snippets Go Help ┌───────────────┐ ┌──────── go vet ./... — exit 1 ────────┐ │ Format │ │ main.go:6:2: unreachable code │ │ Lint │ │ │ │ Build │ │ [ Close ] │ │ Test │ └───────────────────────────────────────┘ │ Run │ ├───────────────┤ │ Create tools… │ └───────────────┘ ``` - New `internal/tools` (95.0 %, both the file and the running of a command) and `internal/projectfile` (75.0 %). - `terminal.Options.Args`, `terminal.ViewOptions`, `View.Exited()`; `Buffer.Reload` with `ErrModified`; `NewOutputDialog`; `App.tick`. - Whole suite green under `-race`, five consecutive runs of the two most affected packages. Quality gate **PASS**: 0/0/0, complexity **down** from 1528 to 1513. - Docs complete in EN and FR — three new pages each, six existing pages updated each. Diagram re-checked against `go list` (39 edges each side). - **Verified in a real terminal**: `go build ./... — ok` with `(no output)`, `go vet ./... — exit 1` with its diagnostic, `gofmt -l -w . — ok` listing the file it rewrote, and the buffer reloading afterwards. Earlier the same day, PR #6 merged the snippets work. ## In flight Nothing. Finished through Phase 8. ## Next steps 1. **Commit and open the PR.** `feature/go-format-lint` is the branch. 2. **Finish ticket 0017.** It also asked for `go mod init` + `touch main.go` — creating a project from nothing, which is a different shape from running a command in an existing one (it needs a name, and there is no project yet). Not done, and the ticket should stay open for it. 3. **Tickets.** 0002, 0003, 0006, 0007, 0009, 0013, 0014 are implemented and open; 0017 is partly implemented. ## Open questions / blockers - **A modal popup holds the whole editor while a command runs.** That was chosen knowingly and is documented, with `output = "terminal"` as the way out for any command it annoys you on. If it turns out to annoy generally, a non-modal output window is the alternative — and it is a different feature, not a tweak. - **`output = "editor"` shows a popup first, then a window.** The popup is how you watch it and how you stop it; the window arrives when you close the popup. It reads oddly written down and is fine in use, but it is worth a second look with real output. - **`go mod init` is not in the menu**, and does not fit the current shape: every other tool runs in the project that already exists, whereas this one creates it and needs a module path typed. It wants a prompt dialog and probably its own item rather than a `tools.toml` entry. - **Nothing jumps to a compile error.** `go build` prints `internal/app/app.go:42:3: …` in the terminal window and you have to open the file yourself. Parsing that output and jumping would be a real win and is a feature of its own — it needs a per-language error format, and the output lives in a terminal emulator rather than in a captured buffer. - **A menu panel still does not scroll** (carried over from the snippets handoff). A `tools.toml` with twenty entries draws a panel taller than the terminal and the bottom is clipped. ## Watch out for - **Verify a new test by breaking the code it covers.** Two tests in this session passed while proving nothing, both because the test drove the step under test: `waitForLoopTurn` called `reloadAfterTools` itself (so the test passed with that step deleted from the loop — hence `App.tick`), and the process-group test killed the shell before it had forked (so it passed without the fix — it now waits for the child to print). Neither was visible by reading. - **Stopping a command must take the process group.** Killing only the shell leaves a grandchild holding the output pipe, and the reading goroutine blocks until *it* ends — 20 seconds in the test suite, and for `go test ./...` it would be every test binary. `processGroup()` and `killGroup()` are build-tagged; `cmd.WaitDelay` is the backstop for anything that escapes. - **A constructor that starts a goroutine must take its callbacks as parameters.** `terminal.NewView` started the reader and callers assigned `OnChange`/`OnExit` afterwards — a data race present since the terminal feature that `-race` never caught, because a shell takes longer to produce its first output than an assignment takes to run. `sh -c "echo x"` finished immediately and the detector fired at once. `ViewOptions` fixes it structurally; do not add an assignable callback back. - **A finished terminal must not swallow keys.** It used to write every key to the dead shell, where the write failed silently and the key was consumed anyway, so `Ctrl-W` could never close the window. `View.HandleKey` returns false after `Exited()`, except for the scrolling keys. `TestAFinishedTerminalStopsTakingKeys` covers it. - **`Buffer.Reload` must refuse over unsaved work.** That restriction is the whole safety of it. `TestReloadRefusesToThrowAwayUnsavedWork` pins it, and `TestAToolLeavesAModifiedBufferAlone` pins the app end of it. - **`internal/buffer`'s atomic write was deliberately left out of `projectfile`.** It preserves the mode of the file it replaces, because it is saving over something the user already had; `projectfile` creates a file with a fixed `0644`. They look alike and are not the same operation — merging them would mean parameterising the mode and losing the different error text. - **`projectfile.Write` already does `MkdirAll`.** The three `Create` functions used to do it themselves; do not add it back. - **The app tests for tools drive the event loop by hand.** `Run` is not running, so `waitForLoopTurn` calls `a.reloadAfterTools()` itself. A test that waits for a reload without calling it will hang until its deadline.