From 4ba99743733f0930291e57fa047014af9b48e6ed Mon Sep 17 00:00:00 2001 From: Aaron Sachs <898627+asachs01@users.noreply.github.com> Date: Sun, 23 Aug 2026 02:14:22 +0000 Subject: [PATCH] fix(bus): widen check-stale-blockers precedent-citation exclude-list for stat-source citations A real, correctly-cited PR can still be a false positive if it's cited as the source of a supporting fact ("documented in-code by PR #NN as 13 verified against prod") rather than as the fix for the blocker. Distinct shape from precedent-citation (that class isn't naming a blocker at all). Bit the same task twice, two days apart (task_1786902033624, 2026-08-20 then 2026-08-22), both times resolved manually by the same peer -- the tool has no memory of a prior resolution, so it re-litigates indefinitely. Reuses the existing exclude-list mechanism (PRECEDENT_CITATION_CUE_REGEX, 2026-08-12) rather than new persisted state -- same failure shape, same fix technique. --- src/bus/system.ts | 14 ++++++- tests/unit/bus/system.test.ts | 70 +++++++++++++++++++++++++++++++++++ 2 files changed, 83 insertions(+), 1 deletion(-) diff --git a/src/bus/system.ts b/src/bus/system.ts index 3c24cba3a8..abbf05320d 100644 --- a/src/bus/system.ts +++ b/src/bus/system.ts @@ -249,11 +249,23 @@ const PR_REFERENCE_REGEX = /\bPR\s*#\s*(\d+)\b/gi; // narrow and nameable (precedent/example citation), so exclude it // specifically rather than narrowing the whole match surface. // +// Widened 2026-08-22 (analyst, task_1786902033624 — a check-stale-blockers +// sweep flagged the same false positive TWICE, two days apart, both times +// resolved by the same peer): a genuinely real, correctly-cited PR can still +// be a false positive if it's cited as the SOURCE OF A SUPPORTING FACT +// ("documented in-code by conduit PR #1424 as 13 verified against prod") +// rather than as the thing that resolves the blocker. This is a distinct +// shape from precedent-citation (that class isn't naming a blocker at all; +// this class names a real, relevant PR, just not as *the fix*) — added as a +// second cue category on the same exclude-list mechanism rather than new +// persisted state, since the failure mode (a citation-shape phrase near the +// reference) and the fix (widen the window check) are identical in kind. +// // No trailing \b: several cues end in a non-word char ("e.g."), and \b only // holds at a word/non-word transition — a trailing \b after "e.g." silently // never matches, since both the "." and the space after it are non-word. const PRECEDENT_CITATION_CUE_REGEX = - /\b(same (shape|pattern|approach|idiom) as|see .{0,10}for (the )?pattern|per the .{0,40}precedent|precedent|e\.g\.|for example|prior art)/i; + /\b(same (shape|pattern|approach|idiom) as|see .{0,10}for (the )?pattern|per the .{0,40}precedent|precedent|e\.g\.|for example|prior art|documented (in-code )?by|verified against|sourced from|per .{0,40}('s)? own (data|finding|number|stat))/i; // Some cues fully precede the reference ("same shape as ... PR #306"); one // straddles it ("see PR #12 for the pattern" — the reference sits INSIDE the diff --git a/tests/unit/bus/system.test.ts b/tests/unit/bus/system.test.ts index 8125db5b7b..161e341c5d 100644 --- a/tests/unit/bus/system.test.ts +++ b/tests/unit/bus/system.test.ts @@ -414,6 +414,28 @@ describe('Bus System', () => { expect(report.entries).toHaveLength(0); }); + // task_1786902033624 (grower/analyst, 2026-08-20 then again 2026-08-22): + // a check-stale-blockers sweep flagged the SAME task twice, two days + // apart, both times a false positive — conduit PR #1424 is a real, + // correctly-cited reference, but it's cited as the source of a + // supporting statistic ("13 lapsed rows verified against prod"), not as + // the fix for this task's blocker. Distinct from precedent-citation + // (that class isn't naming a blocker at all; this one names a real, + // relevant PR, just not as the thing that resolves the block). + it('does not flag a PR mention cited as the source of a supporting fact, not the fix ("documented ... by PR #NN as", "verified against")', () => { + writeTask('myorg', { + id: 'task_stat_source', + title: 'Trialing rows with NULL current_period_end are invisible to the scheduler', + status: 'blocked', + description: + '14 of 15 trialing rows are lapsed, documented in-code by conduit PR #1424 as 13 verified against prod 2026-08-15.', + }); + + const report = checkStaleBlockers(testDir); + + expect(report.entries).toHaveLength(0); + }); + it('still flags a genuine PR reference when "tool artifact" appears but not near that PR number', () => { writeTask('myorg', { id: 'task_unrelated_dismissal', @@ -431,6 +453,54 @@ describe('Bus System', () => { expect(report.entries[0].detail).not.toContain('PR #55'); }); + // NOTE: the two mentions are kept far apart on purpose (separate + // sentences, no shared clause) — this exercise found that a stat-source + // cue sitting in the GAP between two close references (e.g. "...verified + // against prod. This one is blocked on PR#67...") can leak into the + // NEXT reference's before-window despite the existing prev-match-end + // clamp, because that clamp only protects against reaching before/into + // the previous match's own span, not the trailing prose after it. Not + // fixed here — pre-existing architecture limitation (the after-window + // has no symmetric next-match-start clamp), same class as the "e.g." + // trailing-period note above, just not previously triggered because no + // existing cue phrase naturally sits in that gap zone. Flagging in case + // a tighter mixed-citation case is ever reported for real. + it('still flags a genuine blocking PR mention even when a stat-source citation appears earlier, well-separated, in the same description', () => { + writeTask('myorg', { + id: 'task_stat_source_mixed', + title: 'ship the fix', + status: 'blocked', + description: + 'Documented in-code by conduit PR #1424 as 13 verified against prod 2026-08-15. ' + + 'Separately, this task itself cannot proceed until PR#67 merges.', + }); + + const report = checkStaleBlockers(testDir); + + expect(report.entries).toHaveLength(1); + expect(report.entries[0].detail).toContain('PR #67'); + expect(report.entries[0].detail).not.toContain('PR #1424'); + }); + + it('does not flag other stat-source citation phrasings ("sourced from", "per PR #NN\'s own data")', () => { + writeTask('org-a', { + id: 'task_sourced_from', + title: 'reconcile the counts', + status: 'blocked', + description: 'The 41-org figure is sourced from PR #914.', + }); + writeTask('org-a', { + id: 'task_own_data', + title: 'confirm the regression window', + status: 'blocked', + description: 'Per PR #200\'s own data, the window is 72 hours.', + }); + + const report = checkStaleBlockers(testDir); + + expect(report.entries).toHaveLength(0); + }); + it('does not suppress a PR reference on the generic word "resolved" alone, only the narrow "tool artifact" cue', () => { writeTask('myorg', { id: 'task_generic_resolved',