Skip to content

[Sprint] sprint-loop-42#38

Merged
scealiontach merged 5 commits into
mainfrom
sprint/2026-05-13-sprint-loop-42
May 13, 2026
Merged

[Sprint] sprint-loop-42#38
scealiontach merged 5 commits into
mainfrom
sprint/2026-05-13-sprint-loop-42

Conversation

@scealiontach
Copy link
Copy Markdown
Owner

Sprint Plan — 2026-05-13 sprint-loop-42

Sprint goal

Close concrete coverage gaps in three undertested command scripts (bashadoc,
pagerduty-alert, daml-export) and harden two well-scoped quality issues
(pack-script @include parsing; k8s-support-collector empty-dir noise).
Each item is small, self-contained, and lands behind existing test
infrastructure (bats + sprint regression scripts). The goal is to convert
"silent-failure" surfaces into asserted behaviour without expanding scope into
the wider library refactor backlog.

Selected issues

SUR-2835 — Test: bashadoc has no bats coverage

Description summary: bash/bashadoc ships the doc-*.tar.gz release
artifact via make package but has no direct test file. The current "smoke
test" passes even when bashadoc emits empty/garbage markdown because the tar
step never inspects content. The issue calls out specific brittleness around
@package resolution and function @package() { lines in doc.sh polluting
the resolved package name.

Rationale: bashadoc is a published-artifact generator with no unit
coverage. The author already provided a concrete five-case test list, fixtures
suggestion, and known regression (the @package self-collision). This is the
highest-leverage testing addition in the backlog: small surface, high
downstream impact.

Definition of Done:

  • tests/bashadoc.bats exists and is wired into make test_bats /
    pre-commit run bats --all-files.
  • Spec covers all five cases enumerated in the issue: @package header,
    no-@package fallback, @doc/@arg ordering with semicolon stripping,
    function @package() { non-pollution regression, non-.sh arg fails
    with exit 1.
  • Fixtures live under tests/fixtures/bashadoc/ and are referenced by path,
    not heredoc'd inline.
  • make test is green locally.
  • No production change to bash/bashadoc (test-only, unless a fixture surfaces
    the @package regression — then a minimal in-place fix is acceptable and
    must be called out in the commit message).

SUR-2836 — Test: pagerduty-alert entry script has no bats coverage

Description summary: bash/pagerduty-alert (the executable wrapper around
pagerduty.sh) has no .bats file even though the underlying library is
well covered. The script's option-validation, ALERT_TYPE dispatch, default
ALERT_FROM/ALERT_TITLE handling, and error::exit non-incident path are
exercised only by manual invocation; a silently regressing default fails open.

Rationale: Same low-cost / high-payoff shape as SUR-2835. Stub seam
(pagerduty::send_incident, exec::hide) already exists in
tests/pagerduty.bats; we can re-use it. Issue lists five exact assertions.

Definition of Done:

  • tests/pagerduty-alert.bats exists with the five assertions enumerated in
    the issue (missing-flag exits, stub argv ordering, default ALERT_TITLE /
    ALERT_FROM, non-incident ALERT_TYPE path, send-failure propagation).
  • Stubs land under tests/stubs/, mirroring the tests/pagerduty.bats
    pattern.
  • The spec runs via tests/bats/bin/bats tests/pagerduty-alert.bats and is
    picked up by make test_bats.
  • No behavioural change to bash/pagerduty-alert itself.

SUR-2838 — Test: daml-export helper functions lack unit coverage

Description summary: bash/daml-export has helpers (hex_to_dec,
dec_to_hex, verifyExport, correct_archives, correct_export, plus the
no-progress sentinel) exercised only via the SUR-1871 end-to-end regression.
Their documented contract points (three-state verifyExport return code,
correct_archives sed idempotency, correct_export daml.yaml/Export.daml
rewrites) are not asserted in isolation. The issue suggests adding a
DAML_EXPORT_SOURCE_ONLY test seam mirroring K8S_SUPPORT_COLLECTOR_SOURCE_ONLY.

Rationale: Largest of the three test-coverage items because it requires a
small production change (DAML_EXPORT_SOURCE_ONLY guard) before the bats
spec can source the script without firing the main loop. The pattern is
already proven elsewhere, so risk is contained.

Definition of Done:

  • Add a DAML_EXPORT_SOURCE_ONLY-style guard near the bottom of
    bash/daml-export so the helpers can be sourced without executing the main
    loop. The guard MUST default to executing (no behavioural change for
    unwrapped invocations).
  • tests/daml-export.bats covers the five cases from the issue
    (hex_to_dec / dec_to_hex round-trip, verifyExport three-state,
    correct_archives rewrite + idempotency, correct_export dual-file
    rewrite).
  • Existing tests/sur-1871-daml-export.sh still passes unchanged
    (tests/run.sh green).
  • pre-commit run shellcheck --all-files clean against the modified script.

SUR-2842 — Anti-pattern: pack-script extracts @include names via awk '{print $NF}'

Description summary: bash/pack-script's ::get_includes uses
grep "^@include" | awk '{print $NF}', which mis-parses inline comments
(@include foo # SUR-NNNNSUR-NNNN), extra-arg lines, and unanchored
matches. The companion Makefile grep -v ".sh$" filter has the same
fragility class (. matches any character). pack-script is the bin-tarball
packer, so a silent misparse ships a broken release artifact.

Rationale: Concrete fix sketch already in the issue (awk script that
strips comments + selects field 2). Production-affecting (release tarball),
small change, easy to test against the new fixture infrastructure landing
in SUR-2835 / SUR-2836.

Definition of Done:

  • bash/pack-script ::get_includes rewritten to anchor ^@include[[:space:]]+
    and strip trailing comments before extracting the include name (per the
    awk snippet in the issue, or equivalent).
  • Makefile grep -v ".sh$" replaced with find -name '*.sh' exclusion (or
    equivalent) so the filter is a literal extension match, not a regex.
  • A bats spec (tests/pack-script.bats if absent, or extend existing) asserts
    three regression cases: trailing-comment line, multi-arg line, leading-only
    match.
  • make package succeeds and the produced dist/bin-*.tar.gz is
    byte-identical to the prior run for unaffected scripts (eyeballed via
    tar -tzf).
  • No new lint warnings.

SUR-2844 — Simplify: k8s-support-collector creates an unused $out_dir_ns/pod directory

Description summary: describe_pods in bash/k8s-support-collector
creates $out_dir_ns/pod but never writes into it; the .describe output
goes to $out_dir_ns/$pod.describe (which already includes the literal
pod/ prefix from kubectl get pods -o name). Result: every collected
support tarball ships an empty directory. Issue offers two fixes: (a) drop the
unused dirs::ensure, or (b) make the layout symmetric with logs/ by
writing under pod/.

Rationale: Smallest change in the sprint, but production-visible (support
bundles) and trivially verifiable. Use as the closing item to leave slack for
spillover from the test-coverage tickets.

Definition of Done:

  • One of the two options in the issue is implemented; choice (a, drop) vs
    (b, make functional) called out in the commit message with rationale.
  • If option (b): the layout change is reflected in any sprint regression
    fixture (tests/sur-*.sh) or operator-facing doc that named the path
    pre-fix.
  • pre-commit run shellcheck --all-files clean.
  • Manual verification step documented: dry-run bash/k8s-support-collector
    against a fixture namespace and inspect the produced directory tree.

Dependencies / ordering

The five items are largely independent. Suggested sequencing:

  1. SUR-2842 first — smallest production change, lowest blast radius,
    establishes the pack-script fixture pattern that SUR-2835's bashadoc
    fixtures will follow.
  2. SUR-2835, SUR-2836 in parallel — both pure test additions, no
    shared files.
  3. SUR-2838 — requires the DAML_EXPORT_SOURCE_ONLY seam; do after the
    pure-test items so reviewers see the test-only PRs first.
  4. SUR-2844 — closing item; ship last as a "free" cleanup.

No cross-issue file overlap detected: pack-script (bash/pack-script,
Makefile), bashadoc (tests/), pagerduty-alert (tests/), daml-export
(bash/daml-export, tests/), k8s-support-collector
(bash/k8s-support-collector).

Risks + mitigations

  • pack-script Makefile change breaks bin-tarball selection in CI.
    Mitigation: run make clean package locally and diff tar -tzf dist/bin-*.tar.gz against the pre-change tarball before pushing.
  • DAML_EXPORT_SOURCE_ONLY guard mis-placed and breaks the main loop for
    real invocations.
    Mitigation: model the guard exactly on
    K8S_SUPPORT_COLLECTOR_SOURCE_ONLY; add a smoke assertion in
    tests/daml-export.bats that sourcing without the env var runs the loop
    (or, equivalently, that the existing tests/sur-1871-daml-export.sh
    still passes unchanged).
  • bashadoc fixture surfaces the function @package() { regression mid-PR.
    Mitigation: the in-place fix is small; commit it separately within the
    same PR, with a clear "regression discovered by SUR-2835 fixtures" message.
  • pagerduty-alert stubs drift from bash/pagerduty.sh semantics.
    Mitigation: re-use the stub helpers already in tests/pagerduty.bats
    rather than redefining; if helpers need promotion, move them into
    tests/stubs/pagerduty.bash and have both specs source it.
  • k8s-support-collector layout change (option b) breaks downstream
    consumers of the support tarball.
    Mitigation: prefer option (a) —
    drop the unused dirs::ensure — unless an operator-facing doc explicitly
    promises the pod/ subdir.
  • Sprint scope creep into companion mddoc / doc.sh coverage gaps
    (called out in SUR-2835).
    Mitigation: explicitly out-of-scope below.
  • Branch-protection regex (^(fix|feature|refactor|sprint)/[a-zA-Z0-9\\-]+$)
    rejects per-issue branches with underscores.
    Mitigation: branch names
    use the feature/sur-NNNN form already returned by Linear's gitBranchName.

Out of scope

  • mddoc / doc.sh test coverage (called out in SUR-2835's "Why it matters"
    but not selected; file a follow-up if SUR-2835 fixtures make it cheap).
  • The wider standard_defs.mk cleanup (SUR-2841) — touches release
    machinery, deserves its own focused sprint.
  • find-squashable first_squash overload (SUR-2840), log.sh snapshot/
    restore flatten (SUR-2843) — both deferred to keep this sprint's blast
    radius small (log.sh is sourced by every script).
  • The two documentation issues (SUR-2832, SUR-2834) — defer until a
    doc-focused sprint can batch them with related runbook updates.
  • Release publishing flow changes (bash/update-repo-tags, make publish).
  • Any change to the bats submodule pin under tests/bats.

Linear Evidence

  • Linear team verified: Surinis (ce9ebfde-ff2b-4f54-90f1-c388591ca110)
  • Linear project used: shell-scripts (a43901a0-b02b-4009-aae1-a6e8903d127d)
  • Query/filter used: list_issues(project="shell-scripts", state="Backlog", limit=100) against the Surinis team; followed by get_issue(includeRelations=true) and list_issues(parentId=...) per candidate, plus list_comments per candidate.
  • Approx count of Backlog issues reviewed: 10 (full Backlog page; hasNextPage=false).
  • Approx count of manual-labelled Backlog issues skipped: 0 (none of the 10 carried the manual label).
  • Issues skipped due to unmerged blockers: 0 — all 10 candidates returned relations.blockedBy = [].
  • Issues skipped due to open-PR file overlap: 0 — <OPEN_PR_FILES> was [], so Filter B is a no-op for this run.

Sub-issue Status

All selected issues were checked via list_issues(parentId=...) and returned
{"issues":[],"hasNextPage":false}. None of the selected issues have
sub-issues; no parent-gate violations apply.

Parent Issue Sub-issue Sub-issue Status Eligible?
SUR-2835 (none) n/a yes
SUR-2836 (none) n/a yes
SUR-2838 (none) n/a yes
SUR-2842 (none) n/a yes
SUR-2844 (none) n/a yes

Linear State Transitions

Issue ID Previous State New State
SUR-2835 Backlog Todo
SUR-2836 Backlog Todo
SUR-2838 Backlog Todo
SUR-2842 Backlog Todo
SUR-2844 Backlog Todo

Rewrite `::get_includes` to match a leading `@include[[:space:]]+`
directive, strip any trailing `# comment`, and emit field 2 only. The
previous `grep "^@include" | awk '{print $NF}'` surfaced trailing
comment tokens, multi-arg trailing tokens, and bare `@include` lines as
fake include names, leading `includer::find` to fail or produce noisy
errors at release time.

Also harden the companion Makefile filter:
`grep -v ".sh$"` (regex; `.` matches any char) becomes
`find ! -name '*.sh'` so the extension exclusion is a literal match.

Adds `tests/pack-script.bats` with three regression cases (trailing
comment, multi-arg, leading-only) and three fixtures under
`tests/pack-script/`.
Extends `tests/bashadoc.bats` from the three SUR-2829 regression tests
to the five contract points enumerated in SUR-2835:

  1. `@package` header rendering.
  2. No-`@package` fallback to filename + bare-name function list.
  3. `@doc` then `@arg` ordering, with the declare-f trailing
     semicolons scrubbed by the `tr ';' ' '` step.
  4. `function @Package() {` non-pollution regression (the SUR-2829
     anchor fix; kept here so future refactors of the awk extraction
     cannot silently regress it).
  5. Non-`.sh` argument fails with exit 1 and the documented stderr.

Fixtures live under `tests/fixtures/bashadoc/` so each case can be
inspected directly rather than reading heredoc'd content inside the
spec. No production change to `bash/bashadoc` was required — the
SUR-2829 anchor fix already in place handles case 4 cleanly.
Adds `DAML_EXPORT_SOURCE_ONLY` source-only guard near the bottom of
`bash/daml-export`, mirroring the `K8S_SUPPORT_COLLECTOR_SOURCE_ONLY`
seam already in use for the same pattern. Guard defaults to executing,
so unwrapped invocations (including `tests/sur-1871-daml-export.sh`)
are unchanged.

Adds `tests/daml-export.bats` exercising the five contract points
enumerated in SUR-2838 in isolation:

  1. `hex_to_dec` / `dec_to_hex` round-trip + 16-char hex padding.
  2. `verifyExport` three-state return code (2 for empty/missing,
     1 for exported-not-built, 0 when dar present).
  3. `correct_archives` sed rewrite (single match, multi-match,
     non-match passthrough) and idempotency on a second invocation.
  4. `correct_export` dual-file rewrite (`daml.yaml --target=1.14
     → 1.12`, `Export.daml` import drop, archive correction chained).
  5. Smoke check that the SOURCE_ONLY guard short-circuits the main
     loop when the env var is set.

Test bodies run inside `bash -c` to insulate the bats `set -e` from
the trailing `&&` short-circuit in `options::add` triggered when the
script's option table is built on source.
Adds tests/pagerduty-alert.bats covering the entry script's own logic
(`bash/pagerduty.sh` is already exercised in tests/pagerduty.bats):

  1. Missing required flags (-a / -s / -i) each individually exit
     non-zero with the help banner.
  2. With `-i incident`, `pagerduty::send_incident` receives
     `service_id alert_type alert_title alert_from alert_token incident_key`
     in that order.
  3. Default ALERT_TITLE ("Test Alert") and default ALERT_FROM
     ("no-reply@blockchaintp.com") are applied when the corresponding
     flags are omitted.
  4. Non-`incident` `-i` values trigger `error::exit` with the
     documented message.
  5. A non-zero return from the stubbed send propagates as
     `Failed to send incident` and a non-zero exit code.

The stub seam reserves pagerduty.sh's @include dedup guard before
sourcing the entry script, then in-process `pagerduty::send_incident`
records argv to a log file. exec::hide is reused as-is. No production
change to bash/pagerduty-alert was required.
SUR-2844 proposed that `describe_pods` creates an unused
`$out_dir_ns/pod` directory that ships empty inside every collected
support tarball. Investigation showed the premise is incorrect.

`k8s::get_pod_names` wraps `kubectl get pods -o name`, which emits
names in the `pod/<name>` form. The subsequent redirect

    k8s::describe -n "$ns" "$pod" >"${out_dir_ns}/${pod}.describe"

therefore expands to `${out_dir_ns}/pod/<name>.describe` — files DO
land under `pod/`, and the `dirs::ensure "$out_dir_ns/pod"` is needed
for the redirect's parent dir to exist. Removing it (per the issue's
suggested option a) causes the redirect to fail with "No such file or
directory" and the collector misses every pod's describe output.

This commit makes that constraint explicit in a comment so a future
"cleanup" PR cannot regress this code path. No behavioural change.
@scealiontach scealiontach marked this pull request as ready for review May 13, 2026 07:24
@scealiontach scealiontach merged commit 6224ffa into main May 13, 2026
3 checks passed
@scealiontach scealiontach deleted the sprint/2026-05-13-sprint-loop-42 branch May 13, 2026 07:27
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