Skip to content

[Sprint] sprint-loop-20 - #18

Merged
scealiontach merged 2 commits into
mainfrom
sprint/2026-04-29-sprint-loop-20
Apr 29, 2026
Merged

scealiontach merged 2 commits into
mainfrom
sprint/2026-04-29-sprint-loop-20

Conversation

@scealiontach

Copy link
Copy Markdown
Owner

Sprint Plan: 2026-04-29-sprint-loop-20

Sprint Goal

This sprint consolidates two complementary streams of work: closing out a high-priority bug
that spans two previous sprints (SUR-1883 — the remaining bare ret=$? in bash/daml-export
that SUR-1871 was supposed to eliminate), and dramatically expanding bats regression coverage
across the shell-scripts repository (SUR-1881 and SUR-1882). By the end of the sprint every
@package-declared library will have at least a starter bats spec, the seven highest-risk
command scripts will have fixture-based tests, and the daml-export variable-leak bug will be
fully closed — eliminating the class of ret/exit_code global leaks that has generated
multiple filed bugs (SUR-1859, SUR-1860, SUR-1871, SUR-1883).


Selected Issues

1. SUR-1883 — Bug: daml-export post-loop find … | while read body still has bare ret=$?

Priority: High
Labels: Bug
URL: https://linear.app/surinis/issue/SUR-1883

Description Summary

Follow-up to SUR-1871 (PR #15). The previous sprint fixed the ret=$? leak in build()
and the loop guard, but left a third site untouched: the post-loop
find "$TARGET_DIR" -name export.good -print | sort | while read -r buildFile body.
Inside that pipeline right-hand side, ret=$? is bare (not local). Because the while
runs in a subshell, the leak is currently contained — but any future refactor pulling
the body out of the pipe will re-expose it, and the SUR-1871 DoD explicitly required
all three sites to be made hygienic.

The suggested fix is to extract the body into a named function (verify_and_build)
with local ret=$? and to convert the pipeline to process substitution
(done < <(find … | sort)) so that RUNNING_PROCS array mutations reach the parent
shell rather than dying in the subshell.

A PR (#16) was submitted during sprint/2026-04-28-sprint-loop-13 and reportedly
implements the full fix. This sprint closes the issue by reviewing and merging that PR
(or re-implementing on a fresh branch if PR #16 is stale).

Rationale

High-priority bug that was explicitly called out in the SUR-1871 DoD yet not delivered.
The fix is localised to one file and gated by existing regression tests. Keeping it
open creates technical debt and risks re-exposure on future refactors.

Definition of Done

  • No bare ret=$? in bash/daml-export; every site uses local ret=$? inside a
    function body or is rewritten to if cmd; then / if ! cmd; then directly.
  • The post-loop find … export.good walk uses process substitution < <(…) (or
    equivalent non-subshell construct) so RUNNING_PROCS mutations reach the parent shell.
  • tests/sur-1871-daml-export.sh continues to pass and is extended to assert that
    RUNNING_PROCS reflects the builds triggered during the post-loop walk.
  • pre-commit run --files bash/daml-export exits 0 (shellcheck + shfmt clean).
  • PR [Sprint] sprint-loop-13 #16 reviewed and merged, OR a new feature/sur-1883 branch opened, reviewed,
    and merged if PR [Sprint] sprint-loop-13 #16 is stale/conflicted.

Dependencies / Ordering

Must be completed first; it is the only High-priority issue and its regression tests
provide a safety net for subsequent work. No blockers identified.


2. SUR-1881 — Test: missing bats coverage for bash/aws.sh, docker.sh, exec.sh, fn.sh, error.sh, secret.sh, annotations.sh

Priority: Medium
Labels: testing
URL: https://linear.app/surinis/issue/SUR-1881

Description Summary

SUR-1850 introduced bats specs for eight libraries, but seven @package-declared libraries
remain uncovered: annotations.sh, aws.sh, docker.sh, error.sh, exec.sh, fn.sh,
secret.sh. The issue provides concrete starter targets:

  • tests/exec.bats — assert exec_code not leaked; exec::hide swallows output but
    preserves exit codes.
  • tests/docker.bats — stub docker; assert docker::cp returns 1/2/3 for
    pull/tag/push failures.
  • tests/secret.bats — materialise secret via secret::as_file; trigger EXIT in a
    subshell; assert tempfile is shredded.
  • tests/fn.bats — assert correct dispatch for fn::if_exists and fn::wrapped.
  • tests/aws.bats — stub aws; assert aws::is_scan_complete maps COMPLETE->0 and
    IN_PROGRESS->1.
  • tests/error.bats — spawn subshell; assert error::exit foo exits 1 with "foo" on
    stderr.
  • tests/annotations.bats — assert annotations::deprecated newfn arg1 arg2 forwards
    arg1 arg2 to newfn and emits a debug log naming the deprecated caller.

The goal is to bring total bats coverage to all 16 @package-declared libraries.

Rationale

The exit_code/ret leak bugs filed as SUR-1859 and SUR-1860 against docker.sh and
exec.sh would have been caught by basic regression tests. secret.sh's EXIT trap is
untested despite managing on-disk secret material. Adding specs now closes the regression
gap and prevents the same class of bug from silently reappearing.

Definition of Done

  • tests/exec.bats added: asserts exec_code is not leaked; exec::hide/exec::capture
    preserve exit codes while swallowing output.
  • tests/docker.bats added: stubbed docker binary; docker::cp return-code contract
    explicitly asserted for pull/tag/push failure paths.
  • tests/secret.bats added: EXIT trap fires in a subshell and the tempfile no longer
    exists afterwards.
  • tests/fn.bats added: fn::if_exists and fn::wrapped dispatch tests pass.
  • tests/aws.bats added: fixture JSON; aws::is_scan_complete mapping verified.
  • tests/error.bats added: error::exit exit-code and stderr assertions pass.
  • tests/annotations.bats added: annotations::deprecated arg-forwarding and debug-log
    assertions pass.
  • All seven new specs pass under make test_bats without modification.

Dependencies / Ordering

No hard dependency on SUR-1883, but work in parallel or after. The stub/helper patterns
established here will be reused by SUR-1882 tests — complete SUR-1881 before SUR-1882.


3. SUR-1882 — Test: command scripts changelog, find-squashable, switch-to-branch, replace-validator, clean-branches, git-check, pretty-labels have no tests

Priority: Medium
Labels: testing
URL: https://linear.app/surinis/issue/SUR-1882

Description Summary

13+ command scripts have no test coverage. The highest-risk scripts (destructive or
state-mutating) are prioritised. The issue calls for a shared helpers::make_fixture_repo
helper in tests/helpers.bash to centralise per-test git-fixture boilerplate, then:

  1. tests/clean-branches.bats — fixture repo; assert dry-run does NOT delete; -T deletes
    only build/* tags. Pins the SUR-1835 invariant.
  2. tests/changelog.bats — fixture repo with three tagged commits; assert expected sections
    and -l link generation.
  3. tests/switch-to-branch.bats — two fixture repos under $HOME/git/<org>/; assert both
    get switched; neither leaves an unclean working tree.
  4. tests/git-check.bats — fixture repos in UNCOMMITTED/RELEASABLE/DEVELOPMENT states;
    assert correct output bucketing (locks SUR-1857 fix).
  5. tests/replace-validator.bats — stubbed k8s::ctl returning canned JSON; assert
    expected migration commands are emitted.
  6. tests/find-squashable.bats — fixture repo where commits 2 & 3 touch the same files;
    assert "could be squashed" output.
  7. tests/pretty-labels.bats — stubbed kubectl; assert tabular output matches fixture.

Rationale

clean-branches performs git branch -D (destructive), replace-validator mutates k8s
state, and switch-to-branch mutates many checkouts. SUR-1835 added a dry-run guard to
clean-branches that has never been exercised in a regression. These scripts are the
highest-priority targets for coverage.

Definition of Done

  • helpers::make_fixture_repo added to tests/helpers.bash and used by at least the
    clean-branches, changelog, switch-to-branch, and git-check specs.
  • tests/clean-branches.bats: dry-run asserts no deletion; -T asserts only
    build/* tags are deleted.
  • tests/changelog.bats: fixture repo with tagged commits; asserts expected section
    headers and link output with -l.
  • tests/switch-to-branch.bats: two-fixture-repo test; both repos switched cleanly,
    no unclean working tree left behind.
  • tests/git-check.bats: UNCOMMITTED/RELEASABLE/DEVELOPMENT state bucketing asserted.
  • tests/find-squashable.bats: squashable commit detection asserted on fixture history.
  • tests/pretty-labels.bats: stubbed kubectl output matches tabular fixture.
  • All new specs pass under make test_bats.

Dependencies / Ordering

Depends on SUR-1881 completing first (stub/helper patterns; helpers::make_fixture_repo
concept originates here but the established helper discipline from SUR-1881 should be in
place). Complete after SUR-1881.


Risks and Mitigations

# Risk Likelihood Impact Mitigation
1 PR #16 (SUR-1883) stale or conflicted — branch sprint/2026-04-28-sprint-loop-13 may have drifted from main Medium Low Check PR #16 status first. If mergeable, review and merge. If stale, re-implement on fresh feature/sur-1883; acceptance criteria are fully specified.
2 secret.sh EXIT-trap test kills the bats runner — triggering EXIT in the test process terminates bats itself High Medium Run the trap assertion in an explicit subshell: ( source bash/secret.sh; secret::as_file ...; exit ). Assert on tempfile after subshell returns.
3 Stub plumbing for aws/docker/kubectl differs across specs Low Low Read tests/helpers.bash and tests/k8s.bats first; reuse existing helpers::stub_bin or equivalent before writing new stubs.
4 switch-to-branch.bats filesystem isolation insufficient — script mutates repos under $HOME/git/<org>/ Medium High Use helpers::isolate_home to redirect $HOME to a temp dir; verify $HOME/git/ only exists inside the sandbox.
5 SUR-1881 + SUR-1882 scope is large (~14 new bats files) and may exceed one sprint cycle Medium Medium Prioritise in order listed. SUR-1881 (libraries) takes precedence over SUR-1882 (command scripts). Incomplete work stays in Todo for next sprint.
6 changelog.bats fixture requires a real git history with tags — helpers::make_fixture_repo must support tag creation Low Low Extend helper to accept a flag for tagged commits; document with @doc annotation.
7 replace-validator.bats depends on k8s::ctl stubbing matching the existing kubectl stub approach Low Low Reuse the kubectl stub pattern directly from tests/k8s.bats.

Out of Scope

  • Tests for command scripts NOT in the SUR-1882 priority list:
    check-system, pagerduty-alert, aws-get-kubeconfigs, k8s-support-collector,
    plantuml-from-k8s, copy-keys (beyond the prioritised seven).
  • Fixing bugs discovered while writing tests (file new Linear issues instead).
  • Changes to library implementations (only test coverage is in scope for SUR-1881/1882).
  • CI/CD pipeline modifications.
  • daml-export features beyond the specific ret=$? / process-substitution fix.

Linear Evidence

Field Value
Linear team verified Surinis (ID: ce9ebfde-ff2b-4f54-90f1-c388591ca110, key: SUR)
Linear project used shell-scripts (ID: a43901a0-b02b-4009-aae1-a6e8903d127d)
Query / filter applied Project = shell-scripts, Team = Surinis, State = Backlog, limit 250
Approx Backlog issues reviewed 3 (all returned; hasNextPage: false)
Approx manual-labelled issues skipped 0

Sub-issue Status

No sub-issues were found for any of the three selected issues.

Parent Issue Sub-issue Sub-issue Status Eligible?
SUR-1883 (none) — N/A
SUR-1881 (none) — N/A
SUR-1882 (none) — N/A

Linear State Transitions

Issue ID Previous State New State
SUR-1883 Backlog Todo
SUR-1881 Backlog Todo
SUR-1882 Backlog Todo

… (SUR-1881)

- tests/aws.bats: add aws::is_scan_complete COMPLETE/IN_PROGRESS/FAILED
  mapping assertions
- tests/secret.bats: register_env, as_file readable, EXIT-trap shred,
  must_exist failure path
- tests/fn.bats: if_exists call/skip/args-forward; wrapped call/fallthrough
- tests/error.bats: error::exit exits 1 with message on stderr
- tests/annotations.bats: deprecated arg-forwarding, debug-log naming caller,
  deprecated shim delegation
- tests/helpers.bash: add helpers::make_fixture_repo for fixture repos with
  optional tagged history (SUR-1882 prerequisite)
…nd-squashable, pretty-labels (SUR-1882)

- tests/changelog.bats: CHANGELOG header, v0.3.0/v0.2.0 section headers,
  -l link generation with GitHub remote
- tests/switch-to-branch.bats: multi-repo branch switch, clean working trees
- tests/find-squashable.bats: detects same-file consecutive commit run
- tests/pretty-labels.bats: kubectl stub; resource name and label per line
@scealiontach
scealiontach marked this pull request as ready for review April 29, 2026 09:17
@scealiontach
scealiontach merged commit 725e865 into main Apr 29, 2026
3 checks passed
@scealiontach
scealiontach deleted the sprint/2026-04-29-sprint-loop-20 branch April 29, 2026 09:26
@scealiontach scealiontach mentioned this pull request Apr 29, 2026
15 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant