version-bump-sandbox gate treats any git-show failure as "plugin is new", silently skipping the version-bump gate
Severity: medium | Confidence: 0.7 | Effort: S
Where:
.github/workflows/ci.yml:315-322
Evidence: base_json=$(git show "origin/$BASE:plugins/ca-sandbox/.claude-plugin/plugin.json" 2>/dev/null || true) followed by if [ -z "$base_json" ]; then echo "ca-sandbox is new on $BASE ... version bump not required"; exit 0; fi. The 2>/dev/null || true exists to tolerate the "file doesn't exist on base" case, but the redirect swallows every failure mode of git show (transient fetch/object-store error, a corrupted shallow history despite fetch-depth:0, a race on origin/$BASE), not just ENOENT.
Impact: This job exists specifically to stop the "silent staleness" bug this workflow's own header comment describes: a changed plugins/ca-sandbox/** payload shipping on an already-published version so claude plugin update no-ops for installed users. Any non-ENOENT git failure during the base-file lookup is misclassified as "first introduction" and the step takes the exit-0 (bump-not-required) branch instead of failing loudly, so the PR merges without the version-bump gate ever running its real check against the ca-sandbox-v tag.
Recommendation: Distinguish "path does not exist at that ref" (git show exit 128 with a "does not exist" stderr, or use git cat-file -e first) from any other git failure; only treat the former as the new-plugin allow-path, and let any other error propagate/fail the step instead of being caught by || true.
Acceptance criteria:
- A git-show/cat-file failure unrelated to the file being absent at $BASE causes the step to fail (non-zero exit), not silently exit 0
- The legitimate first-introduction case (file genuinely absent on base) still exits 0 without requiring a version bump
version-bump-sandbox gate treats any git-show failure as "plugin is new", silently skipping the version-bump gate
Severity: medium | Confidence: 0.7 | Effort: S
Where:
.github/workflows/ci.yml:315-322
Evidence:
base_json=$(git show "origin/$BASE:plugins/ca-sandbox/.claude-plugin/plugin.json" 2>/dev/null || true)followed byif [ -z "$base_json" ]; then echo "ca-sandbox is new on $BASE ... version bump not required"; exit 0; fi. The2>/dev/null || trueexists to tolerate the "file doesn't exist on base" case, but the redirect swallows every failure mode ofgit show(transient fetch/object-store error, a corrupted shallow history despite fetch-depth:0, a race on origin/$BASE), not just ENOENT.Impact: This job exists specifically to stop the "silent staleness" bug this workflow's own header comment describes: a changed plugins/ca-sandbox/** payload shipping on an already-published version so
claude plugin updateno-ops for installed users. Any non-ENOENT git failure during the base-file lookup is misclassified as "first introduction" and the step takes the exit-0 (bump-not-required) branch instead of failing loudly, so the PR merges without the version-bump gate ever running its real check against the ca-sandbox-v tag.Recommendation: Distinguish "path does not exist at that ref" (git show exit 128 with a "does not exist" stderr, or use
git cat-file -efirst) from any other git failure; only treat the former as the new-plugin allow-path, and let any other error propagate/fail the step instead of being caught by|| true.Acceptance criteria: