Skip to content

fix(toolchain): gate lint code-fix behind --code-fix - #2652

Merged
kyle-sexton merged 4 commits into
mainfrom
cursor/fix-toolchain-lint-fix-gates-f8b0
Aug 15, 2026
Merged

fix(toolchain): gate lint code-fix behind --code-fix#2652
kyle-sexton merged 4 commits into
mainfrom
cursor/fix-toolchain-lint-fix-gates-f8b0

Conversation

@kyle-sexton

Copy link
Copy Markdown
Contributor

Closes #2649

Summary

Split /toolchain:lint --fix (format-only fix-cmd) from semantic lint autofixes (code-fix-cmd via --code-fix).

Fix

  • --fix → format-only (fix-cmd); no semantic autofixes
  • --code-fixcode-fix-cmd behind plan + confirmation / --yes, with --dry-run and a 40-file scope cap (--all-files override)
  • Bundled defaults: python/go/typescript split; python code-fix uses --unfixable F401 (aligned with ruff-format)
  • Contract 1.3.0 adds optional code-fix-cmd; toolchain 0.13.0

Verification

  • Catalog / cheatsheet --check
  • Changelog parity vs origin/main
  • Plugin manifest validation
  • Invariant: no ruff check --fix / golangci-lint --fix / biome check --write on bundled fix-cmd lines
  • Evals updated for format-only --fix, confirmation stop, and file-cap

Related

Refs #2597 — fleet drain context (new issue claimed during drain).

Open in Web Open in Cursor 

@kyle-sexton
kyle-sexton marked this pull request as ready for review August 15, 2026 01:47
@kyle-sexton
kyle-sexton enabled auto-merge (squash) August 15, 2026 01:47
@cursor

cursor Bot commented Aug 15, 2026

Copy link
Copy Markdown

Bugbot is not enabled for your account, so this pull request was not reviewed.

Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs.

@claude

claude Bot commented Aug 15, 2026

Copy link
Copy Markdown
Contributor

Claude finished @kyle-sexton's task in 1m 4s —— View job


Security review complete ✅

  • Gather context (PR diff, changed files, custom instructions)
  • Run skip-gate check
  • Review diff for security-relevant surface
  • Report findings

No security issues found.

This PR is documentation/skill-instruction and config-only (SKILL.md, reference/ecosystems/*.yaml, schema, changelog/README prose — no executable application code, no CI workflow changes, no auth/access-control paths). It doesn't introduce a new security-relevant surface; it's itself a hardening change:

  • Splits format-only fix-cmd from semantic code-fix-cmd, so bare --fix can no longer run code-changing autofixes (ruff check --fix, golangci-lint --fix, biome check --write) without an explicit opt-in.
  • Adds a confirmation gate for --code-fix: interactive sessions require confirmation (or explicit --yes); non-interactive/headless sessions (CLAUDE_CODE_REMOTE, claude -p, autonomous loops) are hard-stopped after emitting the plan unless --yes is passed — see plugins/toolchain/skills/lint/SKILL.md#L138-L163.
  • Adds a scope fence (40-file cap, --all-files override) to bound the blast radius of an applied code-fix — plugins/toolchain/skills/lint/SKILL.md#L165-L172.

The <files> substitution pattern used in code-fix-cmd/fix-cmd (e.g. plugins/toolchain/reference/ecosystems/python.yaml#L16-L17) is pre-existing behavior carried over unchanged from fix-cmd, not new risk introduced by this PR.

Per the security-review skill's scope, this lane reports security issues only — no style/naming/coverage commentary.

@github-actions

Copy link
Copy Markdown

Last security-reviewed head: bbe337de7153d31aedb71797ff3918186e88a5ed. On the next push, the relevance gate compares only the commits since this SHA; delete this comment to force a full re-review.

@claude

claude Bot commented Aug 15, 2026

Copy link
Copy Markdown
Contributor

Claude finished @kyle-sexton's task in 1m 15s —— View job


Security review — /review:security-review

  • Gather context (PR diff, changed files)
  • Invoke /review:security-review skill and follow its instructions
  • Post findings

Skip gate: PR is open, and the change has no security-relevant surface — no .github/workflows files, no executable application code, no auth/authz, secrets, or injection-relevant runtime paths are touched.

All 20 changed files are Markdown skill instructions, JSON schema, and bundled YAML config for the toolchain plugin's /toolchain:lint command (an LLM-interpreted skill, not executed code). The change:

  • Splits the existing fix-cmd (format-only) from a new optional code-fix-cmd (semantic autofixes), gated behind --code-fix + interactive confirmation / --yes, --dry-run, and a 40-file scope cap (--all-files to override) — see plugins/toolchain/skills/lint/SKILL.md.
  • The <files> placeholder substitution pattern extended here is pre-existing (already used by check-cmd/fix-cmd across ecosystems prior to this PR, per resolution-ladder.md) — not a new surface introduced by this diff, so out of scope per the high-signal bar (pre-existing issues excluded).
  • Net effect is a tightening of blast radius: bare --fix can no longer trigger semantic-rewrite autofixes (ruff check --fix, golangci-lint --fix, biome check --write) — those now require the explicit --code-fix flag plus a human confirmation or --yes/non-interactive consent gate, plus a file-count cap. This mirrors the fleet's existing mutator-confirmation pattern (review:fanout fix, claude-memory:audit).

No CRITICAL, IMPORTANT, or SUGGESTION findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: bbe337de71

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread plugins/toolchain/reference/ecosystems/go.yaml Outdated
Comment thread plugins/toolchain/reference/ecosystems/go.yaml Outdated
@claude

claude Bot commented Aug 15, 2026

Copy link
Copy Markdown
Contributor

Claude finished @kyle-sexton's task in 3m 23s —— View job


Code review complete

  • Gather context (PR diff, CLAUDE.md, REVIEW.md)
  • Check skip gate
  • Review changed files for correctness/maintainability
  • Post findings

Skip gate: PR is open, not draft, and the change (191/-43 across 20 files) has real review surface — proceeded with full review. Root CLAUDE.md is empty in this repo, so REVIEW.md's code-review-lane scope (correctness, design, conventions, error handling, docs; security deferred to the security lane) is what governed this pass.

Summary

This PR splits /toolchain:lint's --fix (format-only) from a new gated --code-fix (semantic autofixes), adds the optional code-fix-cmd key to the ecosystem-commands contract (1.3.0), and re-splits the bundled python/go/typescript defaults accordingly. I read the full diff against origin/main and cross-checked every touched file for internal consistency:

  • Invariant holds: no bundled fix-cmd line anywhere in plugins/toolchain/reference/ecosystems/*.yaml invokes ruff check --fix, golangci-lint --fix, or biome check --write — verified directly (not just author-claimed) via grep -n "^fix-cmd:" across all nine ecosystem files.
  • Contract/schema: code-fix-cmd is correctly added as optional (not in required: ["globs"]) in ecosystem.schema.json, matching the "additive, tolerant reader" framing in the CHANGELOG/README.
  • --unfixable F401 rationale: matches the existing ruff-format hook's own --no-unsafe-fixes --unfixable F401 invocation (plugins/ruff-format/hooks/ruff-format.sh:238) — the "aligned with ruff-format" claim in the PR description checks out against the actual hook script, not just the PR's own wording.
  • Version bumps: plugin.json (0.12.1→0.13.0) matches the new ## [0.13.0] CHANGELOG header; contract CHANGELOG (1.2.3→1.3.0) is consistent; no stray version string elsewhere needed updating (marketplace.json doesn't pin plugin versions).
  • Cross-file drift check: docs/conventions/ecosystem-commands/examples/{go,python}.yaml mirror plugins/toolchain/reference/ecosystems/{go,python}.yaml command strings exactly.
  • Gate logic (skills/lint/SKILL.md): the interactive/non-interactive × --yes/--dry-run/--all-files matrix is internally consistent, and the new evals (evals.json perf(markdown-formatter): unwired producer builds telemetry payload before the opt-in guard (~90ms/edit on Windows) #6, docs(playbook): document the local plugin development loop #7) exercise the two stop paths (no---yes in non-interactive, over-cap without --all-files) that the gate table describes.
  • Untouched ecosystems (dotnet, bash, markdown, yaml, cross-cutting, powershell) correctly remain format-only/unchanged, consistent with the CHANGELOG's claim.

No correctness or maintainability issues found that a careful reviewer would block on — this is a well-scoped, self-consistent change with no stale references to the old single-fix-cmd behavior left behind (checked via repo-wide grep for fix-cmd/ruff check --fix/golangci-lint --fix/biome check --write across plugins/toolchain). Nothing to flag inline.

One low-confidence, non-blocking observation (not filed as a finding): code-fix-cmd: "golangci-lint run --fix <files>" in go.yaml passes individual file paths rather than the previous ./... package pattern — worth a quick manual sanity check that golangci-lint run --fix behaves correctly with individual .go file args before this ships broadly, if you haven't already confirmed it. I could not verify this myself since running golangci-lint here isn't available.

Author-claimed and unverified by me (no tool access to run them in this environment): catalog/cheatsheet --check, changelog-parity check, and plugin-manifest validation mentioned in the PR description's "Verification" section.

@github-actions

github-actions Bot commented Aug 15, 2026

Copy link
Copy Markdown

Claude has reviewed this PR 2 times. The lane skips further automatic reviews after 5; deleting this comment resets the count.

@cursor
cursor Bot force-pushed the cursor/fix-toolchain-lint-fix-gates-f8b0 branch from bbe337d to 27d7d93 Compare August 15, 2026 02:04
Split format-only --fix from semantic lint autofixes: bundled fix-cmd
defaults are format-only; code-fix-cmd holds ruff/golangci/biome
code-changers behind confirmation, --yes, --dry-run, and a 40-file cap.
Go format/code-fix substitute only *.go paths, grouped by package dir.
Closes #2649. Version 0.13.0.

Co-authored-by: Kyle Sexton <kyle-sexton@users.noreply.github.com>
@cursor
cursor Bot force-pushed the cursor/fix-toolchain-lint-fix-gates-f8b0 branch from 27d7d93 to aea2b4f Compare August 15, 2026 02:04
kyle-sexton and others added 2 commits August 15, 2026 02:10
Clarify that gofmt and golangci-lint --fix receive only *.go paths from
<files>, and that golangci-lint is invoked once per package directory.
Add lint skill evals covering both review findings.

Co-authored-by: Kyle Sexton <kyle-sexton@users.noreply.github.com>
MD012 failed hygiene on consecutive blank lines after the Go
format/code-fix guidance.

Co-authored-by: Kyle Sexton <kyle-sexton@users.noreply.github.com>
@cursor
cursor Bot force-pushed the cursor/fix-toolchain-lint-fix-gates-f8b0 branch from f8f05c3 to 3bee855 Compare August 15, 2026 02:22
Regenerate docs/CATALOG.md so plugin-gate matches the repo-fleet-hygiene
manifest description already on main.

Co-authored-by: Kyle Sexton <kyle-sexton@users.noreply.github.com>
@cursor
cursor Bot force-pushed the cursor/fix-toolchain-lint-fix-gates-f8b0 branch from 3bee855 to 9ce0ae3 Compare August 15, 2026 02:22
@kyle-sexton
kyle-sexton merged commit d2d03af into main Aug 15, 2026
39 checks passed
@kyle-sexton
kyle-sexton deleted the cursor/fix-toolchain-lint-fix-gates-f8b0 branch August 15, 2026 02:29
@claude

claude Bot commented Aug 15, 2026

Copy link
Copy Markdown
Contributor

Claude finished @cursor[bot]'s task in 3m 46s —— View job


Code review complete

  • Gather context (PR diff via gh pr diff 2652, prior review threads, contract files)
  • Check skip gate
  • Review changed files for correctness/maintainability
  • Post findings

Skip gate: PR has real review surface (225/-44 across 20 files, doc/skill/config-only). Proceeded with full review.

Scope

Reviewed the full diff at head 9ce0ae36d83638e3e60bd7ae67b661595e09f1af against origin/main. This is the same logical change already reviewed by the code/security lanes on this head, plus two follow-up commits (984f9fa1) addressing Codex's two P2 findings (Go <files> non-.go filtering, per-package-directory golangci-lint --fix invocation). I re-verified both fixes landed correctly:

Finding

One inline comment posted:

  • plugins/toolchain/skills/lint/SKILL.md#L118 — the new Go filter paragraph says Go \format-cmd` / `code-fix-cmd`but the contract's actual key isfix-cmd(confirmed againstecosystem.schema.json, resolution-ladder.md, and every other reference in this same file). format-cmd` doesn't exist anywhere in the schema. Low blast-radius since this skill is LLM-interpreted and context makes the intent clear, but worth fixing for consistency with the rest of the contract's terminology — posted with a one-line suggestion.

Verified

  • Invariant holds: no bundled fix-cmd line invokes a semantic autofix (ruff check --fix, golangci-lint --fix, biome check --write) across all ecosystem YAMLs.
  • code-fix-cmd correctly added as optional (not in required) in ecosystem.schema.json, consistent with the "additive, tolerant reader" framing.
  • Version bumps consistent: plugin 0.12.1→0.13.0 matches new ## [0.13.0] CHANGELOG header; contract 1.2.3→1.3.0 matches its own CHANGELOG entry.
  • docs/conventions/ecosystem-commands/examples/{go,python}.yaml mirror the bundled reference/ecosystems/{go,python}.yaml command strings.
  • New evals (6–9) exercise the confirmation-gate stop path, file-cap stop path, and both Go filtering fixes.
  • No stale references to the old single-command fix-cmd behavior remain (repo-wide grep for ruff check . --fix, biome check --write ., golangci-lint run --fix ./... — only an unrelated hit in plugins/miro/package.json).

Author-claimed and not independently re-verified by me (no tool access to run them): catalog/cheatsheet --check, plugin-manifest validation.


**`<files>` substitution:** expand to the ecosystem-scoped changed-file list (paths relative to the execution root). Prefer this scoped list over whole-tree `.` / `./...` whenever the command string contains `<files>`. Under `/toolchain:lint all` with an empty detection set, expand to the matching files under each project root (or the repo root) rather than inventing a silent whole-tree rewrite for code-fix — and still apply the [file-cap](#code-fix-scope-fence) to that expanded set.

**Go `*.go` filter for format/code-fix:** ecosystem `globs` include `go.mod` / `go.sum`, but `gofmt -w` and `golangci-lint run --fix` reject non-source inputs (`gofmt` exits 2 on `go.mod`; `golangci-lint` requires named files in one directory). When substituting `<files>` into Go `format-cmd` / `code-fix-cmd`, drop every non-`.go` path first. For `golangci-lint run --fix`, further partition the remaining `.go` paths by parent directory and invoke once per directory (never pass a multi-directory file list in one process). If filtering leaves zero `.go` files, skip that Go format/code-fix command and report the skip rather than invoking the tool on module metadata alone.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wrong key name: format-cmd doesn't exist in the contract.

When substituting <files> into Go format-cmd / code-fix-cmd, drop every non-.go path first.

The schema/contract key is fix-cmd, not format-cmd — every other reference in this file, in ecosystem.schema.json, and in reference/ecosystems/go.yaml consistently says fix-cmd. This is the only spot that uses format-cmd. Since this skill is LLM-interpreted rather than parsed, a wrong key name here risks the agent looking for a format-cmd key that doesn't exist when resolving the Go ecosystem config. Suggest changing to fix-cmd:

Suggested change
**Go `*.go` filter for format/code-fix:** ecosystem `globs` include `go.mod` / `go.sum`, but `gofmt -w` and `golangci-lint run --fix` reject non-source inputs (`gofmt` exits 2 on `go.mod`; `golangci-lint` requires named files in one directory). When substituting `<files>` into Go `format-cmd` / `code-fix-cmd`, drop every non-`.go` path first. For `golangci-lint run --fix`, further partition the remaining `.go` paths by parent directory and invoke once per directory (never pass a multi-directory file list in one process). If filtering leaves zero `.go` files, skip that Go format/code-fix command and report the skip rather than invoking the tool on module metadata alone.
**Go `*.go` filter for format/code-fix:** ecosystem `globs` include `go.mod` / `go.sum`, but `gofmt -w` and `golangci-lint run --fix` reject non-source inputs (`gofmt` exits 2 on `go.mod`; `golangci-lint` requires named files in one directory). When substituting `<files>` into Go `fix-cmd` / `code-fix-cmd`, drop every non-`.go` path first. For `golangci-lint run --fix`, further partition the remaining `.go` paths by parent directory and invoke once per directory (never pass a multi-directory file list in one process). If filtering leaves zero `.go` files, skip that Go format/code-fix command and report the skip rather than invoking the tool on module metadata alone.

Fix this →

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.

fix(toolchain): lint --fix ships code-changing defaults behind a single flag, no dry-run, no scope fence

1 participant