diff --git a/.github/scripts/issue-quality-core.cjs b/.github/scripts/issue-quality-core.cjs index c6abfacf1d..40fadaca6d 100644 --- a/.github/scripts/issue-quality-core.cjs +++ b/.github/scripts/issue-quality-core.cjs @@ -1134,10 +1134,8 @@ const REPRO_PATH_RE = new RegExp([ "~?/[\\w.@-]+(?:/[\\w.@-]+)+", "[A-Za-z]:\\\\(?:[\\w.@-]+\\\\)+[\\w.@-]+", "~?/[\\w.@-]+/[\\w.@-]+\\.(?:json|yaml|yml|toml|conf|log|env|txt|ts|js|tsx|jsx|sh|ps1|py)", - "[\\w.@-]+\\.(?:json|yaml|yml|toml|conf|log|env)\\b", -].join("|")); -const ACTIONABLE_REPRO_RE = new RegExp( - [REPRO_COMMAND_RE.source, REPRO_FAILURE_RE.source, REPRO_PATH_RE.source].join("|"), + "(?:^|[^\\w.@-])[\\w.@-]+\\.(?:json|yaml|yml|toml|conf|log|env)\\b", +].join("|"), "i", ); @@ -1151,9 +1149,18 @@ const EMPTY_FENCE_RE = /^[ \t]{0,3}(?:```+|~~~+)\s*\n\s*\n[ \t]{0,3}(?:```+|~~~+ * count as actionable when their body contains non-whitespace content. */ function hasActionableReproductionDetail(text) { + if (typeof text !== "string") return false; + // Avoid Markdown cleanup and path matching when the raw input cannot contain + // actionable syntax. Fences remain eligible through their ` / ~ sigils. + if (!/[./\\`~]/.test(text) && !REPRO_COMMAND_RE.test(text) && !REPRO_FAILURE_RE.test(text)) { + return false; + } const c = clean(text); if (!c) return false; - if (ACTIONABLE_REPRO_RE.test(c)) return true; + if (REPRO_COMMAND_RE.test(c) || REPRO_FAILURE_RE.test(c)) return true; + // A boundary-anchored filename avoids retrying the same long token from each + // successive character while preserving case-insensitive extension matches. + if (/[./\\]/.test(c) && REPRO_PATH_RE.test(c)) return true; // Fenced blocks: only count when the body has non-whitespace content. if (/```|~~~/.test(c)) { const parts = stripFencedActionableContent(c); diff --git a/.github/scripts/issue-quality.test.cjs b/.github/scripts/issue-quality.test.cjs index bae797ec41..15a4ec68ab 100644 --- a/.github/scripts/issue-quality.test.cjs +++ b/.github/scripts/issue-quality.test.cjs @@ -713,6 +713,13 @@ describe("validateIssue - feature", () => { assert.equal(hasActionableReproductionDetail("```\nSIGSEGV at 0x0000\n```"), true); }); + it("bounds long non-matching reproduction path tokens", () => { + const startedAt = performance.now(); + assert.equal(hasActionableReproductionDetail(`${"a".repeat(60_000)}.unknown`), false); + assert.ok(performance.now() - startedAt < 500, "actionable reproduction check took too long"); + assert.equal(hasActionableReproductionDetail("CONFIG.JSON"), true); + }); + it("rejects fenced placeholder-only examples", () => { const fencedPlaceholders = [ "```\nN/A\n```",