diff --git a/src/github/commands.ts b/src/github/commands.ts index f540ac5890..092349bec7 100644 --- a/src/github/commands.ts +++ b/src/github/commands.ts @@ -1484,13 +1484,16 @@ export function sanitizePublicComment(value: string): string { .replace(/\bopen pr count\s+\d+\s+exceeds threshold\s+\d+\b\.?/gi, "private context") .replace(/\bopen pr count is at or below\s+\d+\b/gi, "private context") .replace(/\bcredibility\s+[-+]?\d+(?:\.\d+)?\s+is below floor\s+[-+]?\d+(?:\.\d+)?\b\.?/gi, "private context") - .replace(/\b(?:effective|projected) score(?: changes?)?\b(?:\s+from)?\s+[-+]?\d+(?:\.\d+)?\s*(?:->|→|to)\s*[-+]?\d+(?:\.\d+)?/gi, "private context") + .replace(/\b(?:effective|projected|estimated) score(?: changes?)?\b(?:\s+from)?\s+[-+]?\d+(?:\.\d+)?\s*(?:->|→|to)\s*[-+]?\d+(?:\.\d+)?/gi, "private context") .replace(/\b(raw trust score|trust score|wallet|hotkey|coldkey|seed phrase|mnemonic)\b/gi, "private context") .replace(/\b(public score estimate|estimated score|score estimate|estimated rewards?|rewards?|reward estimates?|payout|farming|scoreability|score preview|projected score changes?)\b/gi, "private context") .replace(/\b(private reviewability|reviewability internals?)\b/gi, "private context") .replace(/\b(private rankings?|rankings?)\b/gi, "private context") .replace(/\b(?:open_pr_pressure|closed_pr_credibility|low_credibility|maintainer_lane|inactive_or_unknown_lane|issue_discovery_only)\b/gi, "private context") .replace(/\b(?:credibility(?: updates?)?|closed pr credibility|low credibility|open pr pressure)\b/gi, "private context") + // Catch-all: a phrase replacement above (e.g. "score estimate"/"score preview") can leave a bare + // numeric score transition behind ("private context 32.5 -> 41.2"); redact those residual numbers too. + .replace(/\bprivate context\b\s+[-+]?\d+(?:\.\d+)?\s*(?:->|→|to)\s*[-+]?\d+(?:\.\d+)?/gi, "private context") .replace(/\blikely_duplicate\b/gi, "possible overlap with existing work"); return sanitizeReviewabilityTerm(sanitized).replace(/private context(?:,\s*private context)+/gi, "private context"); } diff --git a/test/unit/github-commands.test.ts b/test/unit/github-commands.test.ts index fe6b2e8638..2a807faf6a 100644 --- a/test/unit/github-commands.test.ts +++ b/test/unit/github-commands.test.ts @@ -156,6 +156,11 @@ describe("GitHub mention commands", () => { expect(sanitizePublicComment("public score estimate private scoreability context score preview")).not.toMatch(/public score estimate|scoreability|score preview/i); expect(sanitizePublicComment("projected score changes 12.3 -> 45.6")).not.toMatch(/projected score changes|12\.3|45\.6/i); expect(sanitizePublicComment("effective score 0 -> 42")).not.toMatch(/effective score|0|42/i); + // The score engine (buildGateDeltas) emits the "estimated score N -> M" wording — the raw numbers must + // be redacted too, not just the words (the catch-all also clears residual numbers from other phrases). + expect(sanitizePublicComment("Open PR pressure changes estimated score 32.5 -> 41.2.")).not.toMatch(/estimated score|32\.5|41\.2/i); + expect(sanitizePublicComment("Linked issue/no-issue context changes estimated score 18 -> 27.")).not.toMatch(/estimated score|18|27/i); + expect(sanitizePublicComment("score estimate 5 → 9")).not.toMatch(/score estimate|\b5\b|\b9\b/i); expect(sanitizePublicComment("Open PR count 7 exceeds threshold 3.")).not.toMatch(/open PR count|7|threshold|3/i); expect(sanitizePublicComment("Credibility 0.12 is below floor 0.4.")).not.toMatch(/credibility|0\.12|floor|0\.4/i); expect(sanitizePublicComment("open_pr_pressure closed_pr_credibility low_credibility credibility updates")).not.toMatch(/open_pr_pressure|closed_pr_credibility|low_credibility|credibility/i);