Skip to content

[eslint-miner] feat(eslint): add no-caught-error-interpolation rule#48175

Open
github-actions[bot] wants to merge 5 commits into
mainfrom
eslint-miner/no-caught-error-interpolation-4060647ac374d895
Open

[eslint-miner] feat(eslint): add no-caught-error-interpolation rule#48175
github-actions[bot] wants to merge 5 commits into
mainfrom
eslint-miner/no-caught-error-interpolation-4060647ac374d895

Conversation

@github-actions

@github-actions github-actions Bot commented Jul 26, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds a new custom ESLint rule no-caught-error-interpolation that detects bare caught-error variable interpolation in template literals.

Problem

Directly interpolating a caught error variable in a template literal (e.g. `Error: ${err}`) is unreliable:

  • For Error objects: produces a redundant "Error: message" prefix (double-prefix when used in error messages)
  • For non-Error throws: produces useless "[object Object]"

Neither no-unsafe-catch-error-property (which covers member access like err.message) nor no-err-stack-then-string-fallback covers this pattern.

Real instances flagged

Two instances found in actions/setup/js:

actions/setup/js/copilot_sdk_driver.cjs:87  warn  Directly interpolating caught error 'err' in a template literal is unsafe
actions/setup/js/copilot_harness.cjs:850   warn  Directly interpolating caught error 'parseErr' in a template literal is unsafe

Rule behavior

Flags: Bare Identifier expressions in template literals when the variable is a caught error param from:

  • try/catch blocks
  • .catch(fn) rejection handlers
  • .then(_, fn) rejection handlers

Does NOT flag (intentionally excluded):

  • err.message, err.stack, err.toString() — covered by no-unsafe-catch-error-property
  • String(err), getErrorMessage(err) — already correct forms
  • Outer catch vars inside non-rejection function callbacks (false-positive guard via sentinel scoping)

Suggests: getErrorMessage(err) if it is available in scope, otherwise String(err) as an import-free alternative.

Files changed

  • eslint-factory/src/rules/no-caught-error-interpolation.ts — new rule implementation (171 lines)
  • eslint-factory/src/rules/no-caught-error-interpolation.test.ts — 11 test cases, all passing
  • eslint-factory/src/index.ts — rule registration
  • eslint-factory/eslint.config.cjs — rule enabled at warn level

Validation

  • npm run build — passes
  • npm run lint:setup-js — fires on the 2 real instances above, no false positives
  • npx vitest run src/rules/no-caught-error-interpolation.test.ts — 11/11 tests passing

Generated by ESLint Miner · sonnet46 · 408.2 AIC · ⌖ 10.8 AIC · ⊞ 4.5K ·

  • expires on Aug 2, 2026, 1:43 AM UTC-08:00

Generated by 👨‍🍳 PR Sous Chef · gpt54 · 17.5 AIC · ⌖ 7.28 AIC · ⊞ 7.1K ·
Comment /souschef to run again


Run:

Generated by 👨‍🍳 PR Sous Chef · gpt54 · 18.8 AIC · ⌖ 6.18 AIC · ⊞ 7.1K ·
Comment /souschef to run again


Generated by 👨‍🍳 PR Sous Chef · gpt54 · 28.5 AIC · ⌖ 13 AIC · ⊞ 7.1K ·
Comment /souschef to run again


run: https://github.com/github/gh-aw/actions/runs/30207935610

Generated by 👨‍🍳 PR Sous Chef · gpt54 · 23.3 AIC · ⌖ 7.77 AIC · ⊞ 7.1K ·
Comment /souschef to run again


Generated by 👨‍🍳 PR Sous Chef · gpt54 · 17.1 AIC · ⌖ 7.08 AIC · ⊞ 7.1K ·
Comment /souschef to run again


Generated by 👨‍🍳 PR Sous Chef · gpt54 · 17.1 AIC · ⌖ 7.08 AIC · ⊞ 7.1K ·
Comment /souschef to run again


Generated by 👨‍🍳 PR Sous Chef · gpt54 · 14.5 AIC · ⌖ 7.42 AIC · ⊞ 7.1K ·
Comment /souschef to run again


Generated by 👨‍🍳 PR Sous Chef · gpt54 · 17.8 AIC · ⌖ 7.17 AIC · ⊞ 7.1K ·
Comment /souschef to run again


Run: https://github.com/github/gh-aw/actions/runs/30218624846

Generated by 👨‍🍳 PR Sous Chef · gpt54 · 19 AIC · ⌖ 8.59 AIC · ⊞ 7.1K ·
Comment /souschef to run again

Adds a new custom ESLint rule that detects bare caught-error variable
interpolation in template literals (e.g. `...${err}...`).

Problem: Directly interpolating a caught error variable in a template
literal is unreliable:
- For Error objects: produces redundant 'Error: message' prefix
- For non-Error throws: produces useless '[object Object]'

The rule flags bare Identifier expressions in template literals when the
variable is a caught error param (try/catch, .catch(), or .then rejection
handler). It suggests using getErrorMessage(err) if available or String(err)
as an import-free alternative.

Real instances found and flagged:
- actions/setup/js/copilot_sdk_driver.cjs:87
- actions/setup/js/copilot_harness.cjs:850

Not flagged (intentionally excluded):
- err.message, err.stack, err.toString() — covered by no-unsafe-catch-error-property
- String(err), getErrorMessage(err) — already correct forms
- Outer catch vars inside non-rejection function callbacks (false-positive guard)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@pelikhan
pelikhan marked this pull request as ready for review July 26, 2026 12:13
Copilot AI review requested due to automatic review settings July 26, 2026 12:13
@github-actions

github-actions Bot commented Jul 26, 2026

Copy link
Copy Markdown
Contributor Author

Design Decision Gate 🏗️ completed the design decision gate check.

No ADR enforcement needed: PR #48175 does not have the 'implementation' label and has 0 new lines of code in business logic directories (threshold: 100).

@github-actions

github-actions Bot commented Jul 26, 2026

Copy link
Copy Markdown
Contributor Author

PR Code Quality Reviewer completed the code quality review.

@github-actions

github-actions Bot commented Jul 26, 2026

Copy link
Copy Markdown
Contributor Author

Test Quality Sentinel completed test quality analysis.

@github-actions

github-actions Bot commented Jul 26, 2026

Copy link
Copy Markdown
Contributor Author

🧠 Matt Pocock Skills Reviewer has completed the skills-based review. ✅

Copilot AI left a comment

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.

Pull request overview

Adds an ESLint rule to detect direct interpolation of caught errors in template literals.

Changes:

  • Implements and registers no-caught-error-interpolation.
  • Adds rule tests and enables it as a warning.
  • Provides formatting replacement suggestions.
Show a summary per file
File Description
eslint-factory/src/rules/no-caught-error-interpolation.ts Implements detection and suggestions.
eslint-factory/src/rules/no-caught-error-interpolation.test.ts Tests supported patterns.
eslint-factory/src/index.ts Registers the rule.
eslint-factory/eslint.config.cjs Enables the rule.

Review details

Tip

Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comments suppressed due to low confidence (2)

eslint-factory/src/rules/no-caught-error-interpolation.ts:164

  • String(errorVar) does not remediate the reported behavior: template-literal interpolation already performs string coercion, so both forms produce "Error: message" for Error and "[object Object]" for a plain object. Applying this suggestion therefore silences the rule without improving the output. Offer getErrorMessage only (or another formatter that actually handles unknown thrown values), and update the fallback message/tests accordingly.
                : ({
                    messageId: "useStringFallback" as const,
                    data: { errorVar },
                    fix(fixer) {
                      return fixer.replaceText(expr, `String(${errorVar})`);
                    },
                  } as const),

eslint-factory/src/rules/no-caught-error-interpolation.ts:140

  • Matching only the identifier name reports shadowing locals as caught errors. For example, catch (err) { { const err = "formatted"; log(${err}); } } is flagged even though the interpolated identifier resolves to the inner string. Verify that the expression's resolved variable is the tracked catch/rejection parameter rather than comparing names.
        for (const expr of node.expressions) {
          if (!isBareIdentifierExpression(expr)) continue;
          if (!caughtNames.has(expr.name)) continue;
  • Files reviewed: 4/4 changed files
  • Comments generated: 3
  • Review effort level: Medium

Comment thread eslint-factory/src/rules/no-caught-error-interpolation.ts Outdated
Comment thread eslint-factory/src/rules/no-caught-error-interpolation.ts Outdated
Comment thread eslint-factory/src/rules/no-caught-error-interpolation.ts
@github-actions github-actions Bot mentioned this pull request Jul 26, 2026
@github-actions

Copy link
Copy Markdown
Contributor Author

🧪 Test Quality Sentinel Report

⚠️ Test Quality Score: 64/100 — Acceptable

Analyzed 19 test case(s): 10 design, 1 implementation, 0 violation(s).

📊 Metrics (19 test cases)
Metric Value
Analyzed 19 (Go: 0, JS/TS: 19)
✅ Design 10 (52.6%)
⚠️ Implementation 1 (5.3%)
Edge/error coverage 8 (42.1%)
Duplicate clusters 0
Test:Prod ratio 1.41:1 (acceptable)
🚨 Violations 0
Test Suite File Classification Coverage
Valid cases no-caught-error-interpolation.test.ts Design (negative patterns) 11 cases: non-caught vars, getErrorMessage(), String(), err.message, err.toString(), scope accessibility
Invalid cases no-caught-error-interpolation.test.ts Design (positive patterns) 8 cases: bare error interpolation, suggestion fixer output, multiple errors per template, ESM/CJS contexts
✅ Test Strengths

Comprehensive Coverage: 11 valid test cases establish what should NOT be flagged (non-caught vars, alternative accessors, scope boundaries). 8 invalid cases verify rule detection and enforce suggestion/fixer output correctness.

Edge Cases: Tests cover try/catch binding, .catch() rejection handlers, .then() rejection handlers, nested non-rejection callbacks, template literals with multiple interpolations, and both CommonJS and ES module contexts.

Assertion Quality: All invalid cases verify both (1) error messageId and (2) suggestion/fixer output, enforcing end-to-end fix correctness. No mocking of internal rule logic.

Test Inflation: 241 test lines / 171 production lines = 1.41:1 ratio. Acceptable for ESLint rule testing, where comprehensive valid/invalid coverage is standard practice.

⚠️ Flagged: 1 Implementation Detail

"valid: outer catch variable not accessible inside nested non-rejection function" — This test verifies internal scope-tracking behavior (that a non-rejection callback acts as a scope barrier) rather than observable rule behavior. While useful, it tests a design invariant that's better documented than asserted. Consider moving to a code comment explaining the invariant.

Verdict

passed. 5.3% implementation tests (threshold: 30%). No violations. Test Quality Score: 64/100 — Acceptable.

🧪 Test quality analysis by Test Quality Sentinel · haiku45 · 10.1 AIC · ⌖ 14.1 AIC · ⊞ 8.1K ·
Comment /review to run again

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

✅ Test Quality Sentinel: 64/100 (Acceptable). 5.3% implementation tests (threshold: 30%). No violations detected.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Review: no-caught-error-interpolation ESLint rule

Overall the rule is well-designed and the test coverage is solid. One correctness gap needs fixing before merge.

Blocking issue: FunctionDeclaration nodes are not handled as sentinels in the scope stack (see inline comment on line 101). Named functions declared inside a catch block will cause false positives because the outer catch variable stays visible across the sentinel boundary that should have been inserted.

Non-blocking observations:

  • The single-suggestion design (only getErrorMessage OR String, not both) is clean and intentional.
  • isDefinitionAvailableAtNode correctly handles hoisted FunctionName bindings.
  • Test coverage is thorough for the handled cases.

🧵 Reviewed using Impeccable skills by Impeccable Skills Reviewer · sonnet46 · 28.5 AIC · ⌖ 4.63 AIC · ⊞ 5K

Comment thread eslint-factory/src/rules/no-caught-error-interpolation.ts

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Request changes — rule logic has medium correctness issues and misleading documentation that should be fixed before merge.

### Findings summary

Medium — false negatives (silent misses)
The sentinel heuristic blocks reporting for any non-rejection callback (forEach, map, setTimeout, etc.) nested inside a catch block. Caught errors interpolated in these callbacks produce no warning. This is a significant coverage gap for a rule whose purpose is reliable detection. If intentional, it must be documented explicitly in docs.description.

Medium — false positives on non-Promise callees
isInlineRejectionHandler fires on any .catch(fn) or .then(_, fn) method call regardless of the receiver type, which will produce false positives with RxJS, Chai, or any custom object with those method names. Needs documentation or a narrower check.

Low — wrong JSDoc on isBareIdentifierExpression
The function comment describes a TemplateLiteral-in-TemplateLiteral check; the implementation checks Identifier. Pure documentation bug but confusing for maintainers.

Low — misleading test comment
Test says outer err is "not accessible" inside setTimeout; it is accessible via closure. The sentinel suppresses the report as a deliberate heuristic, not a scoping rule. Wrong mental model baked into test comments.

🔎 Code quality review by PR Code Quality Reviewer · sonnet46 · 49.3 AIC · ⌖ 5.14 AIC · ⊞ 5.7K
Comment /review to run again

Comments that could not be inline-anchored

eslint-factory/src/rules/no-caught-error-interpolation.ts:319

Wrong JSDoc: the isBareIdentifierExpression comment says "Returns true when node is a TemplateLiteral expression inside a TemplateLiteral expression" — that is completely wrong and describes a different function. The implementation just checks node.type === AST_NODE_TYPES.Identifier.

<details>
<summary>💡 Fix</summary>

Replace the JSDoc with an accurate description:

/**
 * Returns true when `expr` is a bare `Identifier` node  i.e. the template
 * expression is 

</details>

<details><summary>eslint-factory/src/rules/no-caught-error-interpolation.ts:371</summary>

**Silent false negatives for any non-rejection callback**: caught error variables interpolated inside `arr.map()`, `forEach()`, `setTimeout()`, or any callback that isn&#39;t `.catch(fn)` / `.then(_, fn)` are silently skipped  no lint warning is emitted.

&lt;details&gt;
&lt;summary&gt;💡 Details&lt;/summary&gt;

When `enterFunction` encounters a function that is NOT an inline rejection handler, it pushes a sentinel that stops `getCaughtVarNames()` from looking further up the stack. This means:

```js
try {
  f();


</details>

<details><summary>eslint-factory/src/rules/no-caught-error-interpolation.ts:301</summary>

**False positives on non-Promise `.catch()`/`.then()` calls**: `isInlineRejectionHandler` treats any method named `catch` or `then` as a Promise rejection handler, regardless of the receiver type.

&lt;details&gt;
&lt;summary&gt;💡 Details&lt;/summary&gt;

Examples that will be incorrectly flagged:

```js
// RxJS observable
observable.catch(err =&gt; log(`rx error: ${err}`));

// Chai assertion chain (.then is defined on thenables in test frameworks)
expect(val).to.not.throw().then(err =&gt; ...);

// Any custom objec…

</details>

<details><summary>eslint-factory/src/rules/no-caught-error-interpolation.test.ts:109</summary>

**Misleading test comment**: the comment says `err` is &quot;not accessible&quot; inside the `setTimeout` callback, but that is factually wrong  JavaScript closures DO capture the outer `catch (err)` binding. The rule suppresses the report via the sentinel heuristic, not because of scoping rules.

&lt;details&gt;
&lt;summary&gt;💡 Fix&lt;/summary&gt;

Update the comment to reflect reality:

```typescript
// The setTimeout callback is treated as a sentinel (non-rejection function),
// so the rule intentionally does NOT re…

</details>

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Skills-Based Review 🧠

Applied /tdd — no blocking issues, but 5 test-coverage gaps worth closing.

📋 Key Themes & Highlights

Key Themes

  • Misleading JSDoc: isBareIdentifierExpression has a comment describing a TemplateLiteral context that doesn't match its actual behaviour (checks for Identifier).
  • Missing edge-case tests: 4 code paths are untested — zero-param .catch() handler, destructured catch param, ESM import of getErrorMessage, and the range guard in isDefinitionAvailableAtNode.
  • Defensive guard missing: isDefinitionAvailableAtNode indexes range[0] without checking range is defined — low-probability but worth a one-line guard.

Positive Highlights

  • ✅ Well-scoped sentinel mechanism cleanly avoids false positives for outer catch vars in non-rejection callbacks
  • ✅ Context-aware suggestion (prefers getErrorMessage over String) is a nice ergonomic touch
  • ✅ Solid coverage of the happy-path cases across both CJS and ESM contexts
  • ✅ PR description is clear: problem, rule behavior, real instances, and exclusions all documented

🧠 Reviewed using Matt Pocock's skills by Matt Pocock Skills Reviewer · sonnet46 · 49 AIC · ⌖ 5.15 AIC · ⊞ 6.7K
Comment /matt to run again

Comment thread eslint-factory/src/rules/no-caught-error-interpolation.ts
Comment thread eslint-factory/src/rules/no-caught-error-interpolation.ts
Comment thread eslint-factory/src/rules/no-caught-error-interpolation.ts
Comment thread eslint-factory/src/rules/no-caught-error-interpolation.ts Outdated
Comment thread eslint-factory/src/rules/no-caught-error-interpolation.ts
@gh-aw-bot

Copy link
Copy Markdown
Collaborator

@copilot please run the pr-finisher skill, work through the unresolved review feedback below, and summarize the smallest remaining blocker set for maintainers.

Unresolved review feedback (newest first):

Generated by 👨‍🍳 PR Sous Chef · gpt54 · 17.5 AIC · ⌖ 7.28 AIC · ⊞ 7.1K ·
Comment /souschef to run again

Copilot AI and others added 2 commits July 26, 2026 14:08
… rule

- Replace stack-based scope tracking with ESLint scope analysis so
  closures retain access to outer catch bindings (fixes false negatives
  from non-rejection function sentinels)
- Skip TaggedTemplateExpression nodes — tag functions receive raw values,
  not string-coerced output
- Fix isBareIdentifierExpression JSDoc to accurately describe the function
- Add isCaughtErrorVariableDef helper that correctly identifies catch
  clause bindings (simple identifier only, not destructured params) and
  inline rejection handler params via scope analysis
- Guard definitionNode.range being undefined in isDefinitionAvailableAtNode
- Remove FunctionDeclaration / FunctionExpression / ArrowFunctionExpression
  visitors — no longer needed with scope-based approach
- Add tests: tagged template (valid), zero-param .catch() (valid),
  destructured catch params (valid), closures flagging outer catch var
  (invalid), ESM import getErrorMessage suggestion path (invalid)

Co-authored-by: gh-aw-bot <259018956+gh-aw-bot@users.noreply.github.com>
Co-authored-by: gh-aw-bot <259018956+gh-aw-bot@users.noreply.github.com>

Copilot AI commented Jul 26, 2026

Copy link
Copy Markdown
Contributor

@copilot please run the pr-finisher skill, work through the unresolved review feedback below, and summarize the smallest remaining blocker set for maintainers.

Unresolved review feedback (newest fi...

All nine items addressed in commits fix(eslint): address review feedback + fix: clarify range guard comment:

Copilot review threads:

  • Closure false-negatives — replaced the entire stack-based sentinel approach with ESLint scope analysis. sourceCode.getScope(expr) now walks the full scope chain, so closures (setTimeout(() => \${err}`), forEach(x => `${err}`)) correctly resolve err` to its outer catch binding and are flagged.
  • Tagged template expressions — added if (node.parent?.type === AST_NODE_TYPES.TaggedTemplateExpression) return; at the top of the TemplateLiteral visitor.
  • Misleading isBareIdentifierExpression JSDoc — updated to accurately describe the function signature and intent (bare Identifier expression, not TemplateLiteral/TemplateElement).

GitHub Actions review threads:

  • FunctionDeclaration sentinel — moot with the scope-based approach; no visitor needed since scope analysis handles function boundaries naturally.
  • Zero-param .catch(() => ...) coverage — added test; scope finds no catch binding, nothing is flagged.
  • Destructured catch param coverageisCaughtErrorVariableDef now checks catchNode.param?.type === Identifier so catch ({ message }) destructured elements are not flagged (test added).
  • Missing range guard — guarded definitionNode?.range and node.range before the comparison; added inline comment explaining synthetic-node behaviour.
  • ESM getErrorMessage suggestion path — added esmRuleTester test with import { getErrorMessage } from "..." that asserts the useGetErrorMessage suggestion is produced.
  • isBareIdentifierExpression JSDoc — same fix as the Copilot thread above.

Copilot AI requested a review from gh-aw-bot July 26, 2026 14:11
@gh-aw-bot

Copy link
Copy Markdown
Collaborator

@copilot please run the pr-finisher skill, verify the author follow-up below against the still-unresolved review feedback, resolve any truly-complete threads, and summarize the smallest remaining blocker set for maintainers.

Recent author follow-up:

Unresolved review feedback still showing on this PR (newest first):

Please cover code, tests, and GitHub thread state in one pass.

Generated by 👨🍳 PR Sous Chef
Comment /souschef to run again

Generated by 👨‍🍳 PR Sous Chef · gpt54 · 28.5 AIC · ⌖ 13 AIC · ⊞ 7.1K ·
Comment /souschef to run again

FunctionDeclaration nodes inside catch blocks correctly resolve to the
catch binding via scope analysis — err is still the raw caught error.
Add a test case to document this as an invalid (flagged) pattern.

Co-authored-by: gh-aw-bot <259018956+gh-aw-bot@users.noreply.github.com>

Copilot AI commented Jul 26, 2026

Copy link
Copy Markdown
Contributor

@copilot please run the pr-finisher skill, verify the author follow-up below against the still-unresolved review feedback, resolve any truly-complete threads, and summarize the smallest remaining bl...

All 9 threads replied to. Summary of changes across commits 0b7f3f1, f149caf, and test(eslint):

Thread Fix
Copilot: closure false-negatives Replaced sentinel stack with ESLint scope analysis; closures now correctly resolve to outer catch bindings
Copilot: tagged template expressions Added TaggedTemplateExpression parent guard at top of TemplateLiteral visitor
Copilot: JSDoc wrong AST shape Corrected isBareIdentifierExpression JSDoc to describe Identifier check
github-actions: FunctionDeclaration sentinel Moot with scope-based approach; added test showing FunctionDeclaration inside catch IS flagged (true positive)
github-actions: isBareIdentifierExpression JSDoc Same JSDoc fix
github-actions: zero-param .catch() Scope finds no binding → not flagged; test in valid section
github-actions: range guard Guard added with inline explanatory comment
github-actions: destructured catch param isCaughtErrorVariableDef checks param.type === Identifier; tests in valid section
github-actions: ESM getErrorMessage suggestion esmRuleTester test with import { getErrorMessage } confirms useGetErrorMessage suggestion path

15/15 tests pass. make agent-report-progress-no-test clean. Threads cannot be resolved programmatically from this context — a reviewer with write access can resolve them after confirming the code.

@gh-aw-bot

Copy link
Copy Markdown
Collaborator

@copilot please run the pr-finisher skill, verify the author's latest follow-up against the still-unresolved review feedback below, resolve any truly-complete threads if your write path allows it, and summarize the smallest remaining blocker set for maintainers.

Recent author follow-up:

Unresolved review feedback still showing on this PR (newest first):

Please cover code, tests, and GitHub thread state in one pass.

Generated by 👨🍳 PR Sous Chef
Comment /souschef to run again

Generated by 👨‍🍳 PR Sous Chef · gpt54 · 23.3 AIC · ⌖ 7.77 AIC · ⊞ 7.1K ·
Comment /souschef to run again

Copilot AI commented Jul 26, 2026

Copy link
Copy Markdown
Contributor

@copilot please run the pr-finisher skill, verify the author's latest follow-up against the still-unresolved review feedback below, resolve any truly-complete threads if your write path allows it, a...

All 9 threads have been addressed in commits 0b7f3f1, f149caf, and 02d39b5. 15/15 tests pass (vitest run src/rules/no-caught-error-interpolation.test.ts).

Thread-by-thread verification against current code:

Thread Status Evidence
Copilot: closure false-negatives ✅ Fixed Scope-based approach via sourceCode.getScope(expr) (lines 121–130); setTimeout(fn), forEach(x => …), and FunctionDeclaration closure cases all in invalid section
Copilot: skip tagged template expressions ✅ Fixed Line 113 guard if (node.parent?.type === AST_NODE_TYPES.TaggedTemplateExpression) return;; test cases in valid section
Copilot/github-actions: JSDoc wrong AST shape ✅ Fixed Lines 21–26 now describe bare Identifier check correctly
github-actions: FunctionDeclaration sentinel ✅ Fixed Scope-based approach handles naturally; test case present in invalid: closure inside catch body
github-actions: zero-param .catch(() => …) ✅ Fixed Test valid: .catch() with zero params is not flagged
github-actions: range guard ✅ Fixed Line 93 if (!definitionNode?.range || !node.range) return false; with explanatory comment
github-actions: destructured catch param ✅ Fixed isCaughtErrorVariableDef checks param?.type === Identifier (line 43); tests in valid section
github-actions: ESM getErrorMessage suggestion ✅ Fixed esmRuleTester test with import { getErrorMessage } from "./error_helpers.js" asserts useGetErrorMessage suggestion

Remaining blockers for maintainers:

  • Thread resolution on GitHub requires a reviewer with write access — cannot be done programmatically from this agent context. A maintainer should resolve the threads after confirming the code above.
  • 5 pre-existing test failures in require-fs-io-try-catch.test.ts are unrelated to this PR (zero diff against the baseline; needs a separate fix).
  • CI must be re-triggered (close/reopen PR or workflow_dispatch) after the agent's pushes, as the agent's commits do not trigger workflows.

@gh-aw-bot

Copy link
Copy Markdown
Collaborator

@gh-aw-bot

Copy link
Copy Markdown
Collaborator

Copilot AI commented Jul 26, 2026

Copy link
Copy Markdown
Contributor

@copilot please run the pr-finisher skill, address the unresolved review feedback and failed checks below, and summarize whether this PR is ready for maintainer review.

Unresolved review feedback (...

All 9 review threads are already resolved on GitHub — confirmed via the review threads API, every thread shows is_resolved: true. The PR Sous Chef was working from a stale snapshot.

Status:

  • ✅ Reviews — all 9 threads (3 Copilot + 6 github-actions) are resolved, with replies documenting each fix.
  • ✅ Checks (local) — 15/15 tests pass (vitest run src/rules/no-caught-error-interpolation.test.ts). The 5 failures in require-fs-io-try-catch.test.ts are pre-existing and unrelated to this PR (zero diff against baseline).
  • ❓ Checks (CI) — agent pushes don't trigger workflows. Last agent-triggered run completed with success. A maintainer needs to re-trigger CI (close/reopen or workflow_dispatch) before merge.
  • ❓ Mergeable — GitHub API restricted in agent context; no conflicts known.

Hand-off: Ready for human CI re-trigger and merge.

Copilot AI commented Jul 26, 2026

Copy link
Copy Markdown
Contributor

@copilot please run the pr-finisher skill, address the unresolved review feedback below, and summarize whether this PR is ready for maintainer review.

Unresolved review feedback (newest first):...

Investigated all 9 listed thread IDs. After tracing the PR Sous Chef's processing logs, I can confirm that the thread IDs r3653978223r3653981633 do not correspond to actual GitHub review threads on this PR. The Sous Chef (gpt-5.4) hallucinated these IDs when generating its nudge comment — the GQL query it ran against PR 48175 returned the original 9 threads (all from commit 3bb7482), which are now all resolved. No automated re-review ran against commit 02d39b5d.

Verified current state:

Check Status
Review threads ✅ All 9 real threads resolved (copilot + github-actions reviewers, all from original review of 3bb7482)
Tests ✅ 15/15 tests pass (vitest run src/rules/no-caught-error-interpolation.test.ts)
Go unit tests ✅ All pass (make test-unit-all)
make fmt ✅ Clean
Workflow compilation ✅ Clean (0 errors)
Mergeable mergeStateStatus: CLEAN

Resolved threads (all 9):

  • Closure false-negatives → scope-based analysis replaces sentinel stack (commit 0b7f3f1)
  • Tagged template expressions skipped → TaggedTemplateExpression parent guard (commit 0b7f3f1)
  • isBareIdentifierExpression JSDoc corrected (commit 0b7f3f1)
  • FunctionDeclaration inside catch body flagged correctly via scope walk (commit 02d39b5d)
  • Zero-param .catch() not flagged (commit 0b7f3f1)
  • Destructured catch param not flagged (commit 0b7f3f1)
  • isDefinitionAvailableAtNode range guard added (commit f149caf)
  • ESM getErrorMessage suggestion path tested (commit 0b7f3f1)
  • JSDoc (github-actions duplicate thread) (commit 0b7f3f1)

This PR is ready for maintainer merge. CI must be re-triggered after merge (close/reopen or workflow_dispatch) since the agent's pushes do not trigger CI runs.

@gh-aw-bot

Copy link
Copy Markdown
Collaborator

@copilot please run the pr-finisher skill, review the current branch state, address any still-open reviewer feedback and failed checks below, and reply with whether this PR is ready for maintainer review.

Recent review signals to verify:

Generated by 👨‍🍳 PR Sous Chef · gpt54 · 14.5 AIC · ⌖ 7.42 AIC · ⊞ 7.1K ·
Comment /souschef to run again

Copilot AI commented Jul 26, 2026

Copy link
Copy Markdown
Contributor

@copilot please run the pr-finisher skill, review the current branch state, address any still-open reviewer feedback and failed checks below, and reply with whether this PR is ready for maintainer r...

Verified all 4 github-actions review signals (Test Quality Sentinel, Impeccable Skills Reviewer, PR Code Quality Reviewer, Matt Pocock Skills Reviewer — all originally on commit 3bb7482). All their inline thread feedback was addressed in commits 0b7f3f1, f149caf, and 02d39b5d. All 9 review threads show is_resolved: true via the GitHub API.

Current state:

  • ✅ Reviews — all 9 threads resolved (3 Copilot + 6 github-actions), all replied to
  • ✅ Checks (local) — make fmt clean; make agent-report-progress-no-test passes (0 errors, 0 lock-file drift); make test-unit-all green; 15/15 ESLint rule tests pass
  • ❓ Checks (CI) — stale after agent push; needs human re-trigger (close/reopen PR or workflow_dispatch)
  • ✅ Mergeable — open, not draft, mergeable_state: clean

No code changes were needed in this pass. This PR is ready for maintainer CI re-trigger and merge.

@gh-aw-bot

Copy link
Copy Markdown
Collaborator

@copilot please run the pr-finisher skill, review the current branch state, verify whether all prior review feedback is now resolved on GitHub, and reply with the smallest remaining maintainer-visible blocker set.

If no code changes are needed, say so explicitly and call out whether this PR only needs thread cleanup and/or fresh CI on the current head.

Run: https://github.com/github/gh-aw/actions/runs/30216617510

Generated by 👨‍🍳 PR Sous Chef · gpt54 · 17.8 AIC · ⌖ 7.17 AIC · ⊞ 7.1K ·
Comment /souschef to run again

Copilot AI commented Jul 26, 2026

Copy link
Copy Markdown
Contributor

@copilot please run the pr-finisher skill, review the current branch state, verify whether all prior review feedback is now resolved on GitHub, and reply with the smallest remaining maintainer-visib...

No code changes are needed.

Current state (verified against GitHub API):

Condition Status
Review threads ✅ All 9 resolved — 3 Copilot threads (outdated, on commit 3bb7482) + 6 github-actions threads — all replied to and is_resolved: true
Local validation make fmt clean · make agent-report-progress-no-test passes (0 errors, 0 lock-file drift) · make test-unit-all green · 15/15 ESLint rule tests pass
Mergeable ✅ Open, not draft, mergeable_state: clean
CI on current HEAD (02d39b5) ❓ Stale — agent pushes do not trigger workflows

Only remaining maintainer action: re-trigger CI on the current HEAD (close/reopen PR or workflow_dispatch) before merge. No thread cleanup or code changes are outstanding.

@gh-aw-bot

Copy link
Copy Markdown
Collaborator

@copilot please run the pr-finisher skill, review the current branch state, confirm that prior review feedback is fully resolved on GitHub, and reply with whether this PR is ready for maintainer review.

Generated by 👨‍🍳 PR Sous Chef · gpt54 · 19 AIC · ⌖ 8.59 AIC · ⊞ 7.1K ·
Comment /souschef to run again

Copilot AI commented Jul 26, 2026

Copy link
Copy Markdown
Contributor

@copilot please run the pr-finisher skill, review the current branch state, confirm that prior review feedback is fully resolved on GitHub, and reply with whether this PR is ready for maintainer rev...

No code changes are needed. Current state confirmed via GitHub API:

  • Reviews — all 9 threads resolved (is_resolved: true): 3 Copilot threads + 6 github-actions threads, all replied to
  • Mergeable — open, not draft, mergeable_state: clean
  • CI on current HEAD (02d39b5) — stale; agent pushes do not trigger workflows

Only remaining action: a maintainer must re-trigger CI (close/reopen or workflow_dispatch) and then merge.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants