Newer
Older
openstack-caracal-dc-dc / .claude / skills / savegame / SKILL.md

name: savegame

description: "Save the session: the GA-R4 bookend (bounded ledger summary, ledger rotation, memory review) PLUS a full transcript sweep that proves nothing raised in-session would be lost on a context clear. Use at the end of any working session, before /clear, before handing off, or whenever the operator says savegame / save / close out / bookend / wrap up / are we safe to clear. Also use when a session is about to be compacted, and when you find a PRIOR session that ended with no bookend (GA-R4 rule 7 post-hoc close). Repo-specific: it encodes this repository's GA-R1..R7 rules, gate names and paths."

savegame

The end-of-session procedure for THIS repo. It does two jobs that are easy to confuse:

  1. The GA-R4 BOOKEND -- a bounded, durable record of what the session did.
  2. THE SWEEP -- proof that every finding, decision and measurement raised in the session already lives on a repo surface, so a /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.

Hard rules this skill does NOT relax

  • It PREPARES; it does not commit. Run every gate and write every file, then present ONE reviewable diff and STOP. The operator commits. (Ruled 2026-07-31, operator: "Prepare everything, stop before commit (Recommended)".)
  • Hard rule 1 still applies: findings are LOGGED, NOT EXECUTED. If the sweep finds a defect, it goes in the sweep file. It does not get fixed here.
  • Hard rule 2 still applies: every number in the summary is QUOTED from captured output. Never from memory, never from another document's prose (GA-R1 rule 2).
  • Status claims go ONLY in docs/CURRENT-STATE.md. The ledger records session NARRATIVE; a ledger line touching status is a pointer, never a claim (GA-R4 r5).

Step 1 -- Durability triad (do this FIRST; it is the only irreversible risk)

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.

Step 2 -- Gates, all of them, and quote the numbers

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.

Step 3 -- THE SWEEP (the half that gets skipped)

Method, ruled 2026-07-31 ("Model reads the session, then greps each candidate"):

(a) Enumerate. Read back over the whole session and list EVERY:

  • finding, defect or surprise -- including ones already fixed;
  • measurement that contradicts a standing document;
  • decision or operator ruling, with its exact utterance;
  • trap, workaround or environment fact discovered;
  • own-mistake (see Step 5);
  • thing deliberately NOT done, and why.

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:

  1. Gitignored state. .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.
  2. Dangling references. Every path the session's commits cite must resolve.
  3. Ruling fidelity. Every GA-R5 ruling has its EXACT utterance recorded, dated and pushed -- not paraphrased. A paraphrased ruling rules nothing.
  4. As-executed log gaps. 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.
  5. Contradiction detector. Anything the session MEASURED that disagrees with a standing doc. Measurement wins (GA-R1 C2) and the doc owes a correction -- e.g. preflight quoting "50 apps / 97 relations" against a measured 56/108.

Step 4 -- GA-R7 memory review

Read ~/.claude/projects/<sanitized-cwd>/memory/ IN FULL against GA-R7:

  • Memory records OBSERVATIONS and CONVENTIONS only. Never operator policy, priorities or postures.
  • Any entry claiming operator intent is PROPOSED until confirmed verbatim -- remove on discovery and register it as a finding.
  • Durable observations GRADUATE to their repo surface. Memory is never the only copy of anything that matters.
  • Don't duplicate what the repo already records.

Update MEMORY.md's one-line index entry for anything changed.

Step 5 -- The "Owned" section

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.

Step 6 -- The bounded ledger summary + rotation

Append to docs/session-ledger.md:

  • HARD CAP 15 LINES for the closed session (GA-R4 rule 1). This is a cap, not a target.
  • Session NARRATIVE only. Status lives in CURRENT-STATE.
  • End with: what is NEXT, the changelog body path, and "Status ONLY in CURRENT-STATE.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 in docs/. The ruling text needs a DOCFIX to match the ruled practice. Logged, not fixed here.

Step 7 -- Orphaned prior sessions (GA-R4 rule 7)

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.

Step 8 -- Present, and STOP

Show the operator:

  • the durability triad result (including any lagging clone);
  • every gate's quoted numbers;
  • the sweep file, with FIRST SURFACE items called out first;
  • the memory review outcome;
  • the proposed ledger summary and what rotation moved;
  • the complete 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.


What this skill is NOT

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.