# Changelog All notable changes to graceful-handoff are documented here. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). ## [3.2.1] - 2026-08-09 The first time the pipeline was ever run against real repositories. It found two defects sitting under a 42/42-green suite — which is the point the repo's own docs had been making about what prose-grep tests can and cannot prove. ### Fixed - **`dirty_files` truncated the first path.** `gitOk()` called `.trim()` on every command's output, but `git status --porcelain` encodes the worktree status in column 2 — a modified-but-unstaged file is `" M path"`. The trim ate that leading space, and the fixed `slice(3)` then ate the first character of the first path: `app.js` was reported as `pp.js`. Only the first line was affected, which is exactly why it survived: no existing test asserted `dirty_files` **values**, only that the key existed. Porcelain output is now read through a non-trimming `gitOkRaw()`. - **The commit message claimed a STATE.md update it did not contain.** `generateCommitMessage()` always produced `docs(): oppdater STATE.md (session handoff)`. On every `open/` repo — including this one — STATE.md is gitignored, so the handoff commit carries only the explicit `--also` paths. Git history is the regime's long-term log; it was systematically wrong about its own contents. The message now branches on what was actually staged. ### Changed - **The leak condition is a hard gate, not an advisory.** A public remote whose STATE.md is not yet gitignored is the state a *fresh* `open/` repo starts in, and `should_commit_state` was `true` there — the ritual merely *mentioned* `leak_warning` and committed anyway. The warning now also lands in `errors[]` (step 2 stops on a non-empty `errors[]`), `should_commit_state` is `false`, and `--commit` refuses to stage STATE.md (`state-leak-blocked`). Explicit `--also` paths are still honoured: the gate protects STATE.md, not the commit as a whole. Both `--plan` and `--commit` now consult one exported `leakBlock()` so they cannot disagree. - **SKILL.md's justification for the single-line rule was outdated.** It claimed a wrapped `rationale=` replaces the repo's next step on the board with garbage. `board.sh` in repo-mailbox 0.20.3 tracks an HTML comment to its closer, so that no longer follows. The rule stands, now stated with the risk that *is* still real: a `rationale=` containing `-->` ends its own comment early. ### Tests - 42 → 48. Four pipeline tests (first-character preservation in `dirty_files`, the `--plan` and `--commit` halves of the leak gate, commit-message honesty) and two SKILL.md drift guards (the corrected single-line rationale, and step 2 stopping rather than reporting). All six were written failing first. ### Not verified - That `/graceful-handoff` loads as a user command (issue [#26251](https://github.com/anthropics/claude-code/issues/26251)), and that a cross-plugin `Skill` invocation of `repo-mailbox:route` passes from a sub-scoped skill. Both need the catalog `ref` bumped so the version is actually installed; the smoke test could exercise the pipeline but not the slash command. ## [3.2.0] - 2026-08-09 ### Changed - **The ritual is back in sync with the global "Session Slutt" mechanism.** SKILL.md had drifted: its STATE.md template predated the mandatory `board:` line and the `route:` / `route-last:` lines, and its closing line still demanded three fields where the global CLAUDE.md now requires six. Both are fixed, and the ordering matters — see below. - **New step 3: route the next session *before* STATE.md is written.** The ritual now invokes the `repo-mailbox:route` skill between `--plan` and the Write. It cannot run after the commit: the emitted lines live *inside* STATE.md, so routing afterwards would dirty a file that was just committed. One invocation feeds two consumers — the three comment lines in the template, and the `Modell neste økt` / `Oppstartskommando` fields in the closing line. Deriving the model by hand in the closing line is exactly what the lookup exists to prevent. - **`repo-mailbox` is a soft dependency.** The plugin is separately installable, so step 3 documents a fallback: if `repo-mailbox` is absent (or the cross-plugin `Skill` invocation is blocked), the ritual continues, fills `next-cost` by judgement, and says so explicitly rather than passing it off as a rubric lookup. `route.sh`'s path is deliberately **not** hardcoded — it sits in the plugin cache behind a version number that drifts. - **The template now carries the single-line constraint in prose, not just by example.** `board.sh` reads the first line under the `👉 NESTE` heading that is non-blank, non-heading and does not *start* with `