Development record
2026-08-01 — itd-105 / spc-21, FIX pass after two fresh adversarial pre-PR reviews (one security, one correctness) that converged independently on the same top items. Detector-first throughout; each behavioural fix has a test watched failing before it and passing after. Four claims of the entry above are superseded. (1) `ABCD_BOOTSTRAP_BASE_URL` / `ABCD_BOOTSTRAP_API_URL` were bare `${VAR:-default}` reads, which made them a code-execution primitive rather than a test seam: the binary AND the `checksums.txt` that verifies it are fetched from the same base, so whoever set the variable supplied both the payload and the manifest that "verified" it — verification became vacuous — and the installed binary is then run unattended as the Bash shell guard on every tool call. Both are now honoured for `http://127.0.0.1:*` / `http://localhost:*` only and REFUSED otherwise (refusing beats ignoring: a silently dropped override reads as a passing test), and the production calls pin `--proto =https --proto-redir =https` so no redirect can downgrade the transport or point at `file://`. (2) `release_tag` was scraped from `%{url_effective}` after `-L` on the asset download, which was verified against the real repository to land on `release-assets.githubusercontent.com/<numbers>?<signed query>` — no `/releases/download/<tag>/` segment exists there, so in production the tag was ALWAYS `unknown`, `release_sha` was always `unknown` behind it, and the entire version-skew notice (an intent AC) could never fire. The tag is now resolved BEFORE any download, from `%{redirect_url}` on an unfollowed request to `/releases/latest` (302 -> `/releases/tag/<tag>`), and both the asset and `checksums.txt` are then fetched from the TAG-PINNED path — which also closes the narrower hole that a release cut between the two downloads would have checked a new manifest against an old binary. The fixture was the reason this passed review-blind: it redirected to a conveniently tag-shaped URL, so it now mimics the real CDN shape and serves `checksums.txt` only from the pinned path. Consequence accepted: an unresolvable tag is now a refusal rather than a silent `unknown`, because the alternative is an unpinned pair the checksum step cannot honestly verify. (3) The bootstrap's two messages for a person — the unsupported-platform statement and the one-time `abcd ahoy install` suggestion — went to stdout with exit 0, which on `SessionStart` means model context and nothing the human ever sees; both now go to stderr with exit 2, matching `cli.go`'s existing "non-zero so SessionStart shows it; SessionStart never blocks" convention. This deviates from spc-21's Approach step 2, which specified exit 0 for the unsupported platform: the spec's reason (a reported condition, not a hook fault to retry) is preserved — nothing is changed, nothing is retried — but exit 0 also meant the statement was unreadable by its only audience. (4) `trap cleanup EXIT HUP INT TERM` where `cleanup` returns does not terminate on a signal; POSIX RESUMES the script, verified empirically here, so a SIGTERM mid-run deleted the temp dir and then carried on to report a checksum mismatch that never happened. Now `trap cleanup EXIT` plus `trap 'cleanup; exit 1' HUP INT TERM`, cleanup being idempotent. Smaller, same pass: `.binary-meta` is written through the temp dir and renamed in (a crash mid-write otherwise left a truncated `release_sha` that still parsed) and carries the verified `binary_sha256` so a later check can tell the binary that was verified from one that replaced it; `resolvedSHA` now requires forty lowercase hex rather than merely "not the literal unknown"; the skew notice is non-directional, since comparing two commits establishes that they differ and never which is ahead; the fast path requires a regular file, `[ -x ]` alone being true of a directory too; a run holding the lock sweeps `.bootstrap.tmp.*` orphaned by a SIGKILL (which runs no trap); `hooks/*.sh` is pinned `eol=lf`, a CRLF checkout of this one breaking the script that repairs the hooks rather than merely a hook.
2026-08-01 — itd-105 / spc-21, FIX pass after two fresh adversarial pre-PR reviews (one security, one correctness) that converged independently on the same top items. Detector-first throughout; each behavioural fix has a test watched failing before it and passing after. Four claims of the entry above are superseded. (1) ABCD_BOOTSTRAP_BASE_URL / ABCD_BOOTSTRAP_API_URL were bare ${VAR:-default} reads, which made them a code-execution primitive rather than a test seam: the binary AND the checksums.txt that verifies it are fetched from the same base, so whoever set the variable supplied both the payload and the manifest that "verified" it — verification became vacuous — and the installed binary is then run unattended as the Bash shell guard on every tool call. Both are now honoured for http://127.0.0.1:* / http://localhost:* only and REFUSED otherwise (refusing beats ignoring: a silently dropped override reads as a passing test), and the production calls pin --proto =https --proto-redir =https so no redirect can downgrade the transport or point at file://. (2) release_tag was scraped from %{url_effective} after -L on the asset download, which was verified against the real repository to land on release-assets.githubusercontent.com/<numbers>?<signed query> — no /releases/download/<tag>/ segment exists there, so in production the tag was ALWAYS unknown, release_sha was always unknown behind it, and the entire version-skew notice (an intent AC) could never fire. The tag is now resolved BEFORE any download, from %{redirect_url} on an unfollowed request to /releases/latest (302 -> /releases/tag/<tag>), and both the asset and checksums.txt are then fetched from the TAG-PINNED path — which also closes the narrower hole that a release cut between the two downloads would have checked a new manifest against an old binary. The fixture was the reason this passed review-blind: it redirected to a conveniently tag-shaped URL, so it now mimics the real CDN shape and serves checksums.txt only from the pinned path. Consequence accepted: an unresolvable tag is now a refusal rather than a silent unknown, because the alternative is an unpinned pair the checksum step cannot honestly verify. (3) The bootstrap's two messages for a person — the unsupported-platform statement and the one-time abcd ahoy install suggestion — went to stdout with exit 0, which on SessionStart means model context and nothing the human ever sees; both now go to stderr with exit 2, matching cli.go's existing "non-zero so SessionStart shows it; SessionStart never blocks" convention. This deviates from spc-21's Approach step 2, which specified exit 0 for the unsupported platform: the spec's reason (a reported condition, not a hook fault to retry) is preserved — nothing is changed, nothing is retried — but exit 0 also meant the statement was unreadable by its only audience. (4) trap cleanup EXIT HUP INT TERM where cleanup returns does not terminate on a signal; POSIX RESUMES the script, verified empirically here, so a SIGTERM mid-run deleted the temp dir and then carried on to report a checksum mismatch that never happened. Now trap cleanup EXIT plus trap 'cleanup; exit 1' HUP INT TERM, cleanup being idempotent. Smaller, same pass: .binary-meta is written through the temp dir and renamed in (a crash mid-write otherwise left a truncated release_sha that still parsed) and carries the verified binary_sha256 so a later check can tell the binary that was verified from one that replaced it; resolvedSHA now requires forty lowercase hex rather than merely "not the literal unknown"; the skew notice is non-directional, since comparing two commits establishes that they differ and never which is ahead; the fast path requires a regular file, [ -x ] alone being true of a directory too; a run holding the lock sweeps .bootstrap.tmp.* orphaned by a SIGKILL (which runs no trap); hooks/*.sh is pinned eol=lf, a CRLF checkout of this one breaking the script that repairs the hooks rather than merely a hook.
Frontmatter
| id | dcn-2608010000000006 |
|---|---|
| type | decision |
| date | 2026-08-01 |
.abcd/work/decisions/dcn-2608010000000006-itd-105-spc-21-fix-pass-after-two-fresh.md
open on GitHub ↗ · commit history ↗