Repository navigation
Description
Problem
Script hygiene is still enforced by shell discovery, textual checks and structural-checker result handling. The boundaries are tools/check-script-hygiene.sh:56, tools/check-script-hygiene.sh:92, tools/check-script-hygiene.sh:112 and tools/check-script-hygiene.sh:137, on origin/main at a0347a715fab580ece45edfcb3d13509620459a8. Discovery and diagnostic-processing failures already have regression coverage and must not become a clean gate during the port.
This is the script-hygiene split of #332. Part of #588.
Acceptance criteria
- AC1: Default discovery checks the frozen command's owned scripts and local-only skill scripts, including nonignored untracked files and excluding duplicate deployed mirrors.
- AC2: Explicit-file checks preserve the frozen command's file selection, missing-file skips and reasoned hygiene-exemption behavior.
- AC3: Each checked script receives the same locale-pin and GitHub-retargeting findings as the frozen command.
- AC4: Structural findings retain the current rule decisions, path, one-based line, rule ID and message.
- AC5: Findings retain the frozen command's ordering, formatting, total and exit status, with silence on a clean run.
- AC6: Failed discovery, an unusable structural-checker result or failed diagnostic processing produces failure rather than a clean verdict, including when partial output was returned.
- AC7: Non-functional: running the hygiene check changes no repository content or Git state.
- AC8: Existing entry points end as thin shell wrappers that probe the Go subcommand without side effects and use frozen shell only when that capability is absent.
- AC9: A supported Go failure never invokes shell fallback or repeats a check to obtain success.
- AC10: Non-functional: release N-2 invocations retain their findings and behavior without requiring configuration changes or a raised binary floor.
- AC11: Equivalent inputs produce the same diagnostics on supported Linux, macOS and Windows environments.
Scope and non-goals
Preserve both default discovery sets, explicit targets, non-file skips and the whole-file hygiene-exempt opt-out (tools/check-script-hygiene.sh:62, tools/check-script-hygiene.sh:75, tools/check-script-hygiene.sh:93). Preserve the existing comment filtering and textual command detection, including what the current unset predicate actually recognizes (tools/check-script-hygiene.sh:103, tools/check-script-hygiene.sh:121).
Preserve the existing structural rules: bare Git output commands (.ast-grep/rules/bare-git-output.yml:14), diff without its required flag (.ast-grep/rules/diff-without-no-ext-diff.yml:10), and newline-losing field-separator construction (.ast-grep/rules/ifs-command-substitution.yml:15). Preserve checker statuses 0/1 as ordinary outcomes and statuses above 1 as tool failures with diagnostics; retain file/line sorting and literal message characters (tools/check-script-hygiene.sh:150, tools/check-script-hygiene.sh:160).
The existing failure coverage is tests/tools/masked-status.bats:98. Add the rule and discovery fixtures that this suite does not currently provide.
Non-goals: changing exemptions, adding or weakening rules, replacing the structural rules' semantics, broadening the scripts being checked, or porting unrelated cases in the shared masked-status suite. The fallback remains until a separate D9 follow-up establishes N-2 retirement eligibility.
Approach
Write the discovery and diagnostic-failure regressions first. Move the gate behavior to Go, comparing findings and failure transcripts with the frozen shell over the same fixtures. Keep the existing lint task (mise.toml:442). No new checker design or library is prescribed.
Dependencies
None blocking. The probe-and-fallback wrappers let this split land without waiting for #542, the #333 → #544 → #382 → #545 → #546 chain or the #359 delivery chain. Removing the fallback later waits for #333, #544 and the N-2 window, and is filed as a follow-up. Script hygiene is repository lint tooling, not merge, commit or pull request enforcement, so it does not wait for #753. #332 and #588 track this migration.
Size
S. One pull request for a single gate, its compatibility wrappers and rule-parity coverage.
Verify plan
- AC6: first reproduce both discovery failures and the diagnostic-parser failure at
tests/tools/masked-status.bats:98. Add checker startup/configuration failure, malformed diagnostics and partial output followed by nonzero status; assert failure, diagnostic preservation and no clean result. Check that ordinary checker status 1 still yields findings rather than a tool-failure report. - AC1: fixtures cover packaged scripts, local-only skills, deployed mirrors, tracked and nonignored untracked scripts and ignored files; compare the selected files with frozen shell.
- AC2: explicit targets include a missing file, an ordinary file, and a reasoned exemption; assert that exempt files reach neither rule pass, while nonexempt files without Git/GitHub calls still reach structural checks.
- AC3: shell/Go transcript comparisons cover comments, quoted command text, Git-only scripts, GitHub calls, absent/present locale pins and absent/present unset lines, preserving the current predicates rather than assuming stronger rules.
- AC4: positive and negative fixtures for each of the three structural rules compare rule decisions, literal messages and line numbers, including quoted flag text versus a real argument and harmless field-separator assignment.
- AC5: mixed textual/structural findings across several files compare full stdout, stderr, order, totals and status; a clean fixture is silent.
- AC7: filesystem, index and ref snapshots are unchanged after successful and failed checks; use mutation traps for subprocesses.
- AC8: absent binary and older binary without the capability run the frozen command once with unchanged arguments; verify the capability probe is read-only.
- AC9: supported-command failure, partial-output failure and an indeterminate capability probe all refuse without shell fallback or repetition.
- AC10: run unchanged tasks and direct entry points over the N-2 corpus with absent, older and new binaries; compare findings, streams and statuses.
- AC11: run the Go corpus on Linux, macOS and Windows, retaining wrapper smoke coverage where Bash is supported. Run focused suites,
mise run lintandmise run teston the reviewed head. - Definition of done: D1 each AC is verified at the merged head, with the commands and results cited in the pull request's Verification. D2 an independent review approves the exact merged head, and every finding has a recorded disposition. D3 required checks pass with no gate loosened. D4 the leak scans the repository specifies are clean, and every post made for this work (comments, descriptions) passes the per-post leak review before it is posted. D5 every commit is signed. D6 the documentation matches, or the description says
No doc impactwith the reason. D7 every commit carries anAssisted-bytrailer and the pull request carries theprovenance:agent-assistedlabel. D8 the change stays within the pull request size limits. D9 follow-up work, including deferred review findings, is filed as issues, each with a Problem section and numbered acceptance criteria and linking this issue; the pull request's Related section lists them, and any code that defers work links its issue. D10 the merge closes this issue through a closing reference, the project board shows the state Done, and a finalStatus:comment names the merge commit.
Risks
A discovery omission can hide an unchecked script; a swallowed checker error can report false success. Broader text interpretation can also change current rule decisions. File-selection, rule-parity and failure-first evidence cover these risks. Undo: revert the port.
Operator authority
None.
Metadata
Metadata
Assignees
Labels
Type
Fields
Priority
Work type
Projects
- StatusShow more project fieldsBacklog
Activity
tbhb-agent commentedon Oct 26, 2026
Refinement: READY — script-hygiene Go port requirements, parity checks and rollout boundaries are complete
Model: gemini-4-argon-high
Checked
tbhb-dev/devtools#809(refactor(tools): move script hygiene checks to Go, typeFeature, labelchange:feat, 0 comments) and referenced issues#332,#588,#542,#333,#544,#382,#545,#546,#359and#753againstorigin/mainata0347a715fab580ece45edfcb3d13509620459a8.origin/main:tools/check-script-hygiene.sh:56, owned-scriptgit ls-filesdiscovery attools/check-script-hygiene.sh:62, and.claude/skills/*/scripts/*.shdiscovery filtered bypackaged()(tools/check-script-hygiene.sh:48) attools/check-script-hygiene.sh:75.# hygiene-exempt:handling attools/check-script-hygiene.sh:92andtools/check-script-hygiene.sh:93, comment stripping attools/check-script-hygiene.sh:103,missing-locale-pinrule attools/check-script-hygiene.sh:112, andmissing-gh-unsetrule attools/check-script-hygiene.sh:121.tools/check-script-hygiene.sh:137, exit-status handling (ast_status -gt 1) attools/check-script-hygiene.sh:150, tab-joined diagnostic extraction andfile/linesorting attools/check-script-hygiene.sh:160, and total reporting attools/check-script-hygiene.sh:169..ast-grep/rules/bare-git-output.yml:14,.ast-grep/rules/diff-without-no-ext-diff.yml:10and.ast-grep/rules/ifs-command-substitution.yml:15(configured viasgconfig.yml:9).tests/tools/masked-status.bats:98.mise.toml:442(lint-script-hygiene, invoked fromlintatmise.toml:311).AC1–AC11): each criterion states one observable, testable outcome free of prescribed package layout, internal file structure or library choices, and includes non-functional requirements for read-only execution (AC7), N-2 compatibility (AC10, matchingdocs/compatibility.md:3) and cross-platform parity across Linux, macOS and Windows (AC11, matchingmise.toml:72).AC8,AC9) avoid blocking on#333,#544,#382,#545,#546,#359or#542, with fallback retirement deferred to aD9follow-up after#333,#544and the N-2 window. Becausetools/check-script-hygiene.sh:1is repository lint tooling (mise.toml:442) rather than merge, commit or pull request enforcement (#588,#753),#753does not block#809.AC1–AC11) andD1–D10to concrete, falsifiable checks covering discovery sets, exemptions, textual predicates, all three structural rules, output ordering and totals, failure propagation (including partial output and status> 1vs status1), state-mutation traps, capability-probe fallback and refusal rules, N-2 compatibility and cross-platform execution.Noneis accurate becausetools/check-script-hygiene.shandtests/tools/masked-status.batsdo not matchgolden_paths,constitutional_pathsorowner_pathsin.agents/agent-skills.conf:4,.agents/agent-skills.conf:5and.agents/agent-skills.conf:9, whilemise.toml:442,sgconfig.yml:9and.ast-grep/rules/(gate_config_pathsat.agents/agent-skills.conf:8) remain unchanged.Gaps
None
Split
None — size
Sfits a single pull request covering one script-hygiene gate (tools/check-script-hygiene.sh:1), its thin compatibility wrapper and its Go and Bats parity tests.Definition of done
The definition of done for #809 (Feature). Tick each item and give its evidence. Ticked boxes below record planning coverage in the issue's criteria and verification plan, not completed implementation work.
Verify planmapsAC1–AC11to specific test and transcript checks and requiresD1verification citations on the merged head.Verify plan(Definition of done: D2) requires independent review approval of the exact merged head and recorded dispositions for all findings.Scope and non-goalsforbids weakening rules, andVerify plan(AC11andDefinition of done: D3) requiresmise run lint,mise run testand required checks to pass with no gate loosened.check-leaks.shwith the repository's private-strings list, and the leak review of each post. — Planning coverage:Verify plan(Definition of done: D4) requires clean repository leak scans and per-post leak review before posting.Verify plan(Definition of done: D5) requires every commit to be signed.docs/, CHANGELOG or help text), or the Verification section says "No doc impact" and why. — Planning coverage:Verify plan(Definition of done: D6) requires matching documentation or an explicitNo doc impactjustification.provenance:agent-assistedlabel. — Planning coverage:Verify plan(Definition of done: D7) requiresAssisted-bytrailers on every commit and theprovenance:agent-assistedpull request label.Sizescopes the change toS(one pull request for a single gate, wrapper and parity tests), andVerify plan(Definition of done: D8) requires staying within pull request size limits.Scope and non-goals,DependenciesandVerify plan(Definition of done: D9) require filing fallback retirement and any deferred findings as issues withProblemand numbered acceptance criteria linked underRelated.Status:comment names the merge commit. — Planning coverage:Verify plan(Definition of done: D10) requires a closing reference on merge, board stateDoneand a finalStatus:comment naming the merge commit.Round: 1 of 3