commit · diff

git:20261019.e93ae54 to git:20261022.73da425

10 added, 9 removed. Audit A to A.

---
name: commit
description: "Commit the current session's changes only, gateway-inline. Session-isolated (never -A, never stages into the shared index; what commits is read back against the session list), doc-sync-gated. The gateway runs the commit inline — it already holds the diff, session file list, and change intent; on a mechanical gate hit it judges doc-sync warm in its own context (the cold doc-sync-scan agent dispatches only past the scope ceiling), and the premise-closure judge dispatches on a product-anchor hit. Conventional message, commits directly, offers push on explicit confirmation. Bundled with super-bootstrap — encodes the harness commit rules."
tags: [commit, git, session, doc-sync]
---
# Commit — Session-Isolated, Doc-Sync-Gated (gateway-inline)
Commits the changes this Claude session produced, leaving prior uncommitted work alone. The gateway runs the flow inline — it holds the session's diff, file list, and change intent, so the mechanics carry no closure a fresh container would hold. The doc-sync judgment runs warm in that same context: the diff, the change intent, and the session's read docs are the judgment's inputs, and the gateway already holds them all. Dispatch survives as the scope-overload valve — a scan scope past the ceiling moves whole to the cold `doc-sync-scan` agent rather than being truncated inline.
## Execution (gateway-inline)
1. **Session file list + grain** — from this conversation, the files this session edited/wrote. This is the session-isolation ground truth; a file you don't remember touching stays off it. Each listed path takes a grain, read off `git diff HEAD -- <path>` — base HEAD, never the shared index, which can hold another writer's stale entry: **file grain** when every hunk there is this session's edit (the normal case; a new file is file grain, recorded now with `git add -N <path>` — intent-to-add, so every later `git diff HEAD` here sees it and another writer's plain commit does not take it); **hunk grain** when the file also holds another writer's uncommitted edits. §5 commits each grain in its own lane; neither stages into the shared index.
2. **Gather state** — `git status`, `git diff HEAD`, `git diff --staged`, `git log --oneline -10` (recent style). A staged path outside the §1 list is another writer's state — so is a staged change or deletion on a path the worktree holds at HEAD (an entry an out-of-door commit left stale). Early warning only: name it with the commit; §5's lanes commit past it and leave it as it is — they refresh only the session paths' own shared-index entries. Another writer's staged change on a session path → stop and surface: committing would drop their staging. Unstage or restage another writer's entry only on the user's say-so.
3. **Doc-sync grep-gate** — mechanical, no judgment:
- **Deferred mode — check first** (autorun-worktree isolated commit): doc-sync belongs to the merge boundary — skip all of §3, go to §5 (§5's staged-tree verify is skipped too).
- **Frozen-provenance exemption — card lifecycle, history dimension:** every changed path inside `docs/work/` (card-thread appends, card deletions), plus every changed `docs/outward/OUT-*.md` (thread appends, entry deletions) → skip the gate, go to the link check below then §5. Both are append-only threads, self-contained; cross-card ID mentions are frozen provenance, not behavior narration — so `hits` and `refs` leave every `docs/work/` card thread and every `docs/outward/OUT-*.md` thread out of the scan scope too, whatever term they name or anchor they cite; each folder's standing `README.md` narrates its thread contract and stays in both lanes. A doc whose leading frontmatter declares `dimension: history` is frozen provenance the same way — a change to it yields no term (`terms` skips it), `hits` and `refs` leave it out of the scan scope, and the link check below still covers it. Mixed diff → run the gate on the other paths only.
- **Premise lane — product-anchor paths:** the diff touches the product anchor (`docs/overview.md` § Problem / § User, or a dedicated product doc where the repo splits one out) and those sections' post-image carries a premise — body past the skeleton's `{…}` placeholder line, or, for a dedicated product doc with no shipped skeleton, prose beyond a scaffold stub in its Problem / User-equivalent sections → route the anchor portion through §3b — its closure set is the whole doc surface, so it already covers everything this gate would reach for the anchor; the rest of the diff continues through this gate. Sections still on the placeholder revise no premise → the anchor path stays in this gate like any other changed doc.
- **Terms → grep hits — one script call each:** `<skill-base>/assets/doc-links.sh terms <changed paths…>` prints the gate's terms; scaffolding paths (bench, tests, fixtures, goldens, session ledgers), asset extensions, generic basenames, terms under four characters, and the machine state harness-bootstrap seeds under `.claude/` (the runway receipt, `templates/`) yield none. Nothing printed → the grep lane is empty, skip to the citer lookup. Otherwise `<skill-base>/assets/doc-links.sh hits <terms…> | grep -vxF "$(printf '%s\n' <changed files>)"` prints the doc-surface files mentioning a term in **code shape** — a whole word inside backticks, or a path segment — so bare prose stays out. Harness-seeded hub stems (`overview`, `techstack`, `decisions`, the runway receipt, the worktree template) count only as a bare token inside backticks: a path mention of a hub doc is a citation the anchored citer lane already reaches, not a narration. A Godot text asset (`.tscn`, `.tres`) runs the inverse: `terms` keeps its extension (`levels/Ending.tscn` → `Ending.tscn`), and `hits` counts that term only as a path segment (`levels/Ending.tscn`, `Ending.tscn`), never as a bare backticked `Ending` — a scene or resource basename doubles as domain vocabulary. Pass the printed terms to `hits` verbatim, extension included. Hit files join the scan scope; the agent judges them cold (§4). `hits` walks the markdown surface — a manifest description field the diff changes is read here directly.
- **Link-hit (reverse citers) — mechanical, beside the grep:** for each changed `docs/**` / root `README.md` / plugin-README (`plugins/*/README.md`) path, take its post-image hunk ranges from `git diff HEAD -U0 -- <path>` (`@@ -a,b +c,d @@` → `+c,d`) and run `<skill-base>/assets/doc-links.sh anchors <path> <ranges…>`. `(top)` among the slugs means whole-file grain → `<skill-base>/assets/doc-links.sh refs <path>`; otherwise `refs <path>#<slug>…` in one call of the same script, which prints the union. Exclude the changed files themselves. Every file returned is a declared citer of the changed truth — collect them as the **citer read-set**.
- **Self-scope (changed docs) — mechanical, beside the citer lookup:** `<skill-base>/assets/doc-links.sh self <changed paths…>` prints the changed paths that are doc-surface files in their own right — a deleted path, an off-surface path, and frozen provenance (card threads, `docs/outward/OUT-*.md`, `dimension: history`) all drop out. Every path printed joins the scan scope as its own scope doc: §4 reads it whole and holds its **unchanged** sections against the diff's claims, which is where a same-commit contradiction with the file's pre-existing prose sits.
- **Link-target extraction (forward links) — mechanical, beside the reverse lookup:** from the diff's added lines, extract every markdown link target (`grep -oE '\]\([^)]+\.md[^)]*\)'` over `+` lines), resolve each relative to its linking file. Each target is a doc the new prose claims agreement with — add the target files to the scan scope.
- **Scope ceiling — count before judging:** the scan scope is citers ∪ grep hits ∪ link-targets ∪ changed docs. At or under **8** docs → the gateway judges the scope warm-inline (§4). Above 8 → the scope moves whole to the cold `doc-sync-scan` dispatch (§4's fallback lane) — never truncated to fit inline.
- **Any grep hit OR any citer OR any link-target OR any changed doc → run the doc-sync judgment (§4) over the scan scope — citer read-set + grep-hit files + link-target files + the changed docs themselves.**
- **All four lanes empty → the diff narrates nothing; go to §5.** The self lane makes this the narrow branch it reads as: a diff that touched no doc-surface file outside the frozen-provenance exemptions — an asset, code, or exempt-thread diff.
- **Link integrity (every non-deferred commit, exemption included):** run `<skill-base>/assets/doc-links.sh check` from the repo root — `<skill-base>` is the `Base directory for this skill:` path surfaced at invocation; zero model tokens. Broken links (path or anchor) surface to the user with the commit: fix or explicitly acknowledge before landing; never silently skip. One class is exempt by construction — the consumed-card-link skip: a link from a card thread (`docs/work/{BUG,DEBT,GAP}-*.md`) to an absent card ID is consumed provenance — the sibling resolved — so `check` skips it uncounted, while every other target from a card, and any dangling card link from a non-card doc, stays strict.
- **Model-pin integrity (every non-deferred commit):** run `<skill-base>/assets/doc-links.sh pins` from the repo root; zero model tokens. Reads each agent file's frontmatter `model:` and reports doc-surface lines whose restated tier disagrees with the agent named inside an inline code span — `<doc>:<lineno>` + claimed tokens + actual tier + source path. Deliberately narrow, so the per-commit gate stays quiet: a line resolving to no agent or to several is skipped, and any one agreeing tier token clears it. Whole-surface by construction: it consults no scan scope, so a doc no enumeration lane reached is covered the same. Frozen provenance is out, as in every other claim lane — a closed-fork row or card thread restates a past tier by design. Stale pins surface to the user with the commit: fix or explicitly acknowledge before landing; never silently skip.
3b. **Premise-closure lane (product-anchor diff)** — a problem/ICP revision changes premise, not behavior; its closure is every doc whose framing leans on the anchor. Enumerate mechanically — `<skill-base>/assets/doc-links.sh closure <anchor-path>` prints the set: the doc surface minus consumables (per-item work files — `docs/work/{BUG,DEBT}-*.md`, `docs/work/TEMPLATE.md`) minus the anchor. Judgment runs only over the enumerated set — dispatch the `premise-closure` agent (`Agent` tool, `subagent_type: "premise-closure"`; prompt = the anchor diff hunks — `git diff HEAD -U0 -- <anchor-path>`, output pasted verbatim into the prompt (the judge has no shell; the pasted lines are its only view of the old premise) — + the anchor path + the enumerated paths, no staleness leans): its sheet (holds / re-frame / dangling per doc + coverage line) returns here; a coverage mismatch or a `no-hunks` line re-dispatches, the latter with the hunks pasted. Resolve with the user before the commit lands — re-frame: update the doc to align / acknowledge still-accurate; dangling: drop / merge / defer. Never silently fix, never silently skip. Then continue §3 on the rest of the diff.
4. **Doc-sync judgment (gate hit)** — warm gateway-inline by default; the cold dispatch is the overload lane. Both lanes run the same procedure — `agents/doc-sync-scan.md` § Scan — and end in the same resolution.
- **Warm-inline (scope ≤ ceiling):** the gateway applies § Scan itself, in its own context. Warm eyes are the point: hold the change intent and the session's reads beside the diff while judging. Every scope doc gets an outcome — a stale candidate (path + what's outdated + hunk) or read-and-confirmed-unchanged; a doc skimmed or skipped is an incomplete gate, not a `clean`.
- **Cold dispatch (scope > ceiling):** `Agent`, `subagent_type: "doc-sync-scan"`; prompt = the diff (`git diff HEAD -- <session paths>`; a hunk-grain path is read against the session's hunks only) + today's date + the scan scope. The agent judges the same procedure in its own window and returns `stale-docs` or `clean`.
- Either lane stays scoped — never a whole-surface re-derivation; whole-surface coverage belongs to `/super-bootstrap:check-docs-consistency`.
- **Stale candidates** → resolve each with the user (update / acknowledge-accurate / skip — never silently fix, never silently skip). Land approved doc edits (inline for bounded prose; dispatch by closure). Resolved docs join the §1 list and take a grain per §1 (a new doc gets `git add -N`).
- **Nothing stale** → proceed.
- 5. **Message + commit** — draft a Conventional Commit (`<type>(<scope>): <subject>`, imperative ≤72 chars, body only when the why isn't in the diff, match `git log` style; one logical change per commit — a diff spanning two unrelated changes splits). Explicit paths only — never `-A` / `.`, never secrets (`.env`, keys), and never stage content into the shared index (§1's intent-to-add excepted): the index is shared across sessions in one checkout, and a plain `git commit` from any of them takes every staged path. Any hunk-grain path puts the whole commit on the hunk lane. Each readback and the verify is its own tool call, and the commit issues only after its result is read.
- - **File grain — `git commit -o -- <session paths>`.** A new file is already intent-to-add from §1, and `-o` commits it. `-o` commits HEAD plus those paths' worktree content, leaves every other shared-index entry as it was, and refreshes the named paths' entries to the new HEAD. **Readback:** `git diff HEAD --name-only -- <session paths>` equals the §1 list — a listed path missing from it carries no change: drop it, or recheck the list. Order: readback → staged-tree verify → stamp → `git commit -o`.
+ 5. **Message + commit** — draft a Conventional Commit (`<type>(<scope>): <subject>`, imperative ≤72 chars, body only when the why isn't in the diff, match `git log` style; one logical change per commit — a diff spanning two unrelated changes splits). Explicit paths only — never `-A` / `.`, never secrets (`.env`, keys), and never stage content into the shared index (§1's intent-to-add excepted): the index is shared across sessions in one checkout, and a plain `git commit` from any of them takes every staged path. Any hunk-grain path puts the whole commit on the hunk lane. Each readback, the verify and the stamp is its own tool call, and the commit issues only after its result is read. Each call runs in a fresh shell, so name every index in its resolved form, written out in each call that uses it — `<priv>` is `"$(git rev-parse --git-dir)/index-<session>"` (a name unique to this session), `<tmpidx>` is `"$(git rev-parse --git-dir)/index-<role>-<session>"` — and carry a value one call reads into the next as a literal.
+ - **File grain — `git commit -o -- <session paths>`.** A new file is already intent-to-add from §1, and `-o` commits it. `-o` commits HEAD plus those paths' worktree content, leaves every other shared-index entry as it was, and refreshes the named paths' entries to the new HEAD. **Readback:** `git diff HEAD --name-only -- <session paths>` equals the §1 list — a listed path missing from it carries no change: drop it, or recheck the list. Order: readback → staged-tree verify → stamp (seam below) → `git commit -o`.
- **Hunk grain — a private index from HEAD.**
- 1. `priv="$(git rev-parse --git-dir)/index-<session>"` (a name unique to this session), `base="$(git rev-parse HEAD)"`, `GIT_INDEX_FILE="$priv" git read-tree HEAD`.
- Any stop in steps 2–5 deletes `$priv` (`rm -f "$priv"`).
- 2. Per hunk-grain path: write `git diff HEAD -- <path>` to a patch file outside the worktree and keep its file header plus this session's **git hunks** whole — delete the rest. A git hunk that holds both writers' edits → **stop and surface** the path and the hunk: never split a hunk, never rebuild lines by hand. `GIT_INDEX_FILE="$priv" git apply --cached <kept patch>`. File-grain paths in the same commit: `GIT_INDEX_FILE="$priv" git add -- <paths>`.
- 3. **Readback** under the private index: `git diff --cached HEAD --name-only` equals the §1 list, and per hunk-grain path `git diff --cached HEAD -- <path>` equals the kept patch line for line outside its `index` and `@@` header lines (the new blob and the dropped hunks shift those). Any difference → stop and surface.
+ 1. Two calls: read `git rev-parse HEAD` and keep its sha as `<base>`, then `GIT_INDEX_FILE=<priv> git read-tree <base>` — the index and step 6's guard share one anchor.
+ Any stop in steps 2–6 deletes the private index (`rm -f <priv>`).
+ 2. Per hunk-grain path: write `git diff HEAD -- <path>` to a patch file outside the worktree and keep its file header plus this session's **git hunks** whole — delete the rest. A git hunk that holds both writers' edits → **stop and surface** the path and the hunk: never split a hunk, never rebuild lines by hand. `GIT_INDEX_FILE=<priv> git apply --cached <kept patch>`. File-grain paths in the same commit: `GIT_INDEX_FILE=<priv> git add -- <paths>`.
+ 3. **Readback** under the private index: `GIT_INDEX_FILE=<priv> git diff --cached HEAD --name-only` equals the §1 list, and per hunk-grain path `GIT_INDEX_FILE=<priv> git diff --cached HEAD -- <path>` equals the kept patch line for line outside its `index` and `@@` header lines (the new blob and the dropped hunks shift those). Any difference → stop and surface.
4. Staged-tree verify (below), before any commit.
- 5. Commit under the private index only while `[ "$(git rev-parse HEAD)" = "$base" ]`, the check and `git commit` chained in one command — HEAD moved → rebuild from step 1 on the new HEAD. After: `git reset -q HEAD -- <committed paths>` on the shared index (index only — the other writer's hunks stay in the worktree), then `rm -f "$priv"`.
- - **Staged-tree verify — declared command, differing tree; between readback and commit in both lanes.** The consumer may declare one in `docs/techstack.md` § Staged-Tree Verify; none declared → skip. Deferred mode → skip: the gateway runs the declared Staged-Tree Verify once on the integrated tree, before base moves (`merge/SKILL.md` § 5b). Otherwise it runs when the tree about to commit differs from the working tree: hunk grain always; file grain when `git status --porcelain` lists any path outside the session list. Materialize that tree into a temp dir outside the worktree — hunk grain: `GIT_INDEX_FILE="$priv" git checkout-index -a --prefix=<tmp>/`; file grain: `tmpidx="$(git rev-parse --git-dir)/index-verify-<session>"`, then `GIT_INDEX_FILE="$tmpidx" git read-tree HEAD`, `GIT_INDEX_FILE="$tmpidx" git add -- <session paths>`, `GIT_INDEX_FILE="$tmpidx" git checkout-index -a --prefix=<tmp>/` — every call names the throwaway index, since a bare `git read-tree` overwrites the shared one. Run the command there, then delete the dir and `rm -f "$tmpidx"`. Failure → stop and surface: a green working tree does not speak for the tree that commits.
- - **Harness-audit stamp seam — where an audit stamp is installed, stamp the set that commits.** File grain: the stamp runs over the session's harness paths, named explicitly, never read from the shared index, right before `git commit -o`. Hunk grain: a stamp that reads the shared index or the worktree sees neither tree this commit makes, so its nudge can re-fire or mis-match on this lane; name that with the commit, never bypass it.
+ 5. Stamp (seam below), where an audit stamp is installed — its own call, before step 6.
+ 6. Commit under the private index only while HEAD is still `<base>`, the check and the commit chained in one command: `[ "$(git rev-parse HEAD)" = "<base>" ] && GIT_INDEX_FILE=<priv> git commit …`, the prefix immediately before `git`. HEAD moved → rebuild from step 1 on the new HEAD. After: `git reset -q HEAD -- <committed paths>` on the shared index (index only — the other writer's hunks stay in the worktree), then `rm -f <priv>`.
+ - **Staged-tree verify — declared command, differing tree; between readback and commit in both lanes.** The consumer may declare one in `docs/techstack.md` § Staged-Tree Verify; none declared → skip. Deferred mode → skip: the gateway runs the declared Staged-Tree Verify once on the integrated tree, before base moves (`merge/SKILL.md` § 5b). Otherwise it runs when the tree about to commit differs from the working tree: hunk grain always; file grain when `git status --porcelain` lists any path outside the session list. Materialize that tree into a temp dir outside the worktree — hunk grain: `GIT_INDEX_FILE=<priv> git checkout-index -a --prefix=<tmp>/`; file grain, with `<tmpidx>` of role `verify`: `GIT_INDEX_FILE=<tmpidx> git read-tree HEAD`, `GIT_INDEX_FILE=<tmpidx> git add -- <session paths>`, `GIT_INDEX_FILE=<tmpidx> git checkout-index -a --prefix=<tmp>/` — every call names the throwaway index, since a bare `git read-tree` overwrites the shared one. Run the command there, then delete the dir and `rm -f <tmpidx>`. Failure → stop and surface: a green working tree does not speak for the tree that commits.
+ - **Harness-audit stamp seam — where an audit stamp is installed, stamp the set that commits.** Installed = `<hook>`, `~/.claude/hooks/harness-audit-pretool.sh`, exists; absent → skip the seam. It also needs an `audit-harness-edits` pass over these paths' current content, whose one-line verdict is `<verdict>`; no audit on record → skip the seam and name that with the commit. The stamp call itself (the verdict line, its exit codes) is `audit-harness-edits` step 5's; this door fixes its two lanes' forms, and its file-grain form stands in for step 5's `git add` first, since this door stages nothing into the shared index. File grain, with `<tmpidx>` of role `stamp`, in one call: `GIT_INDEX_FILE=<tmpidx> git read-tree HEAD && GIT_INDEX_FILE=<tmpidx> bash <hook> --stamp "<verdict>" $(git diff HEAD --name-only -- <session paths>); rc=$?; rm -f <tmpidx>; exit $rc` — an index from HEAD stages no session path, so the stamp hashes each path's worktree content, which `-o` commits. Write that commit as `git commit -o … -- <session paths>` with every path literal, no `cd` in the command, and an existing HEAD; any other form makes the gate judge the whole dirty tree. Hunk grain, step 5: `GIT_INDEX_FILE=<priv> bash <hook> --stamp "<verdict>" $(GIT_INDEX_FILE=<priv> git diff --cached --name-only)`; step 6's prefix lets the gate read the same index. Done when the `$(…)` is the lane's readback command verbatim and the stamp exits 0, or exits 3 (`nothing stamped`) on a set with no harness path; any other exit → stop and surface.
- Commit with HEREDOC formatting; after, `git show --name-only --format= HEAD` equals the session list — prior dirty state is sacred, so a clean tree is not the check. Pre-commit hooks run; on failure fix the cause, never bypass. Always a new commit — amend only if asked.
6. **Push (where a push surface exists)** — probe first, ask second; the probe is a fact the gateway reads itself. `git remote` prints nothing → no push surface: §7's handoff line is the next and only output. A remote but no upstream for the branch (`git rev-parse --abbrev-ref @{u}` errors) → say so in one line and ask once: **"Set upstream and push (`git push -u <remote> <branch>`)? (y / skip)"** — `<remote>` is the sole remote, or the one the user names when several exist. Remote + upstream → present branch → upstream, commits ahead; ask **"Push these now? (y / skip)"**. Push on explicit yes only; skip on silence or decline. Never force, never unannounced. Invoked by `/super-bootstrap:session-close` → no ask: the close pick's push answer is the answer.
7. **Cycle handoff** — one line from cycle facts (any `docs/work/{BUG,DEBT,GAP}-*.md` present; a card whose latest Plan block has steps the latest Progress doesn't report done = in-flight). Don't expand into a status table — `/super-bootstrap:needs-me` recommends, this line only hands off (skipped when invoked by `/super-bootstrap:session-close` — its Output is the terminal output):
| Cycle facts | Handoff one-liner |
|---|---|
| No open cards | `Cycle complete. Safe to /clear. Next session: /super-bootstrap:needs-me or /super-bootstrap:autorun.` |
| In-flight card (Plan steps not all reported done in latest Progress) | `Cycle complete. {ID} still in-flight — /clear then pick it up by ID or via /super-bootstrap:needs-me.` |
| Open cards, none in-flight | `Cycle complete. Open cards, none in-flight — /clear then /super-bootstrap:needs-me (needs you) or /super-bootstrap:autorun (does not).` |
## Rules
- **Gateway-inline, judgment included; two dispatch valves, each on its own gate.** The gateway holds the diff, session list, intent, and session reads → mechanics and the doc-sync judgment stay inline (the judgment's inputs are exactly what the gateway holds). The cold doc-sync scan dispatches past the scope ceiling; the premise-closure judge dispatches on a product-anchor hit.
- **Grep-gate is mechanical.** Term extraction is path-structure only, never a judgment about which identifiers matter — a judgment gate gets omitted. Any lane hit triggers the doc-sync judgment (§4); conservative by design. A diff that touches no doc-surface file and hits no lane — a pure asset/binary diff with no narrated path — is the skippable class.
- **Session-isolated.** The session list decides; prior dirty state is sacred. Explicit paths, never `-A`, never a session path staged in the shared index (intent-to-add excepted) — file grain commits by pathspec (`-o`), hunk grain through a private index built from HEAD — and what commits is read back against that list before every commit, so another writer's staged or stale entries neither ride in nor get reverted.
- **Doc-sync round-trip, never bypass** — a `stale-docs` return goes through the user before commit.
- **Whole-diff-once.** Doc-sync runs at the integration boundary, on the whole diff, once. An autorun worktree defers it to merge; an implementer never owns doc-sync — a partial-slice view gives false confidence.
- **Push asks only where a push surface exists, and only on explicit yes** — §6's probe decides whether the question fires; committed work is safe locally either way.