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
{{ message }}
Repository navigation
update-check crash is indistinguishable from "up to date" — preamble invocation fails open #1974
with the contract "no output = up to date". Because stderr is suppressed and the exit code is discarded, a script that crashes produces exactly the same observable result as a script that ran successfully and found no update. The check fails open.
Real-world incident
On a macOS install running Claude Code with command sandboxing enabled, ~/.gstack was not writable from inside the sandbox. gstack-update-check runs with set -euo pipefail and writes state to ~/.gstack early (snooze/marker/cache files), so it died on the first rm with Operation not permitted — before ever fetching the remote VERSION:
Wrapped in the documented 2>/dev/null || true chain, this rendered as silence → "up to date". The install sat at v1.12.2.0 while main was at v1.57.10.0 (45 releases, ~6 weeks behind), with every skill preamble cheerfully reporting no upgrade available. It was only caught because the user manually insisted an update existed and the agent compared VERSION against origin/main directly.
This failure mode is generic: any environment where the script exits non-zero (read-only $HOME, sandboxed agents, broken gstack-config, missing find/awk, etc.) silently disables update checks forever.
Suggested fix
Make failure distinguishable from "no update":
In gstack-update-check, trap errors and emit a sentinel line on any abnormal exit, e.g. CHECK_FAILED <reason> on stdout (stdout isn't suppressed by the documented invocation), so callers/agents can react instead of inferring "up to date".
Update the preamble/SKILL.md contract from "no output = up to date" to three states: UPGRADE_AVAILABLE, UP_TO_DATE (could be emitted explicitly), and CHECK_FAILED — and instruct agents to fall back to a direct git fetch && git show origin/main:VERSION comparison when the check fails.
Optionally: degrade gracefully when ~/.gstack is unwritable (skip cache/snooze writes instead of dying) so the remote comparison still runs read-only.
Environment: macOS (Darwin 25.3), global-git install at ~/.claude/skills/gstack, Claude Code with bash sandboxing.
🤖 Filed via Claude Code after debugging the incident above.
@16francej — recommend closing this issue in favor of #1982, but it should close only after the implementation emits one bounded, redacted stage code and updates the resolver and generated contracts. Current behavior hides local update-check failures as ordinary silence. Verify local-failure and quiet-network controls without changing disabled, snoozed, or network-unavailable behavior.
Activity
time-attack commentedon Jul 15, 2026
@16francej — recommend closing this issue in favor of #1982, but it should close only after the implementation emits one bounded, redacted stage code and updates the resolver and generated contracts. Current behavior hides local update-check failures as ordinary silence. Verify local-failure and quiet-network controls without changing disabled, snoozed, or network-unavailable behavior.
v1.64.0.0 fix wave: full tracker audit — 90 fixes, 52 issues closed, …
fix(update-check): flag stale installs by commit clock, not VERSION s…
fix(update-check): own verdict token, ancestry gate, stamped cache
fix(update-check): flag stale installs by commit clock, not VERSION s…
fix(update-check): own verdict token, ancestry gate, stamped cache