Skip to content

[Sprint] sprint-loop-29 - #25

Merged
scealiontach merged 1 commit into
mainfrom
sprint/2026-04-30-sprint-loop-29
May 1, 2026
Merged

scealiontach merged 1 commit into
mainfrom
sprint/2026-04-30-sprint-loop-29

Conversation

@scealiontach

Copy link
Copy Markdown
Owner

Sprint plan — 2026-04-30 — sprint-loop-29

Sprint goal

Strengthen the SUR-1874 check-no-bare-ret pre-commit hook so its brace-tracking matches real bash structure: nested { ... } groups must not reset “inside function” state, eliminating the false-negative path where a bare ret=$?-style capture after a closing } in a brace group is missed. Align implementation with the hook’s stated enforcement boundary (and the issue’s preferred “option 1” scope) without expanding to a full AST or shellcheck-plugin solution this sprint.

Selected issues

SUR-1936 — Anti-pattern: check-no-bare-ret hook resets state on bare } lines, missing captures inside nested brace groups

  • Linear issue ID: SUR-1936
  • Title: Anti-pattern: check-no-bare-ret hook resets state on bare } lines, missing captures inside nested brace groups
  • Description summary: The hook treats any line that is only } as leaving a function, but bash allows { ... } groups inside functions, so in_function and locals are cleared too early and bare captures of $? after the inner } are not flagged. A secondary fragility is regex-based function detection (name() vs real function defs). File: tests/check-no-bare-ret.sh (lines called out ~38–72). Suggested fixes ordered by effort: (1) track brace depth and only reset when depth returns to zero, (2) shfmt/JSON AST, (3) shellcheck-level rule. Option 1 is explicitly the smallest targeted fix.
  • Rationale: Pre-commit hooks that claim a bug class is “impossible to re-introduce” should match that guarantee; the current scanner is structurally loose. Option 1 closes the nested-brace false-negative with minimal churn and keeps the hook dependency-free.
  • Definition of Done:
    • Brace depth (or equivalent) is tracked per file scan so an inner } does not clear function context while the outer function body continues.
    • locals / in_function semantics remain correct for existing patterns (function entry/exit, local lines, capture detection).
    • Header/comment claims in tests/check-no-bare-ret.sh are consistent with actual behavior (no overstated guarantees).
    • Automated tests cover at least one nested { ... } fixture where a bare capture after the inner } must be reported, and a control case with local still passes.
    • pre-commit hook check-no-bare-ret still runs successfully on the repo’s bash libraries.
    • No regressions for SUR-1874-related naming (ret, exit_code, exit_status, rc).
  • Dependencies / ordering: None (no Linear blockers, no open sub-issues). Implement depth tracking before adjusting any optional follow-up on FUNC_DEF_PAT if time permits.

Risks + mitigations

Risk Mitigation
Depth counting mishandles } inside strings, comments, or here-docs Prefer conservative heuristics aligned with issue scope; add fixtures mirroring real bash/ style; extend tests with quoted edge cases if discovered.
False positives on legitimate }-only lines at true function end Pair depth with function-entry detection so depth 0 + } still exits the function as today.
Regex FUNC_DEF_PAT still brittle for rare name() shapes Issue defers deeper fixes; document known limits or add one narrow test if changing regex.
Backlog capacity: only one shell-scripts Backlog issue existed at planning time Single-issue sprint is coherent; next planning cycle should refresh Backlog or pull from Triage when ready.

Out of scope

  • Replacing the scanner with shfmt -tojson + jq or a shellcheck plugin (options 2–3 in the issue).
  • Changes to unrelated hooks or library SUR-1874 call sites beyond what the hook must scan.
  • Issues outside project shell-scripts or team Surinis.

Linear Evidence

  • Linear team verified: Surinis (ce9ebfde-ff2b-4f54-90f1-c388591ca110, key SUR)
  • Linear project used: shell-scripts (a43901a0-b02b-4009-aae1-a6e8903d127d)
  • Query/filter used: list_issues with team=Surinis, project=shell-scripts, state=Backlog, includeArchived=false, limit=250; per-issue get_issue with includeRelations=true; list_issues with parentId=SUR-1936 for sub-issue check; list_comments on selected issue.
  • Approx count of Backlog issues reviewed: 1
  • Approx count of manual-labelled Backlog issues skipped: 0
  • Issues skipped due to unmerged blockers: 0 — []
  • Issues skipped due to open-PR file overlap: 0 — [] (open PR file list was empty)

Sub-issue status

No selected issues have sub-issues in Linear. SUR-1936 has zero child issues; no parent was deferred for incomplete sub-work.

Parent Issue Sub-issue Sub-issue Status Eligible?
— — — —

Linear state transitions

Issue ID Previous State New State
SUR-1936 Backlog Todo

@scealiontach
scealiontach marked this pull request as ready for review April 30, 2026 23:40
test(SUR-1936): check-no-bare-ret fixtures; exclude fixture dir in pre-commit

test(SUR-1936): add bats spec for check-no-bare-ret hook

fix(tests): treat '#' as comment only at start-of-token in check-no-bare-ret

The hook's `apply_line_braces` parser unconditionally treated '#' as a
comment-start, which is wrong inside parameter expansions like
${var#prefix}, ${var##prefix}, and ${#var}. When such an expansion
appeared in a function body before its closing '}', the parser broke at
'#' and never decremented for the matching '}', leaving fn_body_depth
one higher than it should be. A subsequent function-close '}' then left
the hook still considering itself in-function, and any later top-level
bare capture (`ret=$?` etc.) was wrongly flagged.

In bash, '#' starts a comment only at start-of-token (start of line or
after whitespace). Restrict the comment-break to that condition so
parameter expansions parse cleanly. Add a fixture using *unquoted*
${var#…} / ${var##…} / ${#var} forms (the bug only fires in the bare
`norm` state — inside double-quotes the parser already skipped '#'),
followed by a top-level capture, plus a bats case asserting the live
hook accepts the fixture.
@scealiontach
scealiontach force-pushed the sprint/2026-04-30-sprint-loop-29 branch from 89e5d8b to 07f115d Compare April 30, 2026 23:59
@scealiontach
scealiontach merged commit bd973a4 into main May 1, 2026
3 checks passed
@scealiontach
scealiontach deleted the sprint/2026-04-30-sprint-loop-29 branch May 1, 2026 00:00
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