Skip to content

Add SARIF-based lint regression ratchet - #287

Draft
gtbuchanan wants to merge 16 commits into
mainfrom
issue-38-lint-regression-sarif
Draft

Add SARIF-based lint regression ratchet#287
gtbuchanan wants to merge 16 commits into
mainfrom
issue-38-lint-regression-sarif

Conversation

@gtbuchanan

Copy link
Copy Markdown
Owner

Closes #38.

Implements the lint regression gate with SARIF baselining (the standard + sarif-multitool the issue's follow-up comment pointed at) instead of a hand-rolled cross-ref diff: fingerprint/content-based matching absorbs line shifts natively, so there's no git-diff offset math anywhere.

Design

Lint enforcement becomes a ratchet — PRs may not introduce new findings, while pre-existing (accepted) ones never block:

  • Reporters, not gates. lint:eslint drops --max-warnings=0 and writes dist/sarif/eslint.sarif via a bundled formatter (compact console output preserved). Warnings never fail it; fatals still do. The layout is tool-agnostic: any reporter that drops a <tool>.sarif into dist/sarif/ is gated with no extra wiring.
  • gtb sarif compare is the gate. Pairs every dist/sarif/*.sarif with dist/sarif/base/<name>.sarif and classifies via sarif-multitool match-results-forward, failing only on new results. A missing baseline counts as an empty baseline (all findings new — a new reporter or the bootstrap PR can't slip findings in silently), and findings with reasoned in-source suppressions are exempt (the suppression is already the accepted mechanism).
  • Self-sufficient baseline production. --base <ref> (local: merge-base semantics) or --base-sha <sha> (CI: the PR merge ref's first parent, which is the merge base of the merged checkout — no history fetch needed, fetch-depth: 2 suffices) lints the baseline commit in a throwaway git worktree. A stamp (dist/sarif/base.ref) skips production when baselines are current; missing commits are fetched by SHA at depth 1, so shallow clones work.
  • Caching + seeding. PR runs restore baselines from actions/cache keyed on the baseline SHA; release.yml seeds the cache cross-PR from every main commit via gtb sarif baseline (merge base == HEAD there, so it's a pure file copy of the commit's own reporter output).
  • Local parity. The changed-file pre-commit ESLint step and IDE remain the authoring-time gates; gtb sarif compare --base origin/main gives the full ratchet verdict locally (~seconds when the stamp is warm).

Acceptance model

Routine response to new findings: fix them, or suppress in-source with a reason (gate-exempt, stays visible in the logs). The accepted-lint-regression label is the escape hatch for bulk introductions (e.g. a dependency bump shipping a new rule, where per-instance suppression is noise and disabling the rule would let new violations creep in while off): apply the label, re-run the failed job. Labels are read live (re-runs replay stale payloads), dismissed on every push and on reopen, and honored only when applied by someone with the override-role (default maintain) — GitHub has no per-label permission rules, so the workflow implements its own.

Rollout (post-merge)

  • Create the accepted-lint-regression label
  • After the first runs register the checks, add Lint Regression (PR) to required checks; Lint Baseline Seed runs on main pushes
  • The bootstrap state resolves itself: the first main push after merge seeds the baseline cache; PRs opened before that pay one worktree production

Follow-ups (non-blocking)

  • Normalize formatter URIs to repo-relative (current absolute-URI matching works because baseline/current are always produced under identical paths — true, but fragile-by-coincidence)
  • gtb-build-pipeline skill + README coverage of the sarif command family
  • E2E coverage for the --base/--base-sha worktree flows (unit-covered today)
  • Optional hk pre-push step running the compare, if manual local runs prove insufficient

🤖 Generated with Claude Code

gtbuchanan and others added 7 commits July 18, 2026 15:49
Lay the CLI groundwork for the #38 lint regression gate:

- lint:eslint loads a bundled wrapper formatter that writes
  dist/eslint.sarif (via @microsoft/eslint-formatter-sarif) and
  returns compact console output; the file is a turbo task output
  so cached runs restore it
- gtb lint:eslint:compare walks each lint cwd, runs sarif-multitool
  match-results-forward against dist/eslint-base.sarif, and fails
  only on results the baseliner classifies as new — fingerprint and
  content-based matching absorbs line shifts without any git-diff
  offset math
- a pnpm override drops the formatter package''s wrongly-declared
  eslint v8 dependency, whose bin otherwise shadows the workspace
  ESLint inside packages/cli

CI wiring (base-SHA lint via turbo remote cache, PR comment, label
override) is follow-up work tracked in #38.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
PRs now fail only on lint violations that are new relative to their
merge base; pre-existing (accepted) violations never block.

- lint:eslint drops --max-warnings=0 and becomes a reporter: warnings
  never fail it (fatals still do), so every commit produces a
  cacheable SARIF baseline. Local changed-file enforcement stays in
  the hk pre-commit eslint step and the IDE.
- gtb lint:eslint:compare gains --base <ref>: it lints the merge base
  of that ref and HEAD in a throwaway git worktree to produce the
  baselines itself, so the same invocation works locally and in CI.
  A failing base lint is tolerated (pre-ratchet gtb wrote the SARIF
  log before exiting non-zero), and base commits that predate SARIF
  output just skip, which makes rollout graceful.
- New lint-regression.yml reusable workflow wired into pr.yml: lints
  HEAD, compares against the merge base, posts an idempotent PR
  comment on failure, and honors a maintainer-applied override label
  (dismissed on every new push) as a run-but-neutral acceptance.
- E2E coverage runs the real multitool against fixture SARIF logs.
  Per-test fixtures, not the file-scoped one: two compares sharing a
  project dir race on the matched-output write.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The compare machinery never inspects anything ESLint-specific, so stop
naming it that way, and stop scattering loose artifacts in dist/.

- SARIF artifacts move to a dedicated dist/sarif/ tree: <tool>.sarif
  from reporters, base/<tool>.sarif baselines, matched/<tool>.sarif
  multitool output, and base.ref (the merge-base stamp, root only).
  The compare pairs every dist/sarif/*.sarif with its baseline by
  filename, so a future reporter is gated by dropping a file there.
- Commands become a `gtb sarif` hub (compare/baseline), reserving
  colon names for turbo tasks. `sarif compare --base` skips baseline
  production when the base.ref stamp already records the merge base —
  repeat local runs drop from ~35s to multitool time, and CI restores
  the stamped baselines from an actions/cache keyed on the merge-base
  SHA. release.yml seeds that cache cross-PR from each main commit via
  `gtb sarif baseline` (merge base == HEAD, so the baseline is the
  commit's own reporter output; pure file copy).
- A missing baseline is an empty baseline, not a pass: every finding
  in an unbaselined log is new and needs acceptance, so the bootstrap
  PR and newly added reporters can't slip findings in silently.
  Findings carrying in-source suppressions are exempt — a reasoned
  suppression is already the accepted mechanism — but stay in the
  logs for visibility.
- The multitool won't create its output file's parent directory;
  ensure dist/sarif/matched/ exists before matching.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Replace the full-history checkout (fetch-depth: 0) with the merge-ref
first-parent technique: on the PR merge commit both CI providers check
out, HEAD^1 is the target branch head — which is the merge base of the
merged checkout — so a fetch-depth: 2 checkout resolves it with no
branch fetch and no merge-base computation. A guard fails fast if the
job is not on a two-parent merge ref, where HEAD^1 would silently name
the wrong commit.

- `gtb sarif compare` gains --base-sha <sha> (exact commit, mutually
  exclusive with --base); CI passes `git rev-parse HEAD^1`. Local runs
  keep --base <ref> merge-base semantics, where full history is free.
- Baseline production now ensures the commit exists locally, fetching
  it by SHA at depth 1 when absent — which also fixes local shallow
  clones.
- Cache keys become base-tip SHAs, matching exactly what the
  default-branch seed job stamps, so cross-PR baseline cache hits stop
  depending on the branch being up to date with main.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The Enforce step read labels from the event payload, but a re-run
replays the original payload — so a label applied after the failure
could never take effect, and no automatic path re-evaluated the check
either (label events don't trigger the pipeline, deliberately: that
would rebuild everything on any label change).

Accept flow is now: apply the label, re-run the failed job. Enforce
queries the live label state, so the stale payload doesn't matter.
Dismissal only runs on the first attempt of a synchronize — a re-run
of the replayed push event must not strip a label applied after it —
and skips fork PRs, whose read-only token can't edit labels (their
labels are still honored on re-runs, which only read). The PR comment
now spells out the label + re-run ceremony.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
GitHub has no per-label permission rules — anyone with triage can
apply any label, and a PR author with write could self-accept their
own regressions. The Enforce step now resolves the label's most
recent applier from the issue events API and honors it only when
their repository role meets the new `override-role` input (default
`maintain`, so ordinary committers can't self-accept); unresolvable
appliers or roles fail closed.

Also reframe the docs and PR comment: the routine response to new
findings is fixing or suppressing them in-source (suppressed findings
are already gate-exempt); the label is the escape hatch for bulk
introductions like a dependency bump shipping a new rule, where
per-instance suppression is noise and disabling the rule would let
new violations creep in while it's off.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Labels survive PR closure, and pushes to a closed PR emit no
synchronize events — so a reopened head may have moved under a stale
label with nothing dismissing it. Treat reopened like synchronize in
both the dismissal step and Enforce: the label is dropped and
discounted on the first attempt, so acceptance always postdates the
code it vouches for. Also record the known residual: cancelling a run
before its dismissal step and re-running preserves a stale label,
which needs write access and deliberate timing.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jul 21, 2026

Copy link
Copy Markdown

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: d6cb9ebc-3c4e-4f18-98f4-b30bb34762ca

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

Copy link
Copy Markdown

Dependency Review

The following issues were found:
  • ✅ 0 vulnerable package(s)
  • ❌ 1 package(s) with incompatible licenses
  • ✅ 0 package(s) with invalid SPDX license definitions
  • ⚠️ 5 package(s) with unknown licenses.
  • ⚠️ 1 packages with OpenSSF Scorecard issues.
See the Details below.

License Issues

pnpm-lock.yaml

PackageVersionLicenseIssue Type
jschardet3.1.4LGPL-2.1-or-laterIncompatible License

.github/workflows/lint-regression.yml

PackageVersionLicenseIssue Type
actions/cache6.*.*NullUnknown License
actions/cache/save6.*.*NullUnknown License
actions/checkout7.*.*NullUnknown License

packages/cli/package.json

PackageVersionLicenseIssue Type
@microsoft/eslint-formatter-sarifcatalog:NullUnknown License
@microsoft/sarif-multitoolcatalog:NullUnknown License
Allowed Licenses: 0BSD, Apache-2.0, BlueOak-1.0.0, BSD-2-Clause, BSD-3-Clause, CC-BY-3.0, CC-BY-4.0, CC0-1.0, ISC, MIT, Python-2.0, Unlicense
Excluded from license check: pkg:npm/lightningcss, pkg:npm/lightningcss-android-arm64, pkg:npm/lightningcss-darwin-arm64, pkg:npm/lightningcss-darwin-x64, pkg:npm/lightningcss-freebsd-x64, pkg:npm/lightningcss-linux-arm-gnueabihf, pkg:npm/lightningcss-linux-arm64-gnu, pkg:npm/lightningcss-linux-arm64-musl, pkg:npm/lightningcss-linux-x64-gnu, pkg:npm/lightningcss-linux-x64-musl, pkg:npm/lightningcss-win32-arm64-msvc, pkg:npm/lightningcss-win32-x64-msvc

OpenSSF Scorecard

Scorecard details
PackageVersionScoreDetails
actions/actions/cache 6.*.* 🟢 6.4
Details
CheckScoreReason
Code-Review🟢 10all changesets reviewed
Maintained🟢 1013 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10
Packaging⚠️ -1packaging workflow not detected
Binary-Artifacts🟢 10no binaries found in the repo
Dangerous-Workflow🟢 10no dangerous workflow patterns detected
CII-Best-Practices⚠️ 0no effort to earn an OpenSSF best practices badge detected
Token-Permissions⚠️ 0detected GitHub workflow tokens with excessive permissions
Pinned-Dependencies🟢 3dependency not pinned by hash detected -- score normalized to 3
Fuzzing⚠️ 0project is not fuzzed
License🟢 10license file detected
Signed-Releases⚠️ -1no releases found
Security-Policy🟢 9security policy file detected
SAST🟢 10SAST tool is run on all commits
Branch-Protection⚠️ 1branch protection is not maximal on development and all release branches
actions/actions/cache/save 6.*.* 🟢 6.4
Details
CheckScoreReason
Code-Review🟢 10all changesets reviewed
Maintained🟢 1013 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10
Packaging⚠️ -1packaging workflow not detected
Binary-Artifacts🟢 10no binaries found in the repo
Dangerous-Workflow🟢 10no dangerous workflow patterns detected
CII-Best-Practices⚠️ 0no effort to earn an OpenSSF best practices badge detected
Token-Permissions⚠️ 0detected GitHub workflow tokens with excessive permissions
Pinned-Dependencies🟢 3dependency not pinned by hash detected -- score normalized to 3
Fuzzing⚠️ 0project is not fuzzed
License🟢 10license file detected
Signed-Releases⚠️ -1no releases found
Security-Policy🟢 9security policy file detected
SAST🟢 10SAST tool is run on all commits
Branch-Protection⚠️ 1branch protection is not maximal on development and all release branches
actions/actions/checkout 7.*.* 🟢 6.9
Details
CheckScoreReason
Maintained🟢 1024 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10
Code-Review🟢 10all changesets reviewed
Dangerous-Workflow🟢 10no dangerous workflow patterns detected
Binary-Artifacts🟢 10no binaries found in the repo
Token-Permissions⚠️ 0detected GitHub workflow tokens with excessive permissions
CII-Best-Practices⚠️ 0no effort to earn an OpenSSF best practices badge detected
License🟢 10license file detected
Fuzzing⚠️ 0project is not fuzzed
Packaging⚠️ -1packaging workflow not detected
Pinned-Dependencies🟢 3dependency not pinned by hash detected -- score normalized to 3
Signed-Releases⚠️ -1no releases found
Security-Policy🟢 9security policy file detected
SAST🟢 10SAST tool is run on all commits
Branch-Protection🟢 5branch protection is not maximal on development and all release branches
actions/gtbuchanan/tooling/.github/actions/mise-setup main UnknownUnknown
actions/gtbuchanan/tooling/.github/actions/pnpm-tasks main UnknownUnknown
npm/@microsoft/eslint-formatter-sarif catalog: UnknownUnknown
npm/@microsoft/sarif-multitool catalog: UnknownUnknown
npm/@microsoft/eslint-formatter-sarif 3.1.0 🟢 5.8
Details
CheckScoreReason
Maintained⚠️ 00 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0
Code-Review🟢 10all changesets reviewed
Binary-Artifacts🟢 10no binaries found in the repo
Packaging⚠️ -1packaging workflow not detected
Dangerous-Workflow🟢 10no dangerous workflow patterns detected
CII-Best-Practices⚠️ 0no effort to earn an OpenSSF best practices badge detected
Security-Policy🟢 10security policy file detected
Token-Permissions⚠️ 0detected GitHub workflow tokens with excessive permissions
Pinned-Dependencies⚠️ 0dependency not pinned by hash detected -- score normalized to 0
Fuzzing⚠️ 0project is not fuzzed
License🟢 10license file detected
Signed-Releases⚠️ -1no releases found
Branch-Protection🟢 8branch protection is not maximal on development and all release branches
SAST🟢 7SAST tool detected but not run on all commits
npm/@microsoft/sarif-multitool 5.5.0 🟢 7.6
Details
CheckScoreReason
Code-Review🟢 10all last 30 commits are reviewed through GitHub
Maintained🟢 1014 commit(s) out of 30 and 13 issue activity out of 30 found in the last 90 days -- score normalized to 10
CII-Best-Practices⚠️ 0no badge detected
Vulnerabilities🟢 10no vulnerabilities detected
Signed-Releases⚠️ -1no releases found
Branch-Protection🟢 8branch protection is not maximal on development and all release branches
License🟢 10license file detected
Dangerous-Workflow🟢 10no dangerous workflow patterns detected
Packaging⚠️ -1no published package detected
Token-Permissions⚠️ 0non read-only tokens detected in GitHub workflows
Pinned-Dependencies🟢 7dependency not pinned by hash detected -- score normalized to 7
Security-Policy🟢 10security policy file detected
Fuzzing⚠️ 0project is not fuzzed
Binary-Artifacts🟢 8binaries present in source code
Dependency-Update-Tool🟢 10update tool detected
npm/@microsoft/sarif-multitool-darwin 5.5.0 🟢 7.6
Details
CheckScoreReason
Code-Review🟢 10all last 30 commits are reviewed through GitHub
Maintained🟢 1014 commit(s) out of 30 and 13 issue activity out of 30 found in the last 90 days -- score normalized to 10
CII-Best-Practices⚠️ 0no badge detected
Vulnerabilities🟢 10no vulnerabilities detected
Signed-Releases⚠️ -1no releases found
Branch-Protection🟢 8branch protection is not maximal on development and all release branches
License🟢 10license file detected
Dangerous-Workflow🟢 10no dangerous workflow patterns detected
Packaging⚠️ -1no published package detected
Token-Permissions⚠️ 0non read-only tokens detected in GitHub workflows
Pinned-Dependencies🟢 7dependency not pinned by hash detected -- score normalized to 7
Security-Policy🟢 10security policy file detected
Fuzzing⚠️ 0project is not fuzzed
Binary-Artifacts🟢 8binaries present in source code
Dependency-Update-Tool🟢 10update tool detected
npm/@microsoft/sarif-multitool-linux 5.5.0 🟢 7.6
Details
CheckScoreReason
Code-Review🟢 10all last 30 commits are reviewed through GitHub
Maintained🟢 1014 commit(s) out of 30 and 13 issue activity out of 30 found in the last 90 days -- score normalized to 10
CII-Best-Practices⚠️ 0no badge detected
Vulnerabilities🟢 10no vulnerabilities detected
Signed-Releases⚠️ -1no releases found
Branch-Protection🟢 8branch protection is not maximal on development and all release branches
License🟢 10license file detected
Dangerous-Workflow🟢 10no dangerous workflow patterns detected
Packaging⚠️ -1no published package detected
Token-Permissions⚠️ 0non read-only tokens detected in GitHub workflows
Pinned-Dependencies🟢 7dependency not pinned by hash detected -- score normalized to 7
Security-Policy🟢 10security policy file detected
Fuzzing⚠️ 0project is not fuzzed
Binary-Artifacts🟢 8binaries present in source code
Dependency-Update-Tool🟢 10update tool detected
npm/@microsoft/sarif-multitool-win32 5.5.0 🟢 7.6
Details
CheckScoreReason
Code-Review🟢 10all last 30 commits are reviewed through GitHub
Maintained🟢 1014 commit(s) out of 30 and 13 issue activity out of 30 found in the last 90 days -- score normalized to 10
CII-Best-Practices⚠️ 0no badge detected
Vulnerabilities🟢 10no vulnerabilities detected
Signed-Releases⚠️ -1no releases found
Branch-Protection🟢 8branch protection is not maximal on development and all release branches
License🟢 10license file detected
Dangerous-Workflow🟢 10no dangerous workflow patterns detected
Packaging⚠️ -1no published package detected
Token-Permissions⚠️ 0non read-only tokens detected in GitHub workflows
Pinned-Dependencies🟢 7dependency not pinned by hash detected -- score normalized to 7
Security-Policy🟢 10security policy file detected
Fuzzing⚠️ 0project is not fuzzed
Binary-Artifacts🟢 8binaries present in source code
Dependency-Update-Tool🟢 10update tool detected
npm/jschardet 3.1.4 🟢 4
Details
CheckScoreReason
Packaging⚠️ -1packaging workflow not detected
Code-Review⚠️ 1Found 3/25 approved changesets -- score normalized to 1
Token-Permissions⚠️ 0detected GitHub workflow tokens with excessive permissions
Maintained🟢 1010 commit(s) and 17 issue activity found in the last 90 days -- score normalized to 10
Dangerous-Workflow🟢 10no dangerous workflow patterns detected
Binary-Artifacts🟢 10no binaries found in the repo
CII-Best-Practices⚠️ 0no effort to earn an OpenSSF best practices badge detected
Pinned-Dependencies⚠️ 2dependency not pinned by hash detected -- score normalized to 2
Security-Policy⚠️ 0security policy file not detected
License🟢 10license file detected
Signed-Releases⚠️ -1no releases found
Branch-Protection⚠️ 0branch protection not enabled on development/release branches
Fuzzing⚠️ 0project is not fuzzed
SAST⚠️ 0SAST tool is not run on all commits -- score normalized to 0
npm/lodash 4.18.1 🟢 7.2
Details
CheckScoreReason
Binary-Artifacts🟢 10no binaries found in the repo
Branch-Protection⚠️ -1internal error: error during branchesHandler.setup: internal error: githubv4.Query: Resource not accessible by integration
CI-Tests🟢 822 out of 25 merged PRs checked by a CI test -- score normalized to 8
CII-Best-Practices⚠️ 0no effort to earn an OpenSSF best practices badge detected
Code-Review🟢 7Found 22/30 approved changesets -- score normalized to 7
Contributors🟢 10project has 90 contributing companies or organizations
Dangerous-Workflow🟢 10no dangerous workflow patterns detected
Dependency-Update-Tool🟢 10update tool detected
Fuzzing🟢 10project is fuzzed
License🟢 9license file detected
Maintained🟢 109 commit(s) and 7 issue activity found in the last 90 days -- score normalized to 10
Packaging⚠️ -1packaging workflow not detected
Pinned-Dependencies🟢 4dependency not pinned by hash detected -- score normalized to 4
SAST🟢 9SAST tool detected but not run on all commits
Security-Policy🟢 10security policy file detected
Signed-Releases⚠️ -1no releases found
Token-Permissions⚠️ 0detected GitHub workflow tokens with excessive permissions
Vulnerabilities⚠️ 0104 existing vulnerabilities detected
npm/utf8 3.0.0 ⚠️ 2
Details
CheckScoreReason
Code-Review⚠️ 0Found 0/28 approved changesets -- score normalized to 0
Packaging⚠️ -1packaging workflow not detected
Pinned-Dependencies⚠️ -1no dependencies found
Binary-Artifacts🟢 10no binaries found in the repo
Maintained⚠️ 00 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0
Token-Permissions⚠️ -1No tokens found
SAST⚠️ 0no SAST tool detected
Dangerous-Workflow⚠️ -1no workflows found
CII-Best-Practices⚠️ 0no effort to earn an OpenSSF best practices badge detected
Security-Policy⚠️ 0security policy file not detected
Fuzzing⚠️ 0project is not fuzzed
License🟢 10license file detected
Signed-Releases⚠️ -1no releases found
Branch-Protection⚠️ 0branch protection not enabled on development/release branches

Scanned Files

  • .github/workflows/lint-regression.yml
  • packages/cli/package.json
  • pnpm-lock.yaml

Two packaging consequences of the new SARIF dependencies surfaced on
the first PR run:

- pnpm blocks the multitool platform packages' build scripts (they
  chmod the bundled self-contained binary), failing every job at
  install on Linux. Allow all three; entries are consulted only when
  a script exists, so the scriptless win32 one is inert.
- jschardet (LGPL-2.1-or-later) rides in via the formatter's
  SARIF_ESLINT_EMBED feature, which the lint pipeline never enables.
  Every consumer of @gtbuchanan/cli inherits it, so the name-scoped
  exception belongs in the shared dependency-review config — same
  pattern as the lightningcss MPL carve-out. Retire it if sarif-sdk
  makes the embed deps optional.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@codecov-commenter

codecov-commenter commented Jul 21, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 93.03797% with 11 lines in your changes missing coverage. Please review.
✅ Project coverage is 84.26%. Comparing base (feae032) to head (a4d9a91).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
packages/cli/src/commands/root/sarif.ts 0.00% 5 Missing ⚠️
packages/cli/src/lib/sarif-compare.ts 96.96% 0 Missing and 4 partials ⚠️
packages/cli/src/commands/task/lint-eslint.ts 0.00% 1 Missing ⚠️
packages/cli/src/lib/eslint-sarif-formatter.ts 94.44% 0 Missing and 1 partial ⚠️

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

gtbuchanan and others added 8 commits July 21, 2026 12:37
actionlint's shellcheck pass flags `${{ }}` inside single-quoted
script strings (SC2016) — only on Linux, since the shared preset
disables shellcheck under actionlint on Windows, which is why local
pre-commit missed it. Env-var passing is the safer pattern anyway:
the label value never touches shell parsing.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Codecov flagged the real I/O layer as untested: the unit suites
inject stubs and the e2e suites collect no source coverage by
convention. Export the default deps and test each closure against a
temp sandbox (list filtering, recursive removal, mkdir-before-write,
multitool resolution, single-package workspace fallback), and test
the formatter's SARIF write end to end. The formatter now resolves
its output under the ESLint-provided context cwd instead of the
process cwd — what it should have done anyway, and what makes the
write testable without cwd games. The citty command wrappers stay
uncovered like every other command file: they only delegate to the
tested executors.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The changeset recapped the full architecture; the deep detail lives in
AGENTS.md and the README. Keep only what a consumer reading the
CHANGELOG needs.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
With both modes in lint-regression.yml behind a seed input, every PR
run showed a permanently skipped Lint Baseline Seed job and every
release run a skipped Lint Regression job. A dedicated lint-baseline
reusable removes the skipped peers; release.yml calls it directly.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The PR-comment report could go stale after a green re-run (nothing
edited it) and gh's --edit-last targets the bot's last comment, which
another workflow (dependency review) may own. A job summary is pinned
to its run, so neither failure mode exists, and it needs no write
token, so fork PRs get the full report too.

Also fail the merge-ref guard with an explicit ::error:: instead of
git's bare "Needed a single revision", and remove the seed job now
that lint-baseline.yml owns seeding.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The duplicated 'internal' literal covers ESLint's null ruleId (fatal
parse/config errors); hoist it into a shared, documented module. Also
record why formatConsole is hand-rolled (ESLint v9 exposes no
importable formatter, and the line shape matches the compare report)
and that the baseline worktree bootstrap assumes a node-only lint
graph (mise never activates outside the repo).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The ratchet documentation lived only in AGENTS.md while the README --
the consumer-facing surface -- never mentioned the new workflows.
README gains the Lint jobs in both pipeline examples, the reusables
table rows, and a lint regression section (ratchet semantics, override
label flow, inputs, permissions). AGENTS.md keeps a condensed section
scoped to the invariants agents need and points to the README for
usage; its workflow bullets now reflect the job-summary report and the
lint-baseline split.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Only pnpm-lock.yaml conflicted; regenerated via pnpm install (which
merges the lockfile from the combined manifests). Everything else
auto-merged; build and gtb verify pass on the result.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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.

Add CI lint regression check via cross-ref ESLint diff

2 participants