Files
chemenu/instructions/dev/stack-close/SKILL.md
T
torben c77bda2004
CI / verify (push) Successful in 5m20s
CI / pwsh (push) Successful in 1m53s
Release / release (push) Successful in 37s
feat: INSTALL.md held to the installation instructions - prerequisites lists generated from the manifest, setup questions checked by docs verify (#154)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SnAJ7Z3CpVD3PRbN73QtU2

Files changed:
- CHANGES.md
- INSTALL.md
- VERSION
- instructions/dev/doc-pull-through.md
- instructions/dev/stack-close/SKILL.md
- instructions/setup-instance.md
- tools/CONTRACT.md
- tools/README.md
- tools/chemenu/cli_contract.py
- tools/chemenu/commands/docs_verify.py
- tools/chemenu/install_doc.py
- tools/chemenu/tests/test_install_doc.py
2026-10-02 07:47:39 +02:00

10 KiB

name, description
name description
stack-close Closes out a stack-dev work package after its publish has landed - rewrites the issue body to its final state, checks for docs/ staleness, and names which model ran which phase of the session. Use right after a stack-dev session's tools/wikitool publish succeeds, or when resuming a package that was published but never closed.

Stack Close

Purpose: Carry out the unchecked closing phase of a stack-development work package, as its own skill rather than a break stack-dev has to remember to ask for mid-flow.

Trigger: A stack-dev session's tools/wikitool publish just succeeded - stack-dev ends there and hands off here rather than continuing into this phase in the same breath. Also: publish printed its stack-machinery note ("this publish touched stack machinery...") and nothing has closed the work package it belongs to yet; or a package was published in an earlier session and never went through this skill (the gap this split exists to make impossible to skip past silently - see instructions/dev/issue-tracking.md's note that a closed body is the version everyone reads afterwards and nobody revisits).

This directory is dev-only. Same boundary as stack-dev (its own instructions/dev/stack-dev/SKILL.md has the full reasoning) - dist export prunes instructions/dev/ wholesale, so this skill never reaches a distributed instance.

Why this is a separate skill, not stack-dev's step 6

The two phases around the mechanical middle of a stack-dev session have no mechanical guard at all - pytest, docs verify and instructions verify 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 second unchecked stretch - as a prose break inside stack-dev's own step 6 - 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. Splitting the phase into its own skill does not add a check either - wikitool still does not know this tracker exists and must not learn (see instructions/dev/issue-tracking.md § What no tool checks) - but it removes the thing that was actually failing: the closing procedure is no longer sitting in the session's context as a next step to run past - it exists only inside a skill someone has to invoke.

Be precise about what that does and does not buy, because the honest version is weaker than "now it cannot be skipped". What did not change is the trigger: stack-dev's "invoke it now" is still a sentence, and publish's stack-machinery note is deliberately generic enough not to name this skill at all. Two of the three links in that chain remain self-discipline. The split narrows the failure, it does not close it - treat a session that reaches this text as the mechanism having worked this time, not as proof that it always will.

See Gitea #47 for the full incident history and the rejected alternative (a model-switched subagent - not buildable in Claude Code, where a fork inherits the parent's model and a fresh subagent starts without the session's context).

Steps

  1. Offer the model switch back up, once, and keep working either way. A model of the message, not a script to quote: say it in the instance's KB language, per AGENTS.md § File naming.

    From here on no mechanical check applies - nothing verifies the issue body, docs/ staleness, or the changelog prose. If you want to switch back to Opus, now is the moment.

    Never block on the answer. The change is already published; a session that stops here leaves exactly the state this skill exists to prevent.

  2. Rewrite the issue body to its final state, then close. The test is 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
    • 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

    Then one short comment naming what changed against the previous state, and nothing else - instructions/dev/issue-tracking.md steps 2-3 and 7 have the full shape; this is that procedure, run at the point this skill exists to guarantee it actually gets run.

    Close only once CI on the published commit is green, and wait for it this way. The push-triggered runs take about 4 minutes; a push that moved VERSION to a suffix-free release adds about 1 minute for the release job. So:

    • Read the runs for the published commit's SHA through the authenticated Gitea connection ENVIRONMENT.md lists (the Gitea MCP's actions_run_read, list_runs), right after publish, to get their ids. Never anonymously via curl: Gitea answers the Actions API with 401 token is required even for this public repo.
    • Check again after about 4 minutes (5 with a release job), then once a minute.
    • Give up after 15 minutes and hand the open runs to the user by id and link, rather than waiting on.
    • Any shell loop that polls instead must end on the first non-2xx status or missing field and print the raw response. A loop that treats an error as "not finished yet" never ends; that happened in the #139 close-out.

    A red run is not closed over: report it, and the package stays open until it is fixed.

    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. Nothing mechanical catches it, which is why this is a step - and now a whole skill - rather than a habit. #44 and #45 both closed exactly this way on the old, single-skill shape, 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 <stage>/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-dev 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. This phase runs after stack-dev step 4 has already bumped the version, and the documents it touches are frequently the ones CI's version gate watches - types/, instructions/, tools/, AGENTS.md, any <stage>/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 commit - it only advances the running candidate's counter - rather than discovering it from a red run after the issue is already closed.

  4. Name which model ran which phase - not only this one. This is the handover in full, not a note about the tail alone: state the model for the design/version-part/boundary-judgment phase (stack-dev step 3), for the mechanical middle (code, tests, the version bump), and for this closing phase - all three, even when they are all the same model. A handover that only flags a cheap-model closing phase stays silent exactly when the earlier, equally unchecked design phase also ran cheap and nobody offered the switch back then either; naming all three every time is what keeps that omission from being the quiet default.

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 landed - not after every individual publish. A package still open across sessions keeps its body current per instructions/dev/issue-tracking.md step 2 in the meantime; that is maintenance, not closing.
  • 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." The handover in step 4 names the earlier phases from the historical record (the issue's comments, CHANGES.md) rather than from memory.
  • Nothing to close - the session's own exploration, no publish happened? This skill does not apply; there is no package to rewrite a body for.

Scope

Follows a stack-dev session's publish. 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.