---
key: session.shared-checkout-refresh
title: 2026-07-21 — Session end fast-forwards the shared checkout; a stale tree serves stale FILES (#541)
status: active
since: '2026-07-21'
supersedes: none
superseded-by: none
rule: Session end runs `scripts/refresh-shared-checkout.sh`, which fast-forwards `/Users/timothy/ersatztv` to `origin/main` (and reinstalls `web/node_modules` when the lockfile moved), refusing to touch anything unless that tree is on a clean, non-ahead `main`.
signals: 'shared checkout, stale kickoff paste, `/Users/timothy/ersatztv`, session-end protocol, H13 · paths: `scripts/refresh-shared-checkout.sh`, `docs/handoffs/chicorytv-issue-queue.md` · issues: #541, #520, #311, #312'
mechanics: '`docs/handoffs/chicorytv-issue-queue.md` → session-end step 6 + the shared-tree lore bullet'
---

**The existing rule had a hole, and it is a hole no rule can close.** The standing guidance — never
commit in the shared tree, never read its `HEAD`/`git log`/`git status` as truth about `main` — is
written entirely around a session **reading git state**. On 2026-07-21 the trap arrived as a **file**:
the kickoff prompt was pasted out of that tree while it was 81 commits behind, and the handoff doc it
carried still described the queue protocol #520 had retired the previous day (read tracker #237, which
`main` now says must *not* be read for queue state). No `git` command touched that tree all session, so
no discipline check could have fired. Selection happened to go through `scripts/select-queue.sh`, which
is why nothing broke — routing luck, not a control.

**So the fix removes the stale condition rather than adding a check**, which is what the shared-tree
lore bullet already prescribed for its first two failure modes: *"a check does not stay true."*

**The script is deliberately timid, because the tree is shared.** It refuses — loudly, exit 0,
changing nothing — when the tree is not on `main`, is dirty, has local commits, or is mid-rebase or
mid-merge. It never switches branches, never stashes, never discards. A refusal is a normal outcome,
not a failure, because the common reason for one is that another session is legitimately mid-flight.

**Two details that testing forced.** The first version used `npm install`, which **rewrote
`package-lock.json`** and left the shared tree dirty — the exact state the next run refuses on, so the
tool would have disabled itself after one use. It uses `npm ci`, which installs strictly from the
lockfile and never writes it. And it asserts the tree is clean at exit, reporting loudly if not:
leaving the shared tree dirty is the one outcome that would make this script a net negative.
