I recorded "92/14 on pristine develop vs 93/13 after — nothing worsened, one
case better". Three consecutive runs on one unchanged tree give 90/16, 92/14,
92/14: the suite is non-deterministic and both figures were single samples of
that spread. The port is indistinguishable from the noise; claiming an
improvement was false precision.
Surfaced because the post-merge run reported 90/16 and looked like a
regression. It was not — but the only reason the question could be settled
was re-running, which is exactly what the original claim had skipped.
`graphify install` regenerated the skill files against the installed 0.9.16
CLI; only `.graphify_version` moved — SKILL.md and both references are
byte-identical to what 0.9.15 already shipped, so this clears the CLI's
"skill is from graphify 0.9.15, package is 0.9.16" warning with no content
change to review.
CLAUDE.md was clobbered by the installer (it appends its own `# graphify`
section) and restored from a pre-run snapshot, per BDR-028.
Capitalizes the macOS port and the gstack Chromium deadlock, plus an
append-only correction to BLK-008 / LRN-038: their "ubuntu24.04 fallback
build" cause is refuted — macOS arm64 has a native Playwright 1.58.2 build,
no fallback, and the same hang reproduces. The real variable was the Node
version, and that wrong record misdirected this investigation for an hour.
EVAL-029 records two process failures worth keeping: the first fix
recommendation (pin node@22) was reversed only because the user asked
whether the browser was current — staleness had gone unpriced; and the grep
sweep returned empty twice while defects were present, once to `set -e`,
once to a pattern that could not match `${1,,}`.
Index rows added for all four registries. Pre-existing index drift
(BLK-018..020, LRN-144..149) left alone — backfilling means summarising
entries someone else wrote.
BDR-019 stripped the key from all 27 skills because `true` blocks model AND
orchestrator routing — silently breaking the routing CLAUDE.md describes —
while `false` was a no-op noise line. The scaffold kept injecting `true`, so
every skill created with `make new-skill` would have shipped unroutable.
doctor.sh already covers the other half upstream: its check was inverted to
warn on REINTRODUCTION rather than on absence, which is what surfaced this —
a new skill from the template would now trip that very guard.
Two independent failures, both of which stopped `make plugin` outright here.
GNU `sed -i` takes no suffix argument; BSD sed requires one and reads the
script as that suffix, so all three calls errored — and under `set -euo
pipefail` that aborts the installer. They go through a temp file now, written
back with `cat >` so the profile keeps its mode and owner.
While rewriting them: the orphan-comment cleanup `{N; /^\n$/d;}` could never
match on ANY platform — after N the pattern space starts with '#', so the
^\n$ anchor pair never applied. It was a silent no-op, now awk, and tested on
/bin/bash 3.2: both obsolete entries and their stranded headers go, the live
entry and the user's own lines stay, idempotent on re-run.
The second failure was worse because it was invisible: gstack's ./setup runs
`bunx playwright install chromium` unbounded, and Playwright 1.58.2 deadlocks
on Node 26 mid-extraction — both processes idle at 39/333 files, no error, no
progress, forever. That silently cut the 2026-09-13 run at step 2 of 10.
Chromium is now installed here instead, under a 900s deadline; on timeout the
installer bumps gstack's Playwright (its package.json declares "^1.x", so a
minor bump is in range) and retries once, then warns rather than aborts —
gstack is OFF by default and only its browser depends on this.
`timeout` is not in a stock macOS, so the deadline is pure bash. Proven by a
forced hang: rc 124 in 6s, no orphaned oopDownloadBrowserMain, stderr clean.
BSD userland rejects or silently ignores several GNU spellings the repo used:
- `timeout` is not in a stock macOS at all (Homebrew installs it, and also as
`gtimeout`). Without it every gates.sh check exited 127 and was recorded
NOT-MET whatever the check actually did — a systematic false negative.
The binary is now resolved once, with a pure-bash deadline behind it so the
124 contract still holds where neither binary exists. GATES_TIMEOUT_BIN is
overridable with `-` not `:-`, so an empty value forces that fallback: the
suite passes 64/64 both ways, timeout cases included.
- `touch -d '10 days ago'` is GNU-only; perl's utime is the one spelling both
platforms ship.
- BSD `wc -l` pads its count with leading spaces, so string compares failed as
got[ 48] want[48].
- `sed -i` needs a suffix argument on BSD AND does not expand \n in the
replacement, so the release-candidate CHANGELOG edit silently did nothing
and the assertion failed for the wrong reason. Rewritten in awk; the RC_TAG=0
mode still REDs on the absent tag, so the test keeps its teeth.
- `/bin/grep` does not exist on macOS (grep lives in /usr/bin), and `stat -c`
is GNU-only.
fast-libs 11/11, seo-data 221/221, release-candidate 5 GREEN / 0 RED.
macOS ships bash 3.2 as /bin/bash, which `#!/usr/bin/env bash` resolves to
when no newer bash is on PATH. Two builtins the repo relies on do not exist
there, and both failed SILENTLY:
- `mapfile` in the three surgical-commit helpers left every array empty, so
the scope guards passed on nothing (fail-OPEN) and the commits degraded to
"nothing pending — no-op" while reporting success. deploy-commit.test.sh
went 4/16; memory and doc commits simply never happened.
- `declare -A` in the session-start hook errored on every session and left
each plugin cost at 0, so the passive-budget warning could never fire.
`_read_lines_into` is the portable equivalent of `mapfile`, space-safe and
resetting its target first — expanding a never-assigned array trips `set -u`
on bash < 4.4, which is how the empty arrays surfaced as "unbound variable".
Plugin costs move to a `case`.
source-scope.sh's header prescribed `mapfile` to its callers; it now shows
the read loop, and its own test plus run-reconcile.sh stop using the builtin.
deploy-commit 16/16, source-scope 34/34, run-reconcile 25 GREEN / 0 RED,
session-start stderr empty.
`${1,,}` is bash 4.0+. macOS ships bash 3.2 as /bin/bash, where it raises
"bad substitution"; the subshell then exited 1 — read as "not local" — so
`url-guard.sh host` returned rc 0 for localhost, 127.x, 10.x, 192.168.x,
172.16-31.x, 169.254.169.254 and metadata.google.internal. The guard failed
OPEN on every Mac, and url-guard.test.sh recorded it as 13 "got[0] want[2]".
`shopt -s nocasematch` (bash 3.1+) keeps both the ASCII-only folding that
LC_ALL=C gives and the no-fork property the lowercase expansion had.
Verified on /bin/bash 3.2: the ten local/private/metadata targets now return
rc 2 (case-folded variants included), legitimate hosts still rc 0.
Ending a turn right after spawning a subagent fired the bell and a toast
saying the response was finished, while the work continued. The Stop
payload carries background_tasks, so skip the signal when it is not
empty; the next turn end signals once the work is really done.
Interaction requests still signal during background work. A missing
field still signals, so an older client loses nothing. Also drop the
message suffix when it merely restates the label.
Only turn end and the moments needing the user should signal. Any other
event reaching the hook, such as agent_completed or auth_success, now
exits without emitting, so a subagent finishing rings nothing even if the
Notification matcher is ignored.
The toast body showed Claude's own message when present and the raw
notification_type otherwise, so permission_prompt and idle_prompt reached
the user as snake_case. Map every event the matcher covers to a readable
label, and keep Claude's message as a suffix when it adds detail.
Notification matcher covers input-needed events only; end of turn had no
signal but idle_prompt, ~60s late. Wire notify-attention.sh on Stop too,
branching on hook_event_name for the message. Signal only: returns
terminalSequence + suppressOutput, never blocks (guard vs BDR-083).
Header documents both client-side prerequisites found in BLK-020.
Notification hook (permission_prompt|idle_prompt|agent_needs_input|
elicitation_*) returns BEL x2 + OSC 777 via the terminalSequence JSON
field (hooks have no controlling TTY). Client side over Remote-SSH:
VS Code accessibility.signals.terminalBell sound:on for the beep,
wenbopan.vscode-terminal-osc-notifier extension for the Windows toast.