---
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:

```bash
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`:

```bash
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 1b -- PULL the inner clones up to date at close (added 2026-08-03, operator-directed)

**A lagging clone must not merely be REPORTED -- bring it into sync.** After the durability
triad confirms this host is pushed, `git pull` every git-backed execution-host clone so all
working locations are at the same HEAD for the next session. **The next session may be a NEW
OPERATOR at a different working location; sync parity is what lets them resume without
re-deriving which clone is authoritative.** Operator, verbatim (2026-08-03): *"Add an inner
space task to the savegame to complete a pull to bring inner clones up to date at the end of
sessions. This will make sure that there is sync parody between working locations for next
session since a new session may be a new operator."*

```bash
# every git-backed inner clone -- discover, do not hardcode the path (D-110)
ssh voffice1 "cd \"\$REPO\" && git pull --ff-only" && \
  echo "voffice1 now at: $(ssh voffice1 "cd \"\$REPO\" && git rev-parse --short HEAD")"
```

- **Fast-forward ONLY** (`--ff-only`). An inner clone should never hold divergent local
  commits; if `--ff-only` refuses, that clone has uncommitted or divergent work -- STOP, do
  not force, and surface it (it may be work that itself needs pushing).
- **The dc0/dc1 racks are NOT git clones** -- they carry `~/repo-stage/` with no `.git`. Do
  not `git pull` them; RE-STAGE any drifted tracked file (`scp` + sha256-verify) as the
  parent skill's D-138 note requires. A pull and a re-stage are different operations for
  different host types; use the right one.
- This runs at CLOSE, after this host is pushed, so the inner clones pull the session's own
  final commit. Report each clone's resulting HEAD in the summary -- "synced" is a claim that
  gets quoted, not assumed.

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

```bash
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:

```bash
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.

```bash
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.
