Skip to content

feat(standards): name what failed, not just that something did - #176

Merged
twistedmelonman merged 1 commit into
mainfrom
claude/feat-standards-name-failures-8a854048
Sep 25, 2026
Merged

twistedmelonman merged 1 commit into
mainfrom
claude/feat-standards-name-failures-8a854048

Conversation

@twistedmelonman

Copy link
Copy Markdown
Member

What

A failed standards check now says which linter failed and what it found. Before this, the check printed "shellcheck found problems" and then "N linter(s) failed". Neither line named the rule or the file.

standards/run-standards.sh keeps a copy of each linter's output as it streams. When a linter fails, the script:

  1. Adds the first 20 lines of that linter's findings to its ::error title=<linter>:: annotation. The check's annotation list then shows the rule and the file.
  2. Ends with ::error::standards-check failed: shellcheck, markdownlint (it lists every linter that failed).
  3. When GITHUB_STEP_SUMMARY is set, writes each failed linter's output to the run summary, up to 200 lines each. A clean run writes nothing there.

Exit codes and the streamed log are unchanged.

Tests

New cases in tests/test-run-standards.sh. The first three fail on main (known-bad):

  • final error line names the failed linter
  • per-linter annotation carries the finding (SC2086)
  • step summary names the failed linter and its finding
  • clean run writes no failure section to the step summary (a guard, so a green run never lists "failures")

bash tests/run-tests.sh: 21 passed, 0 failed. shellcheck -S info is clean.

The tag stays where it is

Fleet callers pin @standards-check-v1, and the workflow checks out standards/ at job.workflow_sha. So until that tag moves, callers keep running the old script. This PR changes main only. Retagging standards-check-v1 is a separate decision for a human. This PR does not move it.

self-standards-check.yml calls the workflow locally, so this PR's own CI runs the new script.

What's left

The symptom in dev-env#113 is gpush's line CI failed (Standards Check: failure), which comes from dotfiles/bash/gpush-wrapper.sh. This PR doesn't touch gpush. For gpush to show the findings, it would need to print the failing run's annotations or its URL. That is a separate dotfiles change. So this PR advances the issue but doesn't close it.

Advances smartwatermelon/dev-env#113

A red standards check said "shellcheck found problems" and, at the end,
"N linter(s) failed". Neither named the rule or the file, so finding the
cause meant opening the raw job log.

run-standards.sh now captures each linter's output as it streams and, on
failure:

- annotates the linter with the first 20 lines of its findings, so the
  check's annotation list shows the rule and file;
- ends with "standards-check failed: <linter>, <linter>";
- when GITHUB_STEP_SUMMARY is set, writes each failed linter's output
  (first 200 lines) to the run summary. A clean run writes nothing there.

Exit codes and the streamed log are unchanged.

Callers pin the standards-check-v1 tag, which still points at the old
script. They see none of this until the tag moves, and moving it is a
separate decision.

Advances smartwatermelon/dev-env#113
@claude

claude Bot commented Sep 25, 2026

Copy link
Copy Markdown

The PR replaces the simple failures counter and _fail helper with a failed[] array, a _lint wrapper that captures linter output via tee, and richer annotation/summary output.

No BLOCK criteria are present:

  • The _lint pipeline correctly relies on pipefail (documented in the comment at the change site) — linter failure propagates through the pipeline to the if branch.
  • config_dir paths passed to linters inside the cd "${repo}" subshell are absolute (they were already used inside subshells for every other linter before this PR), so the node-floor invocation change in working directory is safe.
  • _annotation_escape handles %, CR, LF before inserting linter output into a workflow command; linter names in title= are hardcoded strings, not user-controlled.
  • out_dir is properly cleaned up via trap ... EXIT.
  • Exit logic ((${#failed[@]} > 0)) is a correct replacement for ((failures > 0)).

VERDICT: PASS

@twistedmelonman
twistedmelonman merged commit d1a52ec into main Sep 25, 2026
3 checks passed
@twistedmelonman
twistedmelonman deleted the claude/feat-standards-name-failures-8a854048 branch September 25, 2026 16:06
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