What
actionlint (which also runs shellcheck against embedded run: blocks)
flags the test job's "Set up PostgreSQL + pgvector (runner-local, no
registry pull)" step (.github/workflows/ci.yml:44-65):
$ actionlint .github/workflows/ci.yml
.github/workflows/ci.yml:45:9: shellcheck reported issue in this script: SC2015:info:10:40: Note that A && B || C is not if-then-else. C may run when A is true [shellcheck]
.github/workflows/ci.yml:45:9: shellcheck reported issue in this script: SC2015:info:11:76: Note that A && B || C is not if-then-else. C may run when A is true [shellcheck]
.github/workflows/ci.yml:45:9: shellcheck reported issue in this script: SC2015:info:20:65: Note that A && B || C is not if-then-else. C may run when A is true [shellcheck]
.github/workflows/ci.yml:45:9: shellcheck reported issue in this script: SC2034:warning:19:1: i appears unused. Verify use (or export if used externally) [shellcheck]
Three for i in 1 2 3; do <cmd> && break || sleep 5; done / for i in $(seq 1 30); do <cmd> && break || sleep 1; done retry loops
(lines 55, 56, 64) use A && B || C, which is not if/then/else: if B
itself fails (e.g. break inside a loop that a shell option makes fail, or
any future edit that puts a failing command in the B slot), C runs too.
Today break cannot itself fail, so this is not a live bug, but it is exactly
the shape SC2015 exists to flag before an edit turns it into one. $i is
also unused beyond the loop counter (SC2034), which is usually a false
positive for a retry counter but is worth silencing explicitly rather than
leaving a standing warning.
Why filed here, not fixed inline
Found 2026-07-29 while verifying an unrelated .github/workflows/ci.yml edit
for issue #251 (a new step in the lint job, far below this one in the
test job). actionlint/shellcheck is not part of this repo's own gates
(grep confirms zero references in .github/, no pre-commit config) — I ran
it as an extra precaution on my own new YAML, and it surfaced this
pre-existing, unrelated finding. None of #251's own build/lint/test steps
reach this code path, so it is outside that change's blast radius per
coding-standards.md §14.3, and is deferred here rather than folded into an
unrelated PR (which would also add merge-conflict surface across the several
other worktree branches presently editing ci.yml).
Acceptance criteria
- Each
A && B || C retry loop (lines 55, 56, 64) rewritten as an explicit
if/until so a failing B cannot fall through to C.
- The retry-loop counter variables are either used (e.g. logged on final
failure) or renamed/prefixed to signal intentional non-use, silencing
SC2034.
actionlint .github/workflows/ci.yml reports zero findings.
- The
test job still passes on Python 3.10-3.13 (no behavior change to the
PostgreSQL provisioning retry semantics).
What
actionlint(which also runs shellcheck against embeddedrun:blocks)flags the
testjob's "Set up PostgreSQL + pgvector (runner-local, noregistry pull)" step (
.github/workflows/ci.yml:44-65):Three
for i in 1 2 3; do <cmd> && break || sleep 5; done/for i in $(seq 1 30); do <cmd> && break || sleep 1; doneretry loops(lines 55, 56, 64) use
A && B || C, which is not if/then/else: ifBitself fails (e.g.
breakinside a loop that a shell option makes fail, orany future edit that puts a failing command in the
Bslot),Cruns too.Today
breakcannot itself fail, so this is not a live bug, but it is exactlythe shape SC2015 exists to flag before an edit turns it into one.
$iisalso unused beyond the loop counter (SC2034), which is usually a false
positive for a retry counter but is worth silencing explicitly rather than
leaving a standing warning.
Why filed here, not fixed inline
Found 2026-07-29 while verifying an unrelated
.github/workflows/ci.ymleditfor issue #251 (a new step in the
lintjob, far below this one in thetestjob).actionlint/shellcheck is not part of this repo's own gates(grep confirms zero references in
.github/, no pre-commit config) — I ranit as an extra precaution on my own new YAML, and it surfaced this
pre-existing, unrelated finding. None of #251's own build/lint/test steps
reach this code path, so it is outside that change's blast radius per
coding-standards.md §14.3, and is deferred here rather than folded into an
unrelated PR (which would also add merge-conflict surface across the several
other worktree branches presently editing ci.yml).
Acceptance criteria
A && B || Cretry loop (lines 55, 56, 64) rewritten as an explicitif/untilso a failingBcannot fall through toC.failure) or renamed/prefixed to signal intentional non-use, silencing
SC2034.
actionlint .github/workflows/ci.ymlreports zero findings.testjob still passes on Python 3.10-3.13 (no behavior change to thePostgreSQL provisioning retry semantics).