Skip to content

eslint-factory: flag core.error + core.setFailed(prefix + msg) as redundant - #49496

Merged
pelikhan merged 6 commits into
mainfrom
copilot/fix-eslint-no-core-error
Aug 1, 2026
Merged

eslint-factory: flag core.error + core.setFailed(prefix + msg) as redundant#49496
pelikhan merged 6 commits into
mainfrom
copilot/fix-eslint-no-core-error

Conversation

Copilot AI commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

The no-core-error-then-setfailed rule only fired on exact source-text matches, missing the codebase's dominant pattern where setFailed prepends an error code to the same message — 9 live sites, zero flagged.

Changes

  • no-core-error-then-setfailed.ts — adds isSetFailedArgPrefixedVersion: recognises when setFailedArg is a TemplateLiteral whose content ends with the full content of errorArg (also a TemplateLiteral), with only a non-empty prefix in front. The prefix may include template expressions (e.g. ${ERR_API}: ). Suffix/interleaved additions remain unflagged.

  • no-core-error-then-setfailed.test.ts — moves the former valid prefix-pattern case to invalid; adds two new invalid cases (literal prefix, expression prefix); adds a suffix valid case.

Now flagged (previously missed)

core.error(`Failed to add reaction: ${errorMessage}`);
core.setFailed(`${ERR_API}: Failed to add reaction: ${errorMessage}`);
//             ^^^^^^^^^^^^ prefix — entire errorArg content is a strict suffix

Remains valid (suffix adds distinct context)

core.error(`Failed: ${msg}`);
core.setFailed(`Failed: ${msg} [extra context]`);  // suffix — not flagged

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

Generated by 👨‍🍳 PR Sous Chef · gpt54 · 14.6 AIC · ⌖ 13.9 AIC · ⊞ 8.1K ·
Comment /souschef to run again

Copilot AI and others added 2 commits August 1, 2026 06:44
… pattern

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix strict text-equality check in no-core-error-then-setfailed rule eslint-factory: flag core.error + core.setFailed(prefix + msg) as redundant Aug 1, 2026
Copilot AI requested a review from pelikhan August 1, 2026 06:54
@pelikhan
pelikhan marked this pull request as ready for review August 1, 2026 06:59
Copilot AI review requested due to automatic review settings August 1, 2026 06:59
@github-actions

github-actions Bot commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

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

No ADR enforcement needed: PR does not have the 'implementation' label and has ≤100 new lines of code in business logic directories.

@github-actions

github-actions Bot commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

Test Quality Sentinel completed test quality analysis.

@github-actions

github-actions Bot commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

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

@github-actions

github-actions Bot commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

PR Code Quality Reviewer completed the code quality 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

Extends the ESLint rule to detect redundant core.error() calls when core.setFailed() prefixes the same template message.

Changes:

  • Adds template-literal prefix matching.
  • Adds prefix and suffix test cases.
  • Regenerates one unrelated workflow lock file.
Show a summary per file
File Description
eslint-factory/src/rules/no-core-error-then-setfailed.ts Implements prefixed-message detection.
eslint-factory/src/rules/no-core-error-then-setfailed.test.ts Tests literal/expression prefixes and suffix exclusion.
.github/workflows/daily-byok-ollama-test.lock.yml Adds generated model-routing and pricing configuration.

Review details

Tip

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

  • Files reviewed: 3/3 changed files
  • Comments generated: 3
  • Review effort level: Balanced

Comment on lines +55 to +57
function isSetFailedArgPrefixedVersion(errorArg: TSESTree.Expression, setFailedArg: TSESTree.Expression, sourceCode: SourceCode): boolean {
if (errorArg.type !== AST_NODE_TYPES.TemplateLiteral) return false;
if (setFailedArg.type !== AST_NODE_TYPES.TemplateLiteral) return false;
(umask 177 && touch /tmp/gh-aw/threat-detection/detection.log)
GH_AW_MAX_AI_CREDITS="${{ vars.GH_AW_DEFAULT_DETECTION_MAX_AI_CREDITS || '400' }}"
printf '%s\n' "{\"\$schema\":\"https://github.com/github/gh-aw-firewall/releases/download/v0.27.43/awf-config.schema.json\",\"network\":{\"allowDomains\":[\"api.business.githubcopilot.com\",\"api.enterprise.githubcopilot.com\",\"api.github.com\",\"api.githubcopilot.com\",\"api.individual.githubcopilot.com\",\"github.com\",\"host.docker.internal\",\"raw.githubusercontent.com\",\"registry.npmjs.org\",\"telemetry.enterprise.githubcopilot.com\"]},\"apiProxy\":{\"enabled\":true,\"enableTokenSteering\":true,\"maxRuns\":500,\"maxAiCredits\":${GH_AW_MAX_AI_CREDITS},\"maxCacheMisses\":5,\"targets\":{\"copilot\":{\"host\":\"host.docker.internal:11434\"}}},\"container\":{\"imageTag\":\"0.27.43,squid=sha256:26be5e0b8c8f4c41c8a59126b29bb5d80b07253597472ded2a16bdd75abcbf9d,agent=sha256:04e2d1987a565000a8f114b89d806ae7a3864dd4f944be65275b28c93d8690e6,api-proxy=sha256:d85f57975af5ea23af4996e41ed73fbc8f5b4a47402472bfe82e508f352cb0c1,cli-proxy=sha256:65c45ea2967984d0024f3df61bc71335658a77ede96c8d9665da7a5f33a795ab\"},\"logging\":{\"proxyLogsDir\":\"/tmp/gh-aw/sandbox/firewall/logs\",\"auditDir\":\"/tmp/gh-aw/sandbox/firewall/audit\"}}" > "${RUNNER_TEMP}/gh-aw/awf-config.json"
printf '%s\n' "{\"\$schema\":\"https://github.com/github/gh-aw-firewall/releases/download/v0.27.43/awf-config.schema.json\",\"network\":{\"allowDomains\":[\"api.business.githubcopilot.com\",\"api.enterprise.githubcopilot.com\",\"api.github.com\",\"api.githubcopilot.com\",\"api.individual.githubcopilot.com\",\"github.com\",\"host.docker.internal\",\"raw.githubusercontent.com\",\"registry.npmjs.org\",\"telemetry.enterprise.githubcopilot.com\"]},\"apiProxy\":{\"enabled\":true,\"enableTokenSteering\":true,\"maxRuns\":500,\"maxAiCredits\":${GH_AW_MAX_AI_CREDITS},\"maxCacheMisses\":5,\"defaultAiCreditsPricing\":{\"input\":0.000001,\"output\":0.000001},\"targets\":{\"copilot\":{\"host\":\"host.docker.internal:11434\"}},\"models\":{\"agent\":[\"sonnet-6x\",\"gpt-5.4\",\"gpt-5.5\",\"gpt-5.6\",\"gpt-5.3\",\"gemini-pro\",\"any\"],\"antigravity\":[\"copilot/antigravity*\",\"google/antigravity*\",\"gemini/antigravity*\"],\"any\":[\"copilot/*\",\"anthropic/*\",\"openai/*\",\"google/*\",\"gemini/*\"],\"auto\":[\"copilot/auto\",\"large\"],\"claude\":[\"agent\"],\"codex\":[\"agent\"],\"coding\":[\"copilot/gpt-5*codex*\",\"openai/gpt-5*codex*\",\"gpt-5-codex\",\"kimi\"],\"computer-use\":[\"copilot/*computer-use*\",\"google/*computer-use*\",\"gemini/*computer-use*\",\"openai/*computer-use*\"],\"copilot\":[\"agent\"],\"deep-research\":[\"copilot/deep-research*\",\"copilot/o3-deep-research*\",\"copilot/o4-mini-deep-research*\",\"google/deep-research*\",\"gemini/deep-research*\",\"openai/o3-deep-research*\",\"openai/o4-mini-deep-research*\"],\"fable\":[\"copilot/*fable*\",\"anthropic/*fable*\"],\"gemini\":[\"agent\"],\"gemini-3-flash\":[\"copilot/gemini-3*flash*\",\"google/gemini-3*flash*\",\"gemini/gemini-3*flash*\"],\"gemini-3-pro\":[\"copilot/gemini-3*pro*\",\"google/gemini-3*pro*\",\"google/nano-banana*\",\"gemini/gemini-3*pro*\"],\"gemini-3.1-flash\":[\"copilot/gemini-3.1*flash*\",\"google/gemini-3.1*flash*\",\"gemini/gemini-3.1*flash*\"],\"gemini-3.1-pro\":[\"copilot/gemini-3.1*pro*\",\"google/gemini-3.1*pro*\",\"gemini/gemini-3.1*pro*\"],\"gemini-3.5-flash\":[\"copilot/gemini-3.5*flash*\",\"google/gemini-3.5*flash*\",\"gemini/gemini-3.5*flash*\"],\"gemini-3.6-flash\":[\"copilot/gemini-3.6*flash*\",\"google/gemini-3.6*flash*\",\"gemini/gemini-3.6*flash*\"],\"gemini-flash\":[\"copilot/gemini-*flash*\",\"google/gemini-*flash*\",\"gemini/gemini-*flash*\"],\"gemini-flash-lite\":[\"copilot/gemini-*flash*lite*\",\"google/gemini-*flash*lite*\",\"gemini/gemini-*flash*lite*\"],\"gemini-omni\":[\"copilot/gemini-omni*\",\"google/gemini-omni*\",\"gemini/gemini-omni*\"],\"gemini-pro\":[\"copilot/gemini-*pro*\",\"google/gemini-*pro*\",\"gemini/gemini-*pro*\"],\"gemma\":[\"copilot/gemma*\",\"google/gemma*\",\"gemini/gemma*\"],\"gpt-5\":[\"copilot/gpt-5*\",\"openai/gpt-5*\"],\"gpt-5-codex\":[\"copilot/gpt-5*codex*\",\"openai/gpt-5*codex*\"],\"gpt-5-mini\":[\"copilot/gpt-5*mini*\",\"openai/gpt-5*mini*\"],\"gpt-5-nano\":[\"copilot/gpt-5*nano*\",\"openai/gpt-5*nano*\"],\"gpt-5-pro\":[\"copilot/gpt-5*pro*\",\"openai/gpt-5*pro*\"],\"gpt-5.1\":[\"copilot/gpt-5.1*\",\"openai/gpt-5.1*\"],\"gpt-5.2\":[\"copilot/gpt-5.2*\",\"openai/gpt-5.2*\"],\"gpt-5.3\":[\"copilot/gpt-5.3*\",\"openai/gpt-5.3*\"],\"gpt-5.4\":[\"copilot/gpt-5.4*\",\"openai/gpt-5.4*\"],\"gpt-5.5\":[\"copilot/gpt-5.5*\",\"openai/gpt-5.5*\"],\"gpt-5.6\":[\"copilot/gpt-5.6*\",\"openai/gpt-5.6*\"],\"grok\":[\"copilot/*grok*\",\"openai/*grok*\"],\"haiku\":[\"copilot/*haiku*\",\"anthropic/*haiku*\"],\"image-generation\":[\"copilot/gpt-image*\",\"openai/gpt-image*\",\"openai/chatgpt-image*\",\"copilot/gemini-*image*\",\"google/gemini-*image*\",\"gemini/gemini-*image*\",\"google/imagen*\"],\"kimi\":[\"copilot/kimi*\",\"openai/kimi*\"],\"kiwi\":[\"copilot/kiwi*\",\"openai/kiwi*\"],\"large\":[\"sonnet\",\"gpt-5-pro\",\"gpt-5\",\"gemini-pro\"],\"lyria\":[\"google/lyria*\",\"gemini/lyria*\",\"copilot/lyria*\"],\"mai-code\":[\"copilot/MAI-Code*\",\"copilot/mai-code*\",\"openai/MAI-Code*\"],\"mai-code-1-flash-picker\":[\"copilot/MAI-Code-1-Flash-picker*\",\"copilot/mai-code-1-flash-picker*\",\"openai/MAI-Code-1-Flash-picker*\"],\"mini\":[\"haiku\",\"gpt-5-mini\",\"gpt-5-nano\",\"gemini-flash-lite\"],\"nano-banana\":[\"copilot/nano-banana*\",\"google/nano-banana*\",\"gemini/nano-banana*\"],\"opus\":[\"copilot/*opus*\",\"anthropic/*opus*\"],\"opusplan\":[\"opus?effort=high\"],\"raptor-mini\":[\"copilot/raptor*\",\"openai/raptor*\"],\"reasoning\":[\"copilot/o1*\",\"copilot/o3*\",\"copilot/o4*\",\"openai/o1*\",\"openai/o3*\",\"openai/o4*\"],\"robotics\":[\"copilot/*robotics*\",\"google/*robotics*\",\"gemini/*robotics*\"],\"small\":[\"mini\"],\"small-agent\":[\"haiku\",\"gpt-5-mini\",\"gemini-flash\"],\"sonnet\":[\"copilot/*sonnet*\",\"anthropic/*sonnet*\"],\"sonnet-6x\":[\"copilot/*sonnet-4.5*\",\"copilot/*sonnet-4.6*\",\"copilot/*sonnet-5*\",\"copilot/*sonnet-4-5-*\",\"anthropic/*sonnet-4-5-*\",\"copilot/*sonnet-4-6*\",\"anthropic/*sonnet-4-6*\",\"anthropic/*sonnet-5*\"],\"summarization\":[\"haiku\",\"gpt-5-mini\",\"gemini-flash-lite\",\"mini\"],\"veo\":[\"google/veo*\",\"gemini/veo*\"],\"vision\":[\"copilot/gemini-*image*\",\"google/gemini-*image*\",\"gemini/gemini-*image*\",\"copilot/gemini-*flash*\",\"google/gemini-*flash*\",\"gemini/gemini-*flash*\"]}},\"container\":{\"imageTag\":\"0.27.43,squid=sha256:26be5e0b8c8f4c41c8a59126b29bb5d80b07253597472ded2a16bdd75abcbf9d,agent=sha256:04e2d1987a565000a8f114b89d806ae7a3864dd4f944be65275b28c93d8690e6,api-proxy=sha256:d85f57975af5ea23af4996e41ed73fbc8f5b4a47402472bfe82e508f352cb0c1,cli-proxy=sha256:65c45ea2967984d0024f3df61bc71335658a77ede96c8d9665da7a5f33a795ab\"},\"logging\":{\"proxyLogsDir\":\"/tmp/gh-aw/sandbox/firewall/logs\",\"auditDir\":\"/tmp/gh-aw/sandbox/firewall/audit\"}}" > "${RUNNER_TEMP}/gh-aw/awf-config.json"
Comment on lines +214 to +215
const exactMatch = sourceCode.getText(errorArg) === sourceCode.getText(setFailedArg);
if (!exactMatch && !isSetFailedArgPrefixedVersion(errorArg, setFailedArg, sourceCode)) continue;

@github-actions github-actions Bot 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.

The isSetFailedArgPrefixedVersion implementation is correct and well-guarded. The null checks for cooked values, expression count guards, and suffix/junction quasi matching all look sound. Test cases properly cover literal prefix, expression prefix, and the suffix non-match case. No blocking issues.

🧵 Reviewed using Impeccable skills by Impeccable Skills Reviewer · sonnet46 · 12.5 AIC · ⌖ 7.15 AIC · ⊞ 5.3K

@github-actions

github-actions Bot commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

🧪 Test Quality Sentinel Report

Test Quality Score: 100/100 — Excellent

Analyzed 2 test(s): 2 design, 0 implementation, 0 violation(s).

📊 Metrics (2 tests)
Metric Value
Analyzed 2 (TypeScript vitest)
✅ Design 2 (100%)
⚠️ Implementation 0 (0%)
Edge/error coverage 2 (100%)
Duplicate clusters 0
Inflation No (0.32:1 ratio)
🚨 Violations 0
Test Location Classification
code: core.error(...); core.setFailed(ERR: ...); line 84 Design, error case, suggestion verified
code: core.error(...); core.setFailed(${ERR_API}: ...); line 94 Design, error case, real-world pattern

Verdict

passed. 0% implementation tests (threshold: 30%). Both new test cases verify the core ESLint rule logic for detecting prefixed template literals with exact output assertions.

Highlights:

  • Real-world coverage: second test mirrors actual codebase pattern from add_reaction.cjs:184-185
  • Minimal test inflation: 22 new test lines vs 68 source lines
  • Complete error specification: both tests verify messageId, suggestions, and exact output format

🧪 Test quality analysis by Test Quality Sentinel · haiku45 · 11.6 AIC · ⌖ 6.75 AIC · ⊞ 8.4K ·
Comment /review to run again

@github-actions github-actions Bot 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.

✅ Test Quality Sentinel: 100/100. 0% implementation tests (threshold: 30%). Both new test cases verify the core ESLint rule logic for detecting prefixed template literals with exact output assertions. Real-world coverage mirrors add_reaction.cjs pattern.

@github-actions github-actions Bot 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.

Skills-Based Review 🧠

Applied /diagnosing-bugs and /tdd — requesting changes for two targeted issues.

📋 Key Themes & Highlights

Issues

  • Null guard gap (no-core-error-then-setfailed.ts:75): intermediate quasis are compared with !== without guarding for cooked === null. Since null !== null is false, two quasis whose escape sequences are both invalid would be incorrectly treated as equal, creating false-positive lint reports. The junction-quasi check at lines 81–82 already does the right thing — apply the same pattern to the inner loop.
  • Missing test (no-core-error-then-setfailed.test.ts): the expression-first errorArg path (${msg} with no leading text) is not covered. Since endsWith('') is always true, the empty-leading-quasi edge case relies entirely on the prefixExprCount > 0 guard — a test would lock in this behaviour.

Positive Highlights

  • ✅ Algorithm design is sound: suffix additions are correctly excluded, expression alignment via source-text comparison is robust
  • ✅ Comprehensive JSDoc comment clearly lays out all six match conditions
  • ✅ New tests mirror an actual codebase pattern (add_reaction.cjs:184-185), making the intent concrete

🧠 Reviewed using Matt Pocock's skills by Matt Pocock Skills Reviewer · sonnet46 · 36.8 AIC · ⌖ 7.61 AIC · ⊞ 7K
Comment /matt to run again


// Quasis at offsets [prefixExprCount+1 .. end] of sfTpl must equal errTpl quasis [1 .. end].
for (let i = 1; i < errTpl.quasis.length; i++) {
if (sfTpl.quasis[prefixExprCount + i].value.cooked !== errTpl.quasis[i].value.cooked) return false;

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.

[/diagnosing-bugs] Null guard missing for intermediate quasis — when a template literal contains an invalid escape sequence, cooked is null, and null !== null evaluates to false, causing two structurally different null quasis to be treated as equal (false positive).

💡 Suggested fix
const sfCooked = sfTpl.quasis[prefixExprCount + i].value.cooked;
const errCooked = errTpl.quasis[i].value.cooked;
if (sfCooked === null || errCooked === null || sfCooked !== errCooked) return false;

This brings the inner-quasi check in line with the null guard already applied at lines 81–82 for the junction quasi.

@copilot please address this.

},
],
});
});

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.

[/tdd] Missing edge-case: errorArg starts with an expression (empty leading quasi). When errTpl.quasis[0].value.cooked === '' and the junction quasi ends with '', endsWith('') is always true, so the prefix guard at line 85 becomes the only safeguard. Add a test to document the expected behaviour:

💡 Suggested test case
// Expression-first error arg with expression prefix in setFailed
{
  code: 'core.error(`${msg}`); core.setFailed(`ERR: ${msg}`);',
  errors: [{ messageId: 'noCoreErrorThenSetFailed', ... }],
},

This exercises the empty-leading-quasi path and confirms that prefixExprCount > 0 correctly drives the non-empty-prefix guard when errFirstCooked === ''.

@copilot please address this.

@github-actions github-actions Bot 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.

Verdict: Comment (no blocking issues)

Solid, well-tested implementation of a legitimate rule improvement. Findings below are non-blocking hardening/test-coverage suggestions.

💡 Themes
  • The new prefix-match heuristic in is textually-based (source-text equality of expressions, cooked-value equality of quasis). This is consistent with the existing exact-match approach in the rule but widens the matching surface, so false positives (flagging genuinely non-redundant pairs) are somewhat more likely than before, though the risk is mitigated by this only producing a suggestion, not an autofix.
  • Test coverage is good for the primary new cases (literal prefix, expression prefix, suffix-not-flagged) but misses a couple of boundary conditions in the new function: zero-expression error templates with a prefix expression, and the null-guard branch.
  • No correctness bugs found in the array-indexing logic itself (quasis/expressions loop bounds were checked and are consistent with invariants).

🔎 Code quality review by PR Code Quality Reviewer · auto · 64.8 AIC · ⌖ 10.6 AIC · ⊞ 7.8K
Comment /review to run again


// Last errTpl.expressions.length expressions of sfTpl must match errTpl's expressions.
for (let i = 0; i < errTpl.expressions.length; i++) {
const sfExpr = sfTpl.expressions[prefixExprCount + i] as TSESTree.Expression;

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.

Expression-prefix matching relies purely on textual source comparison, which can be fooled by non-obvious cases.

💡 Details

Both exactMatch and isSetFailedArgPrefixedVersion compare sourceCode.getText(expr) for equality. This was already the approach for the exact-match case, but the new prefix-matching path widens the blast radius: it now also compares multiple expressions per call pair (all of errTpl.expressions) and glues cooked quasi text together, so more real-world call sites will be auto-matched and their core.error() calls silently removed by the removeErrorCall suggestion.

Textual equality does not guarantee semantic equality — e.g. a shadowed err in nested scope, or an expression whose evaluation has a side effect visible only through equality-of-text but not equality-of-runtime-value (rare, but the existing isSideEffectFree check only protects against side effects in the removed call, not against divergent runtime values between the two call sites).

Suggested hardening: since this is a suggestion (not autofix), reviewers already vet it manually, so the risk is moderate rather than critical. Still worth documenting this limitation explicitly in the function doc comment so future maintainers don't assume textual equality implies semantic equality.

@@ -88,6 +79,26 @@ describe("no-core-error-then-setfailed", () => {
},

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.

New prefix-matching branches lack tests for zero-expression error templates and null-cooked quasis, leaving two guard conditions unverified.

💡 Details

isSetFailedArgPrefixedVersion has at least two branches with no covering test case:

  1. errTpl.expressions.length === 0 (a plain literal-only core.error(\Failed`)) paired with a setFailedtemplate that has a prefix expression, e.g.core.setFailed(`${ERR_CODE}: Failed`). This exercises prefixExprCount > 0with the loop overerrTpl.expressionsnever running — a distinct code path from the two invalid tests added, which both useerrTpl.expressions.length === 1`.
  2. The cooked === null guard (if (junctionCooked === null || errFirstCooked === null) return false;) — reachable when a template literal contains an invalid escape sequence — has no test, so a regression that inverts or removes this null check would go undetected.

Adding two more invalid/valid cases would close this gap and lock in the intended behavior for both edge cases.

@github-actions

github-actions Bot commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

PR Triage

  • Category: refactor | Risk: low | Priority: medium
  • Score: 43/100 (impact 20 + urgency 8 + quality 15)
  • Recommended action: batch_review

Note: ESLint tooling rule addition, has tests, CI green

Generated by 🔧 PR Triage Agent · auto · 48.9 AIC · ⌖ 6.24 AIC · ⊞ 7.9K ·

@gh-aw-bot

Copy link
Copy Markdown
Collaborator

@copilot please address the remaining review feedback, refresh the branch if GitHub allows it, and run the pr-finisher skill before handoff.

Current maintainer-facing blockers:

  • changes-requested review from Matt Pocock Skills Reviewer on null-cooked quasi guarding in the intermediate-quasi loop
  • add coverage for the expression-first / empty-leading-quasi edge case called out in review
  • once updated, summarize whether any unresolved reviewer comments can be closed

Please summarize which comments are fully addressed, whether any stale blocking reviews remain, and what still needs maintainer action.

Generated by 👨‍🍳 PR Sous Chef · gpt54 · 14.6 AIC · ⌖ 13.9 AIC · ⊞ 8.1K ·
Comment /souschef to run again

…e-case tests

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

Copilot AI commented Aug 1, 2026

Copy link
Copy Markdown
Contributor Author

@copilot please address the remaining review feedback, refresh the branch if GitHub allows it, and run the pr-finisher skill before handoff.

Current maintainer-facing blockers:...

Addressed all remaining review feedback in commit b5cf65d:

Changes made:

  1. BinaryExpression support — Added isSetFailedArgStringConcatPrefixedVersion which flags core.setFailed("ERR: " + \Failed: ${msg}`)when the right operand is identical in source toerrorArg`. Corresponding invalid test added.

  2. Null-cooked quasi guarding — The intermediate-quasi loop (previously sfTpl.quasis[...].value.cooked !== errTpl.quasis[...].value.cooked) now explicitly extracts each cooked value, checks for null (produced by invalid Unicode escape sequences like \u{INVALID}), and returns false if either is null.

  3. Expression-first / empty-leading-quasi edge case — Added an invalid test: core.error(\${msg} failed`); core.setFailed(`ERR: ${msg} failed`);whereerrorArghas an empty leading quasi. The matcher handles this correctly since"ERR: ".endsWith("") is always true, and the prefix non-empty check (junctionCooked.length > 0`) guards against false exact-equal matches.

Lock file note: The daily-byok-ollama-test.lock.yml change in the PR is the correct compiled output for the current daily-byok-ollama-test.md source (the .md was updated in main before this branch, and make recompile produces the same result). make check-workflow-drift confirms no drift.

Stale blocking reviews: The Matt Pocock Skills Reviewer blocking review on null-cooked quasi guarding and expression-first edge cases is now fully addressed. No other unresolved reviewer comments require maintainer action.

Copilot AI requested a review from gh-aw-bot August 1, 2026 07:45
@pelikhan
pelikhan merged commit d2c5f25 into main Aug 1, 2026
@pelikhan
pelikhan deleted the copilot/fix-eslint-no-core-error branch August 1, 2026 07:53
@github-actions

github-actions Bot commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

🎉 This pull request is included in a new release.

Release: v0.84.2

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

Projects

None yet

4 participants