Q3e (order 20260913T051659Z-717911204-from-.claude), after Q3d. Live incident 13.09
(operator's own run): `release-plugin.mjs repo-mailbox --version 0.34.0 --create-tag
--write --commit --push` tagged+pushed v0.34.0, wrote the catalog ref + README label,
then crashed with a raw Node stacktrace because check-versions found the catalog's own
stat line stale against the plugin's NEW badge (868 vs 927). Neither --commit nor
--push of the catalog ran; the push token was correctly consumed (Q3c). Operator fixed
the line and committed/pushed manually.
D1 — the ordinary pre-flight (applyRelease -> check-versions) only ever inspects the
OLD ref, so a stat-line drift the release itself is about to expose slipped straight
through it into a pushed tag + a written, uncommitted catalog. New `preflightStatMismatches`
compares the catalog's stat line against what the release is about to make current (the
target ref's badge if that tag already exists, else the plugin's worktree README — exactly
what --create-tag is about to tag), BEFORE any tag or write. Extracted the shared
mismatch logic into check-versions.mjs as `statMismatchFindings` (pure refactor,
classifyPlugin's own behavior unchanged) so both the post-hoc gate and this pre-release
check use one rule.
D2 — the post-write confirmation was a bare execFileSync, which throws on a non-zero
exit. `reportPostWriteCheck` catches any failure (a real ERROR, or the subprocess
dying) and reports exactly what is done (tag pushed y/n, files written) and what
remains (commit/push), returning an exit code instead of an unhandled exception.
No version bump, no tag, no push, no CLAUDE.md wording this session.
Verification:
- node --test scripts/release-plugin.test.mjs: 41/41 (Q3d) -> 50/50 (9 new: 3
preflightStatMismatches unit + 2 real-git D1 integration + 3 reportPostWriteCheck
unit + 1 real-git D2 integration)
- node --test scripts/*.test.mjs: 158/158 (Q3d) -> 167/167
- node scripts/check-versions.mjs: 0 ERROR (1 known WARN: claude-design, unrelated)
- Mutation evidence (D1): commented out the new pre-flight call in runRelease ->
exactly the new "D1 (Q3e, real git)" test went red (49 pass, 1 fail), all others
stayed green; restored -> 50/50 again.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>