You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Six hooks (go-format, ruff-format, biome-format, bash-format, powershell-format, eol-normalizer) hand-write the same four-step protocol: snapshot to mktemp, cmp -s after the formatter runs, name the rewrite on the user channel, release the snapshot on every exit arm. The blocks are near-identical, differing only in variable prefix (_fmt_before, _go_before, _ps_before, _ruff_before, _biome_before, _eol_tmp).
Because the protocol lives in each plugin rather than behind one interface, the same defect recurs plugin by plugin. The rollout itself landed one plugin at a time (f5b8a3d bash, b3e9735 biome, 1b10069 powershell, 3c9351d eol-normalizer, b1b1c22 the rest), then #3401 (a7f9537) fixed powershell's leaked snapshot and undisclosed rewrite, while the identical leak sat unrepaired next door in go-format. Both remaining defect families were verified live on 2026-08-27 and are filed as #3405 (go-format snapshot leak on both error arms) and #3406 (ruff/biome/bash emitting two JSON documents on a rewrite-plus-findings run, against the single-document invariant documented at lib/hook-utils.sh:75-78).
Deletion test: concentrates. A future maintainer would rebuild this module substantially the same way; the protocol (snapshot lifetime, disclosure wording, single-document stdout composition) is exactly the knowledge that should live once. Two adapters exist naturally: the six production hooks and the test suite exercising every exit arm.
Proposed work
Move the protocol behind one interface (vendored per ADR-0019 alongside the hook-utils cluster) that owns snapshot lifetime and single-document composition, so an exit arm cannot leak and a rewrite-plus-findings run cannot double-print by construction.
One suite with a stub formatter and an isolated TMPDIR: on every exit arm the scratch is empty afterward (with a during-run probe so the assertion is not vacuous); a rewrite-plus-findings run puts exactly one JSON document on stdout carrying both channels; a no-op run stays silent.
Acceptance criteria
The snapshot/disclose/release protocol has one implementation consumed by all six hooks.
Parent candidate: the shared formatter-hook prologue (filed separately, top recommendation); this protocol is its first natural slice.
Found by the /architecture:improve deepening scan (2026-08-27); shallow-signal and both runtime claims reproduced before filing. Dependency category: local-substitutable. Recommendation: Strong.
Context
Six hooks (
go-format,ruff-format,biome-format,bash-format,powershell-format,eol-normalizer) hand-write the same four-step protocol: snapshot to mktemp,cmp -safter the formatter runs, name the rewrite on the user channel, release the snapshot on every exit arm. The blocks are near-identical, differing only in variable prefix (_fmt_before,_go_before,_ps_before,_ruff_before,_biome_before,_eol_tmp).Because the protocol lives in each plugin rather than behind one interface, the same defect recurs plugin by plugin. The rollout itself landed one plugin at a time (f5b8a3d bash, b3e9735 biome, 1b10069 powershell, 3c9351d eol-normalizer, b1b1c22 the rest), then #3401 (a7f9537) fixed powershell's leaked snapshot and undisclosed rewrite, while the identical leak sat unrepaired next door in go-format. Both remaining defect families were verified live on 2026-08-27 and are filed as #3405 (go-format snapshot leak on both error arms) and #3406 (ruff/biome/bash emitting two JSON documents on a rewrite-plus-findings run, against the single-document invariant documented at
lib/hook-utils.sh:75-78).Deletion test: concentrates. A future maintainer would rebuild this module substantially the same way; the protocol (snapshot lifetime, disclosure wording, single-document stdout composition) is exactly the knowledge that should live once. Two adapters exist naturally: the six production hooks and the test suite exercising every exit arm.
Proposed work
TMPDIR: on every exit arm the scratch is empty afterward (with a during-run probe so the assertion is not vacuous); a rewrite-plus-findings run puts exactly one JSON document on stdout carrying both channels; a no-op run stays silent.Acceptance criteria
References
plugins/{go,ruff,biome,bash,powershell}-format/hooks/*.sh,plugins/eol-normalizer/hooks/eol-normalizer.sh,lib/hook-utils.sh:75-78/architecture:improvedeepening scan (2026-08-27); shallow-signal and both runtime claims reproduced before filing. Dependency category: local-substitutable. Recommendation: Strong.