Problem Statement
.github/workflows/ci.yml's shard job installs the Claude Code CLI over the network on every one of its five matrix shards, uncached and unconditional, behind the required check lib + python tests. Only the monolith shard consumes the CLI — the issue-671 plugin validate --strict gate lives in lib/test/run.sh — so four of the five installs are pure exposure: four unnecessary network dependencies in front of the merge-gating check.
Current Behavior
Reproduction facts: in one observed session claude.ai/install.sh returned HTTP 403 on all three retry attempts of the install step (bash scripts/retry-with-backoff.sh 3 2 'set -o pipefail; curl -fsSL https://claude.ai/install.sh | bash -s "$CLAUDE_CLI_VERSION"'), failing a shard before any test ran and costing a full re-run. The failure depends only on the remote host's response, not on the runner environment. The retry helper behaved correctly — a sustained 403 exhausts any retry budget. The step has been unconditional since it landed on 2026-07-28 (5fe55d349, 0bd193a78), and its own comment names the trade and the narrowing remedy: condition on the monolith shard once the trade stops being worth it, accepting the silent-revert exposure that reopens — the issue-671 gate self-skips when the CLI is absent, so if that gate ever migrated to a shard without an install, the check would go green while validating nothing.
Desired Behavior
The CLI install and its version-verify step run only on the monolith shard, cutting five network installs per push to one. The silent-revert exposure is closed rather than accepted: a CI run in which the issue-671 plugin-validate gate self-skips for CLI absence on the shard meant to run it fails loudly instead of passing green. The verify step stays unconditional relative to the install, so a wrong-version CLI still fails closed. No install cache is added — with one install remaining, the residual exposure is one transient-absorbing retried download per push, and a cache would add an exact-match key surface for marginal saving.
User Impact
A claude.ai outage can no longer redden the required check through four shards that consume nothing from the CLI, and every push spends one network install instead of five.
Technical Context
Scope note: The files and details below are the known starting points, not the full list. Before implementing, trace the change through the codebase to find every affected call site, consumer, and layer — this issue maps the work, it does not bound it.
- Relevant Classes/Files —
.github/workflows/ci.yml (the install and verify steps in the shard job, and the step comment that currently justifies the unconditional shape); lib/test/run.sh (the issue-671 gate and its blocking-gate self-skip, whose per-run NOTE line is the loud signal the new assertion keys on); scripts/assert-cli-version.sh (the existing verify helper, unchanged).
- Architecture Alignment — skips are already first-class: the suite enumerates each self-skip with a name, kind, and reason, and a
blocking-gate skip means a real gate that should have run here could not. Failing the monolith shard on that specific skip is the fail-closed shape the suite's skip taxonomy was built for.
- Dependencies — none new; the change removes network dependence from four shards.
- Data/Schema Considerations — none.
- Cross-layer Impact — one workflow file, plus whatever small assertion surface the shard path needs to fail on the gate's self-skip.
Provenance: #671 introduced the install step; #877 / #1292 / #890 / #1181 created the shard matrix that multiplies it. None addressed install cost.
Acceptance Criteria
Implementation Notes
- Approach — add
if: matrix.shard == 'monolith' to the install and verify steps, then close the exposure with an assertion on the monolith shard's path that the issue-671 gate did not take its blocking-gate skip branch — keyed on the gate's own enumerated skip line, so a future migration of the gate to another shard fails loudly there instead of reverting silently. Rewrite the step comment to the new shape in the same change.
- Relevant files — this touches
.github/workflows/ci.yml, and plausibly lib/test/run-shard.sh and lib/test/run.sh if the skip-line assertion is cleanest inside the shard runner rather than the workflow.
- Code Patterns — the suite's
skip <name> <kind> <reason> helper and its one-NOTE-line-per-skip emission are the machine-readable surface to assert against; scripts/assert-cli-version.sh is the existing fail-closed verify shape.
- Testing Strategy — the workflow half is verified by the shipped run itself (the required check's own CI reading shows four shards without the install step and one with it); the assertion half gets one focused check that the gate's
blocking-gate skip on the hosting shard produces a failure, exercised through the suite's existing skip machinery rather than a live CLI outage. actionlint in CI covers the workflow edit's shell.
- Documentation Needed — none. The step comment inside
ci.yml is the only prose describing this step.
- Potential Gotchas — the verify step must stay unconditional relative to the install (gated on the shard, never on the install step's outcome), so a corrupt restore path can never pass. A
blocking-gate skip does not fail the suite by design — the suite's exit code ignores skips — so the new assertion must read the skip enumeration explicitly rather than relying on exit status. Keep the assertion scoped to the CLI-absence skip of the issue-671 gate: other legitimate blocking-gate skips (the issue-434 dirty-tree self-scan arm) must not start failing CI. The # prflow:required-check markers and job names in ci.yml must not move.
Problem Statement
.github/workflows/ci.yml'sshardjob installs the Claude Code CLI over the network on every one of its five matrix shards, uncached and unconditional, behind the required checklib + python tests. Only themonolithshard consumes the CLI — the issue-671plugin validate --strictgate lives inlib/test/run.sh— so four of the five installs are pure exposure: four unnecessary network dependencies in front of the merge-gating check.Current Behavior
Reproduction facts: in one observed session
claude.ai/install.shreturned HTTP 403 on all three retry attempts of the install step (bash scripts/retry-with-backoff.sh 3 2 'set -o pipefail; curl -fsSL https://claude.ai/install.sh | bash -s "$CLAUDE_CLI_VERSION"'), failing a shard before any test ran and costing a full re-run. The failure depends only on the remote host's response, not on the runner environment. The retry helper behaved correctly — a sustained 403 exhausts any retry budget. The step has been unconditional since it landed on 2026-07-28 (5fe55d349,0bd193a78), and its own comment names the trade and the narrowing remedy: condition on themonolithshard once the trade stops being worth it, accepting the silent-revert exposure that reopens — the issue-671 gate self-skips when the CLI is absent, so if that gate ever migrated to a shard without an install, the check would go green while validating nothing.Desired Behavior
The CLI install and its version-verify step run only on the
monolithshard, cutting five network installs per push to one. The silent-revert exposure is closed rather than accepted: a CI run in which the issue-671 plugin-validate gate self-skips for CLI absence on the shard meant to run it fails loudly instead of passing green. The verify step stays unconditional relative to the install, so a wrong-version CLI still fails closed. No install cache is added — with one install remaining, the residual exposure is one transient-absorbing retried download per push, and a cache would add an exact-match key surface for marginal saving.User Impact
A claude.ai outage can no longer redden the required check through four shards that consume nothing from the CLI, and every push spends one network install instead of five.
Technical Context
.github/workflows/ci.yml(the install and verify steps in theshardjob, and the step comment that currently justifies the unconditional shape);lib/test/run.sh(the issue-671 gate and itsblocking-gateself-skip, whose per-run NOTE line is the loud signal the new assertion keys on);scripts/assert-cli-version.sh(the existing verify helper, unchanged).blocking-gateskip means a real gate that should have run here could not. Failing the monolith shard on that specific skip is the fail-closed shape the suite's skip taxonomy was built for.Provenance: #671 introduced the install step; #877 / #1292 / #890 / #1181 created the shard matrix that multiplies it. None addressed install cost.
Acceptance Criteria
.github/workflows/ci.yml, the Claude CLI install and version-verify steps execute on themonolithshard only; the other four shards perform no CLI install and no network fetch fromclaude.ai.monolithshard, the verify step still runs whenever the shard runs and fails the job on a missing or wrong-version CLI, independent of how the install step fared.blocking-gateself-skip for CLI absence on the shard that hosts it fails, rather than passing with the gate silently reverted..github/workflows/ci.ymlcontains noactions/cachestep for the CLI.Implementation Notes
if: matrix.shard == 'monolith'to the install and verify steps, then close the exposure with an assertion on the monolith shard's path that the issue-671 gate did not take itsblocking-gateskip branch — keyed on the gate's own enumerated skip line, so a future migration of the gate to another shard fails loudly there instead of reverting silently. Rewrite the step comment to the new shape in the same change..github/workflows/ci.yml, and plausiblylib/test/run-shard.shandlib/test/run.shif the skip-line assertion is cleanest inside the shard runner rather than the workflow.skip <name> <kind> <reason>helper and its one-NOTE-line-per-skip emission are the machine-readable surface to assert against;scripts/assert-cli-version.shis the existing fail-closed verify shape.blocking-gateskip on the hosting shard produces a failure, exercised through the suite's existing skip machinery rather than a live CLI outage.actionlintin CI covers the workflow edit's shell.ci.ymlis the only prose describing this step.blocking-gateskip does not fail the suite by design — the suite's exit code ignores skips — so the new assertion must read the skip enumeration explicitly rather than relying on exit status. Keep the assertion scoped to the CLI-absence skip of the issue-671 gate: other legitimateblocking-gateskips (the issue-434 dirty-tree self-scan arm) must not start failing CI. The# prflow:required-checkmarkers and job names inci.ymlmust not move.