Repository navigation
[Sprint] sprint-loop-34 - #30
Merged
Merged
Conversation
scealiontach
marked this pull request as ready for review
May 5, 2026 15:00
Signed-off-by: Kevin O'Donnell <kodonnel@gmail.com>
…(SUR-2342) Signed-off-by: Kevin O'Donnell <kodonnel@gmail.com>
Signed-off-by: Kevin O'Donnell <kodonnel@gmail.com>
…der injection (SUR-2331) Signed-off-by: Kevin O'Donnell <kodonnel@gmail.com>
…UR-2327) Signed-off-by: Kevin O'Donnell <kodonnel@gmail.com>
Signed-off-by: Kevin O'Donnell <kodonnel@gmail.com>
…SUR-2324) Signed-off-by: Kevin O'Donnell <kodonnel@gmail.com>
The original SUR-2327 fix defaulted any unresolved endpoint to HEAD or the repo root so -f and -t could be used independently. That conflated two cases: (a) the user did not pass the flag, and (b) the user passed the flag but the date matched no commit. Case (b) now silently expanded the range to the opposite of what was requested — e.g. -t 1900-01-01 dumped full history instead of reporting "no commits before that date". Distinguish the two before applying the default. If the user supplied the flag but the corresponding date_to_commit lookup returned empty, print "No commits before <date>" / "No commits on or after <date>" and exit 0. Otherwise apply the per-flag default as before. Updated the existing 2999-01-01 fixtures to 2050-01-01: git rev-list's approxidate parser silently misparses 2999, which masked the regression by making the broken-default path indistinguishable from the fixed one. Adds two regression tests covering -t with a pre-history date and -f with a post-history date; both must NOT print any commit message. Signed-off-by: Kevin O'Donnell <kodonnel@gmail.com>
scealiontach
force-pushed
the
sprint/2026-05-05-sprint-loop-34
branch
from
May 5, 2026 17:07
450a7e9 to
3ece592
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Sprint Plan: 2026-05-05 — sprint-loop-34
Sprint Goal
Harden the
bash/library against a cluster of small, latent correctnessbugs and ergonomic anti-patterns that have been catalogued in the Backlog
but never picked up. Each selected issue is a self-contained, low-blast-
radius fix in either a single command script (
changelog,aliases,pretty-labels) or a single library function (commands::use,log::_format, thelog.shsource-time guard,secret::_install_cleanup_trap).Every fix lands with a corresponding
batsregression spec so thebehaviour does not silently regress again. The sprint is sized so all
seven items can ship as independent commits on one feature branch and
roll up into a single PR per issue.
Selected Issues
1. SUR-2330 — Bug: aliases
update_kubectlmissingmkdir -p $HOME/.local/binbeforeinstallupdate_kubectlcallsinstall -m 0755 "$tmpdir/kubectl" "$HOME/.local/bin/kubectl"(line 226) without firstensuring
~/.local/binexists. Peer functionsupdate_eksctl(line 89)and
update_helm(line 148) bothmkdir -pfirst. On a fresh machinethe install hard-fails with
cannot create regular file ... No such file or directory.update_kubectlintoparity with its two siblings. New-machine UX bug; the kind of thing
that bites exactly when someone is trying the script for the first
time. Self-contained; no library impact.
mkdir -p "$HOME/.local/bin"(or equivalentinstall -D) addedimmediately before the existing
installcall inupdate_kubectl.update_*functions consistent in their dir-creationstyle.
tests/aliases.bats(new or extended) covers: with~/.local/binabsent,
update_kubectlsucceeds and the binary is installed.make testandpre-commit run --all-filespass.2. SUR-2342 — Bug:
commands::usebreaks for command names containing hyphenscommands::usebuilds the cache-key variableas
_${cmd}and thendeclare -g "${var}=$path". When$cmdcontainsa hyphen or dot (
ssh-keygen,aws-vault,python3.12), the literalvariable name is rejected by bash:
declare: '_ssh-keygen=...': not a valid identifier. Distinct fromthe closed SUR-1810 fix.
tool" helper that AGENTS.md actively encourages new code to use. Latent
today (current callers are all hyphen-free), but every future caller
needing
ssh-keygen/pre-commit/python3.12would hit it.commands::usesanitises non-identifier characters ([^A-Za-z0-9_] → _) when constructing the cache-key variable name.command -v "$cmd"continues to use the unsanitised original name(we resolve
ssh-keygen, notssh_keygen).tests/commands.batscases: stubssh-keygenon PATH, assertcommands::use ssh-keygenreturns the stubbed path; secondinvocation hits the cache without re-resolving.
awk,jq,kubectl, etc.) stillpass their bats coverage.
make testandpre-commit run --all-filespass.bash/commands.shandtests/commands.bats.3. SUR-2347 — Improvement:
log.shsource-time init guard skips ALLLOG_DISABLE_*flags if any one is pre-setbash/log.sh:89–96the source-time guardinitialises
LOG_DISABLE_*fromLOG_LEVELonly when none of thefour disable flags are pre-set. If a caller pre-sets exactly one
(e.g.
LOG_DISABLE_INFO=false), the other three remain unset (empty),and
[ "$LOG_DISABLE_TRACE" = "false" ]evaluates false, silentlydisabling those levels regardless of
LOG_LEVEL.to debug. Distinct from closed SUR-1925. Fix is a small, contained
refactor of one source-time block.
LOG_DISABLE_*flag independently whenunset; explicit caller pre-sets are preserved.
tests/log.batsadds: pre-setLOG_DISABLE_INFO=falseonly,LOG_LEVEL=4, sourcelog.sh, assert all four flags arefalse.make testandpre-commit run --all-filespass.bash/log.shandtests/log.bats. Should land before or after SUR-2331 (separatecommits; orthogonal line ranges).
4. SUR-2331 — Bug:
log::_formatsequential substitution lets messages inject%LEVEL/%PID/%DATEplaceholderslog::_formatsubstitutes%MESSAGEfirst,then
%LEVEL/%PID/%DATE, so any literal placeholder text insidethe user-supplied message gets re-interpreted by the subsequent
substitutions.
log::info "request: %LEVEL"prints... INFO request: INFOinstead of... INFO request: %LEVEL.substituting
%MESSAGElast; alternatively switch toprintfpositional
%ss.log::_formatsubstitutes%LEVEL,%PID,%DATEbefore%MESSAGE(or moves toprintfwith positional args).tests/log.batsadds:log::_format INFO "literal %LEVEL"outputcontains the literal string
%LEVEL, never the substituted levelname.
make testandpre-commit run --all-filespass.bash/log.sh).Land in a separate commit. Either order works; lines 89–96 vs 205–220
do not conflict.
5. SUR-2327 — Bug:
changelogwith only-for only-tfailsbash/changelogdocuments-f FROM_DATEand-t TO_DATEas independent, but the wiring requires both:-faloneprints "No change history in the requested range";
-talone hits::fromto's${1:?}parameter-null error.exactly the natural "give me a changelog since date X" use case.
Fix is to default each missing endpoint to a sensible ref (HEAD for
to, repo-root commit forfrom).-falone produces a non-empty changelog ending at HEAD.-talone produces a non-empty changelog starting at the repo root.removed when at least one of
-f/-tis set.tests/changelog.bats(new or extended) covers all three cases.make testandpre-commit run --all-filespass.bash/changelogandtests/changelog.bats.6. SUR-2332 — Bug:
pretty-labelsemits a stray header row fromkubectl --show-labelsbash/pretty-labelsrunskubectl get $RESOURCE_TYPE --show-labelswithout--no-headers, so the headerrow survives the awk extraction as
"NAME:LABELS"and produces onejunk row per invocation. The closed SUR-1841 explicitly flagged this
anti-pattern as generic;
pretty-labelswas missed.consistent; affects every invocation. Mockable with a stubbed
kubectlin bats.
pretty-labelsinvokeskubectl get ... --show-labels --no-headers "$@", eliminating the header row at the source.tests/pretty-labels.bats(new) mockskubectlto emitheader + one row, asserts output contains exactly the per-row lines
and no
LABELSliteral.make testandpre-commit run --all-filespass.bash/pretty-labelsand
tests/pretty-labels.bats.7. SUR-2324 — Bug:
secret::_install_cleanup_trapclobbers caller-defined EXIT/INT/TERM trapssecret::_install_cleanup_trap(added bySUR-1839) installs
trap 'secret::clear' EXIT INT TERMunconditionallyon first secret registration, silently overwriting any caller-installed
EXIT/INT/TERM trap. Resource leaks follow.
capture the existing trap with
trap -pand chain it aftersecret::clear. Has clear bats reproducer.secret::_install_cleanup_trapcaptures any pre-existing EXIT (andoptionally INT/TERM) trap and chains it after
secret::clear.tests/secret.bats(new or extended) installs a caller trap thattouches a sentinel file, calls
secret::register_env, exitscleanly in a subshell, and asserts both the secret tempfiles are
gone and the caller sentinel was created.
SECRET_TRAP_INSTALLEDidempotency guard remains.make testandpre-commit run --all-filespass.bash/secret.shandtests/secret.bats.Risks + Mitigations
bash/log.shmerge friction between SUR-2347 and SUR-2331.Both modify
log.shandtests/log.bats. Mitigation: land them inseparate commits in known order; rebase the second on the first
before pushing.
commands::usesanitisation could shadow distinct commandsthat differ only by hyphen vs underscore (e.g.
foo-barvsfoo_barboth map to cache key
_foo_bar). Mitigation: such collisionsare extraordinarily unlikely on a real PATH; document in a function
header comment that the sanitiser is for cache-key validity only and
the
command -vlookup uses the original name. Add an assertion inthe bats test.
update_kubectlandupdate_helm/update_eksctlparitydrifts further if the fix is applied only to
update_kubectl.Mitigation: prefer
install -D -m 0755for all three (pulls dircreation inside
installitself) — but only if the change can bescoped within SUR-2330's intended blast radius without becoming a
cross-issue refactor.
pretty-labels--no-headersflag may conflict withuser-supplied flags via
"$@". Mitigation: insert--no-headersbefore
"$@"so a user can still suppress it intentionally if needed(last-flag-wins in kubectl). Cover in bats.
secret::_install_cleanup_trapchained trap with embeddedsingle quotes in caller's prior trap could break the
reconstruction. Mitigation: prefer the documented
trap -p EXITcapture pattern and quote-escape carefully; add a bats case where the
caller trap contains a single quote.
changelogdefault endpoints (HEAD, repo-root commit) maysurprise existing users. Mitigation: document the default in
--help; addtests/changelog.batscases that pin the newbehaviour.
CI already runs
make test; verify the submodule init step ispresent, otherwise add
git submodule update --initto the verifyplan.
no-commit-to-branchhook rejects the sprintbranch on commit if branch name fails the
^(fix|feature|refactor|sprint)/[a-zA-Z0-9-]+$regex. Mitigation: branchname
sprint/2026-05-05-sprint-loop-34matches the regex; verified.Out of Scope
bash/release-imageslog-level forcing (SUR-2344) —not selected this sprint.
pagerduty::send_incidentxtrace silencing (SUR-2339).aws::wait_for_scan_completetimeout/max-attempts(SUR-2340).
options::add -mmandatory-flag enforcement (SUR-2322).docker::registrycmdnull-token handling (SUR-2337).switch-to-branch -nfallback semantics (SUR-2334).update_kubectl/update_helm/update_eksctl(beyond the localparity fix).
log::_formatfrom sequential parameter substitution to afull
printf-based formatter (only the placeholder-ordering fix isin scope; deeper rewrite is out).
@includegraph change.Linear Evidence
Surinis(idce9ebfde-ff2b-4f54-90f1-c388591ca110)shell-scripts(ida43901a0-b02b-4009-aae1-a6e8903d127d)mcp__linear__list_issueswithteam=Surinis,project=shell-scripts,state=Backlog,limit=100;per-issue follow-ups via
mcp__linear__get_issuewithincludeRelations=true, sub-issue scan viamcp__linear__list_issueswith
parentId=<id>, comments viamcp__linear__list_comments.manual-labelled Backlog issues skipped: 0[][](the<OPEN_PR_FILES>list was empty, so Filter B was a no-op)Sub-issue Status
None of the 13 Backlog issues had any sub-issues. Each
mcp__linear__list_issues parentId=<ID>query returned an empty list.Linear State Transitions