ref-diagnosis-time-caslisted
Install: claude install-skill natb1/commons.systems
# Diagnosis-Time Compare-and-Swap
## When this applies
The rule is stated by shape, not by caller class: any caller that makes a
decision from a read of a node and later writes that node must capture the
blob at the deciding read and pin it through `--base`. It does not matter
whether the gap is a human interview or a loop over subprocess calls — what
matters is whether a decision was made from a read that a later write could
silently invalidate.
Canonical case: a batched office-hours drain diagnoses several parked nodes,
then interviews the human author about each proposed disposition before
executing any of them — minutes can pass. Without a pin, a fleet write landing
during that interview window would be silently absorbed by park-node's /
clear-park's own execution-time self-refresh of origin/main, including one
that changes what the human should have decided. This is the widest instance
of the shape, not the only one.
Worked example of a narrower instance: `dispatch-tick`'s `frozen_session_sweep`
and `terminal_without_disposition_sweep`
(`.claude/skills/dispatch-propagate/scripts/lib-frozen-session-park.sh`) fetch
`origin/main` once per sweep, then loop over N candidates, each candidate's
already-parked guard read served from that single fetch, each candidate's
`park-node` call bounded by a 120s timeout over a 60s landing-lock wait.
Observed windows were not "a handful of subprocesses": 351s, 441s, and 809s.
`park-node`'s own fresh `origin/main` re-read is not the gua