name: savegame
The end-of-session procedure for THIS repo. It does two jobs that are easy to confuse:
/clear loses nothing.The sweep is the half that gets skipped, and it is the half that matters. Across the sessions that ran it, the items marked FIRST SURFACE -- existing only in the transcript -- were consistently the highest-consequence ones. A bookend without a sweep is a tidy record of work whose findings evaporated.
docs/CURRENT-STATE.md. The ledger records session NARRATIVE; a ledger line touching status is a pointer, never a claim (GA-R4 r5).A session that ends unpushed is not durable, and this is the one failure a clear makes unrecoverable. Check all three, not just the first:
git status --porcelain | wc -l # want 0
git log @{u}..HEAD --oneline | wc -l # want 0 (unpushed)
Then every execution host's clone, not just this one. The 2026-07-27 stale-clone hazard is why this is checked rather than assumed, and on 2026-07-31 voffice1 was found 6 commits behind at close.
Never hardcode the repo's own name or path -- it has been renamed/forked once already (D-110) and will again. Discover the remote-side clone the same way the parent skill does, from a $REPO set once per session or from git remote -v:
ssh voffice1 "cd \"\$REPO\" && git fetch -q; git rev-list --count HEAD..@{u}"
Under D-138 the DC client hosts matter too -- the dc0 rack carries a ~/repo-stage/ copy of bundle.yaml + overlays with NO git at all. A staged copy that has drifted from the repo is a silent deploy hazard: compare digests, do not assume.
A lagging clone is not a loss (the remote has the work) but it IS a hazard and belongs in the summary.
bash scripts/repo-lint.sh # expect 0 fail bash scripts/run-tests-all.sh # expect ALL GREEN (n harnesses) bash scripts/ledger-scan.sh # open decisions, SEC count, next-free numbers
Quote the ACTUAL numbers into the summary. If a gate is red, the summary says so plainly with the failing line -- a close that hides a red gate is worse than no close. Note run-tests-all.sh --record-manifest WRITES the manifest; never pass it here.
Reconcile ledger-scan against what the session CLAIMED. If the session opened SEC rows or assigned D-/DOCFIX-/BUNDLEFIX numbers, the scan's next-free values must have moved accordingly. A mismatch means a number was assigned and not recorded, or recorded and not assigned.
Method, ruled 2026-07-31 ("Model reads the session, then greps each candidate"):
(a) Enumerate. Read back over the whole session and list EVERY:
Do not filter for importance yet. The 2026-07-30 sweep's most valuable item was a permission-rule text that looked like housekeeping.
(b) Prove each one, mechanically. For every candidate, grep the repo for it:
grep -rn "<distinctive phrase>" docs/CURRENT-STATE.md docs/changelog-*.md docs/ runbooks/ scripts/
An item with a hit is ALREADY ON SURFACE -- record where. An item with no hit is FIRST SURFACE and would have been lost. This grep step is not optional: an unverified "that's already recorded" is precisely the claim that has been wrong before.
(c) Write it to docs/audit/queued-findings-<date>-<label>.txt, following the established format (see any docs/audit/queued-findings-*.txt). Each item states where it already lives, or that this file is its first surface. Lead the file with the FIRST SURFACE items.
(d) Always sweep these five, because they are structurally invisible:
.claude/settings.local.json permission rules are lost on any rebuild -- record their VERBATIM text. Same for any gitignored artifact the session created or relied on.run-logged.sh opens an interactive script(1) subshell and is unusable non-interactively; the classifier also refuses many wrapped forms. If the log under-records the window, SAY SO on a surface. A log that looks complete and is not is worse than one declaring its gap.Read ~/.claude/projects/<sanitized-cwd>/memory/ IN FULL against GA-R7:
Update MEMORY.md's one-line index entry for anything changed.
This repo's culture records own-mistakes explicitly, and they are the first thing a clear destroys. The summary carries an OWNED line: wrong claims made and corrected, instrument errors, work batched that should have been gated, anything waved through. State them plainly and move on -- no self-flagellation, but no quiet omission either.
Append to docs/session-ledger.md:
Then enforce rule 3's 300-line cap, which binds AT CLOSE: after writing the summary, rotate the OLDEST closed-session summaries out until the file is under 300 lines. An OPEN session's in-flight section is never rotated but counts toward the cap.
wc -l < docs/session-ledger.md # must end under 300
Known live condition (2026-07-31): the ledger sits at ~295 lines. The next close breaches the cap, and rotation appears not to have run since the one-time Phase-5 rotation. Do not skip this step because it has historically been a no-op.
Session bodies (changelogs) do NOT move at session close. They stay in docs/ and the ledger points at them; the GA-R2 stage consolidation moves them to docs/archive/changelogs/ at STAGE close. (Ruled 2026-07-31, operator: "Follow practice: archive at stage close (Recommended)".)
KNOWN DIVERGENCE, DOCFIX OWED: GA-R4 rule 2's literal text says the body moves "in the same close commit". Practice does it at stage close -- 114 archived files, newest
20260727, with the current stage's working set still indocs/. The ruling text needs a DOCFIX to match the ruled practice. Logged, not fixed here.
Check whether the ledger holds an in-flight section with no close bookend for a session that verifiably ended. If so, close it POST-HOC: a bounded summary marked closed post-hoc by <this session>; original did not bookend.
Post-hoc summaries carry no status weight -- they record that the session happened, never that its work is durable.
Show the operator:
git status / diff to be committed.Then STOP and wait. Do not commit. Do not push.
Once the operator approves, commit everything in ONE commit (the ledger summary, the sweep file, any CURRENT-STATE update, the memory index) and push. A session ending without its bookend PUSHED is treated as NOT durable by the next session.
It is not a stage close. A stage close is a superset and is governed by GA-R6: a named executable check whose captured output the closing commit cites, the GA-R2 consolidation commit, the memory review, a MERGE of the stage branch to main (merge commit, never squash, operator-gated), branch retirement, a sweep of the openstack-cloud-ops skill itself, and regeneration of the dated Chat snapshot. If the session also closes a stage, do all of that too -- see openstack-cloud-ops/SKILL.md "At STAGE CLOSE".
It does not fix things. Everything it finds is logged. The circuit-breaker still applies: if you have been fixing records to match records for more than one cycle without touching the deliverable, STOP and report to the operator.