Skip to content

fix(cli): make create-sg-rule's Quirks workarounds hold for real code - #491

Merged
theCodeDrift merged 1 commit into
mainfrom
fix/sg-rule-quirks-review
Oct 12, 2026
Merged

theCodeDrift merged 1 commit into
mainfrom
fix/sg-rule-quirks-review

Conversation

@theCodeDrift

Copy link
Copy Markdown
Member

Follow-up to #488, which merged without review. A local review afterwards found that the recipe's own workarounds reintroduced the silent failures the Quirks section warns about. Everything below was measured on ast-grep 0.45.3.

Recipe fixes (create-sg-rule.md, topic v6 → v7; v6 already shipped in the nightly)

  • readonly workaround matched 1 of 4 real shapes. ^readonly\b on required_parameter missed private readonly x, a decorated parameter, and readonly x? (an optional_parameter). The new regex matches all four and excludes x: readonly string[], a parameter named readonly, and public x.
  • The callee repro and workaround failed verify. Each had a regex with no sibling kind (sg-regex-needs-kind). Both now carry kind: identifier.
  • Method callees. Under await, client.rpc<Foo>() wraps a member_expression; the identifier-only workaround found 0 of 2. The recipe now shows the member form.
  • Step 5 overclaimed. It said every quirk "verifies clean", but verify reports the language: spelling and a TypeScript rule whose files: names .tsx. The Quirks table gains a column saying which quirks verify reports.

Every YAML example in the recipe passes taskless verify and taskless test, checked in a scratch project.

Tests

  • The vendor contract pins claims it previously took on trust: Tsx parses the same way; !, void and typeof hide the callee behind unary_expression; yield does not; and both workarounds match exactly what the recipe says.
  • The header reads "measured at 0.45.3" rather than "added at", since no bump introduced these.
  • The three copies of the NDJSON parse chain become one grammarMatches.
  • agent-extensions asserts exitCode in both new tests.

Changeset: the pending sg-rule-quirks.md is extended, not duplicated, and now names topic v7.

Refs #485

A post-merge review of #488 found the recipe's own workarounds reintroduced
the silent failures the section warns about. All measured on ast-grep 0.45.3.

- The `readonly` workaround (`^readonly\b` on `required_parameter`) matched
  1 of 4 real shapes. It missed `private readonly x` and a decorated
  parameter, whose text starts before the keyword, and `readonly x?`, which
  is an `optional_parameter`. The new regex covers all four and keeps out a
  `readonly` type and a parameter named `readonly`.
- The awaited-call workaround and the repro both used a `regex` with no
  sibling `kind`, which `verify` refuses (`sg-regex-needs-kind`). Both now
  carry `kind: identifier`. The recipe also shows the method form: under
  `await`, `client.rpc<Foo>()` wraps a `member_expression`, and the
  identifier branch found 0 of 2.
- Step 5 claimed every quirk "verifies clean", but `verify` does report the
  `language:` spelling and a TypeScript rule whose `files:` names `.tsx`.
  The table gains a column saying which quirks `verify` reports.

The vendor contract now pins the claims it previously took on trust: Tsx
parses awaited generics the same way, `!`/`void`/`typeof` wrap the callee in
`unary_expression` and `yield` does not, and both workarounds match exactly
what the recipe says. The header reads "measured at" rather than "added at",
since a bump did not introduce these. `typescriptMatches` and `arityMatches`
were the third copy of the same parse chain; both now go through
`grammarMatches`. The topic moves to v7, because v6 already shipped in the
nightly, and the pending changeset says so.
@theCodeDrift

Copy link
Copy Markdown
Member Author

@claude /review

@github-actions

github-actions Bot commented Oct 12, 2026 •

Copy link
Copy Markdown
Contributor

Claude finished @theCodeDrift's task in 3m 57s —— View job


Review mode: incremental — read 0 prior review thread(s) before reviewing. .prior-review.json contained no review threads, reviews, or inline comments (only the trigger comment itself), so this is the first review of this PR.

Todo

  • Read .prior-review.json
  • Fetch PR diff and metadata
  • Review .changeset/sg-rule-quirks.md
  • Review packages/cli/src/agent/create-sg-rule.md
  • Review packages/cli/test/agent-extensions.test.ts
  • Review packages/cli/test/ast-grep-vendor-contract.test.ts
  • Post final review

Summary

I found nothing NEW to flag. This is a tight, well-verified fix — every claim it makes is cross-checked against either the test file or the actual verify.ts implementation:

  • readonly regex (create-sg-rule.md:307-313): ^(?:@\S+\s+)*(?:(?:public|private|protected)\s+)?readonly\s correctly matches private readonly x, @Inject() readonly c, and readonly d? (as optional_parameter), while excluding x: readonly string[], a parameter literally named readonly, and public x. Verified by tracing the regex against all 7 fixture classes in ast-grep-vendor-contract.test.ts:1091-1099 and the expected-match list at :1119-1135 — they line up exactly. The recipe itself calls out the one real residual gap (a decorator whose args contain whitespace, e.g. @Inject(A, B), defeats \S+), so that's a documented limitation, not a silent one.
  • kind: identifier additions to the callee repro/workaround (create-sg-rule.md:332, :359-360): fixes sg-regex-needs-kind without changing match semantics (the kind constraint is already implied by the pre-existing text/structure mismatch), confirmed by reading packages/cli/src/rules/verify.ts:142-145 (the regex-requires-kind check) and :341-368 (sg-regex-needs-kind wiring).
  • Method-callee (member_expression) workaround (create-sg-rule.md:369-377): indentation is a correct drop-in for the any: list in the identifier-only version, and the test at ast-grep-vendor-contract.test.ts:1210-1246 exercises exactly this shape (this.rpc, client.rpc under await, and a bare non-generic client.rpc), matching the recipe's YAML verbatim.
  • Quirks table's new "verify reports it" column: the .tsx/files: claim (create-sg-rule.md:203,222-223) matches verify.ts:233-237,284-291 (the Tsx/TypeScript split check only fires when files: is an array naming .tsx), and the "no" entries for the other rows are consistent with there being no corresponding check in verify.ts.
  • Test refactor: typescriptFindings/typescriptMatches were fully replaced by grammarFindings/grammarMatches with no leftover references; arityRule/aritySource are still used directly at :947-949 for the strictness: ast case, so nothing was left dead by the consolidation.
  • Changeset: extends the existing file rather than duplicating it, correctly stays at patch per this repo's "0.y.z is still patch" versioning rule (CLAUDE.md), and accurately summarizes the diff.
  • agent-extensions.test.ts: the added exitCode assertion is consistent with the sibling test in the same describe block, which already had it.

No correctness, security, or test-adequacy issues found in this diff.
(branch)

@theCodeDrift
theCodeDrift merged commit 47f5f96 into main Oct 12, 2026
8 checks passed
@theCodeDrift
theCodeDrift deleted the fix/sg-rule-quirks-review branch October 12, 2026 21:59
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