--- name: stack-close description: Closes out a stack work package once its publish has a green CI run - checks the issue body's final state, checks for docs/ and contract staleness, and records which model and effort ran each phase in the closing comment. Started only by the operator as /stack-close, after stack-build has ended its phase. disable-model-invocation: true --- # Stack Close **Purpose:** Carry out the unchecked closing phase of a stack-development work package, as its own skill rather than a step the build session has to remember to take on its own. **Trigger:** The operator runs `/stack-close`, after `stack-build` ended its phase with a green CI run on the published commit. Nothing else starts this skill: the frontmatter's `disable-model-invocation` keeps Claude Code from invoking it, and in a harness that ignores that key this sentence is the rule. Also for a package that was published in an earlier session and never closed - the operator starts it the same way. `instructions/dev/stack-mode.md` has the rules of a stack-development session and the three phases this one ends; read it first when this session started cold. ## Why this is a separate skill, and why the operator starts it The phases around the checked middle of a work package have no mechanical guard at all - `pytest`, `docs verify`, `instructions verify` and CI cover the code and tests in between, and nothing covers a changelog entry's accuracy, a `docs/` page's staleness, or an issue body's final state (see `docs/model-and-effort-selection.md`). Asking the same session to notice it has crossed into that unchecked stretch - as a prose break inside one long skill - failed twice in a row on this stack (Gitea #42, then #30): both times the session knew the rule and skipped past it anyway, because nothing in the moment forced the question. The first split (Gitea #47) moved the closing procedure into its own skill, so it no longer sat in the session's context as a next step to run past - but the trigger stayed a sentence: the build skill told the agent to "invoke it now", and a prose model-switch offer at the same point never once led to a switch (Gitea #50). Since Gitea #168 the trigger is the operator's slash command, and the skill cannot be invoked by the agent at all in Claude Code. **Be precise about what that buys.** The phase change is now a real stop rather than a sentence in the output, and it is where the operator decides on context and model. What moved is the risk #47 named: forgetting the close is now the operator's failure, not the agent's. Two signals stay to catch it - `publish`'s note that what follows CI is checked by nothing, and an open issue on the board whose criteria are ticked and whose CI is green. Treat a session that reaches this text as the mechanism having worked *this time*, not as proof that it always will. ## Steps 1. **Check the handover you start from.** The body names a green CI run on the published commit (`stack-build` step 6). If it does not, or the run is red, this is not the closing phase yet: say so and recommend `/stack-build #N`. A red run is never closed over. This phase is meant to run on Opus at high effort - a lower effort gives up multi-file consistency first, which is exactly what the staleness check in step 3 needs. If this session runs on something else, say so once and carry on; offer no `/model` or `/effort` switch (see `instructions/dev/stack-mode.md` § Sessions and models), and record it in step 4. 2. **Check that the body is in its final state.** `stack-build` kept it current at three fixed points, so this is a check, not a rewrite - but the test is still what a reader who opens the closed issue tomorrow would conclude: - every acceptance criterion ticked, or struck with the reason it was dropped - proposals that were decided read as decided; a "to decide" section has become the decision and its reasoning; an open, non-blocking question carries its answer - nothing left in the present tense about a defect that no longer exists - what was verified is named - which checks ran, which CI run - not a commit hash alone Fix what is off by rewriting the body (`instructions/dev/issue-tracking.md` steps 2 and 7). **A closing report in a comment does not satisfy this**, however thorough: it reads as complete to whoever writes it and leaves a body still phrased as open work. #44 and #45 both closed exactly this way, the second an hour after the rule was first written down. 3. **Check whether a `docs/` page, a contract, or a new human doc went stale.** A `docs/` page carries no normative sentence, so nothing verifies it by construction (AGENTS.md § File naming) - the same is true of `tools/CONTRACT.md`'s generated command records and any touched `/CONTRACT.md`, whose prose `docs verify` checks only for presence and record membership, never for what a field or a section actually says (`instructions/dev/doc-pull-through.md`); of `README.md`/`INSTALL.md`/`DEVELOPMENT.md` prose; and of a new instruction's own wording, which `instructions verify` checks structurally but never for what it claims. If the change this package shipped moved the reasoning or the behaviour one of these documents describes, update it now; if none did, say so rather than leaving the question unasked. **If the published diff touches an installation instruction, read the human guide against it once more.** Which instructions those are and which human document answers for each is the pull-through table's row in `instructions/dev/doc-pull-through.md` - `stack-build` step 5 applied it before the publish; this is the second reading, after. A deviation found here is filed as a follow-up issue naming both files and the sentence that disagrees, rather than fixed in this phase: the pull-through before the publish missed it, and that miss is worth a record of its own. **If that update moved a `##`/`###` heading, the file's table of contents is now stale** - regenerate it with `tools/wikitool docs toc --apply`, never by editing the list. The region is generated (AGENTS.md invariant 1), `docs verify` fails on stale exactly as on missing, and a pull-through in this phase is a common way to move a heading without noticing. **A pull-through of its own needs its own bump, publish and CI run.** The documents this phase touches are frequently the ones CI's version gate watches - `types/`, `instructions/`, `tools/`, `AGENTS.md`, any `/CONTRACT.md`. A commit into one of those without a `VERSION` line fails the gate (`.gitea/workflows/ci.yml`, "Version gate"), whatever the session meant it as. Reading the edit as "only documentation" is the trap: `types/source.md` is a document *and* a shipped behaviour description, and the gate is scoped by path, not by intent. So run `tools/wikitool version bump --patch` in the same breath as the pull-through - it only advances the running candidate's counter - then publish and wait per `instructions/dev/publish-and-ci.md`, and name that run in the body too. 4. **Record the handover, then close.** The closing comment carries the one changelog line `instructions/dev/issue-tracking.md` step 3 asks for, and the handover for **every phase**, not only this one: | Phase | Model | Effort | Own session? | Context overflowed or compacted? | |---|---|---|---|---| | 1 Design (`stack-dev`) | | | | | | 2 Build (`stack-build`) | | | | | | 3 Closing (`stack-close`) | | | | | plus the issue's `size/` label. Fill every cell, even when all three phases ran the same model in one session - a handover that only flags the unusual case stays silent exactly when an equally unchecked phase also ran cheap. Phases from an earlier session are named from the record (the issue's comments, `CHANGES.md`), not from memory, and marked unknown where the record does not say. These rows are the evidence `docs/model-and-effort-selection.md`'s phase guide is checked against. Then close the issue. ## Decision points - **The work package spans several sessions?** Run this skill once, at the point the package is actually finished and its last publish has a green run - not after every individual publish. - **Resuming a package whose publish landed in an earlier, already-ended session?** Run this skill now, on whatever model the current session is - do not reopen the earlier session to run it "correctly." Step 4 names the earlier phases from the record. - **Nothing to close - the session's own exploration, no publish happened?** This skill does not apply; there is no package to close. ## Scope Follows `stack-build`'s green CI run (`instructions/dev/stack-build/SKILL.md`). Not for wiki content work - use `wiki-ingest`/`wiki-query`/`wiki-manage`/`wiki-lint`/`wiki-status`/ `gtd-weekly-review` for that, whose own closing conventions (`kb/log.md`, page provenance) are unrelated to this tracker-body procedure.