Skip to content

issues-store-rename

M4 of the eval/issue/remark refactor — finish the forum kill at the bottom data layer. The local issue store's on-disk directory becomes .spec/.issues (was .spec/.forum), with a one-shot self-migration so every existing deployment renames itself on first touch and no thread is lost.

raw source

M3 (eval-issue-split) killed the word "forum" from every code identifier, but deliberately left the data directory named .spec/.forum — a rename touches every deployment's on-disk store, so it was parked as residue. The directive was to refactor the substrate all the way down, and the directory name is the bottom-most name there is. So it goes too: the store now lives at .spec/.issues, and the local store is named, top to bottom, as what it holds — a local Issue.

The one thing a data-dir rename must not do is break a running deployment or lose a thread. The store is plain git-tracked files under a fixed path (local-issues); an old toolchain reads .spec/.forum, a new one reads .spec/.issues, and the gap between "toolchain updated" and "directory moved" is exactly where a deployment would silently read an empty store. So the rename cannot be a manual step someone remembers to run on each box — it has to ride the store's own first touch.

expanded spec

One mechanism, no per-deployment branch. local-issues owns the store's whole seam, so the migration lives there too and every deployment migrates itself the same way — there is no host-specific if/else and no operator checklist. The trigger is the store's first touch after the toolchain updates: any read (the board, spex issues) or any write (an open/reply/remark) reaches the store through local-issues, and that is where the legacy directory is noticed and moved, before the touch proceeds. A fresh repo that never had .spec/.forum skips it entirely; a deployment that already migrated skips it on the fast path with no work.

The move is one committed rename on the trunk, so history survives. Because the store is git (a thread's version and reply history are read from the commit log), the migration is a single git mv of the directory committed straight to the main checkout — not a copy-and-delete. A --follow read of any thread after the move traces cleanly back through the rename into its whole pre-rename history: the reply timeline reads identically. The commit is data, not a spec version (a pure rename bumps no node), and lands --no-verify like every other store write, so it needs no main-guard exception.

Atomic against a first-touch burst, loud on the pathological case. SpexCode runs parallel workers, so the first store touch after an update can arrive from several at once. The find-check-move runs under the same store lock every write already holds (local-issues), so a burst produces exactly one rename commit: the racer that waited re-checks under the lock and finds the move already done. The one state the store must never resolve by guessing is both directories present — a genuine .spec/.forum and a genuine .spec/.issues — since auto-merging could drop threads; that fails loud with the manual repair, never a silent union.

This retires eval-issue-split's "deliberate residue": the forum kill is now complete at every layer, and the migration mechanism — not the old name — is the standing contract.