@@ -43,8 +43,8 @@ const AI_ANALYSIS_PATH = join(WORKSPACE_ROOT, '.ai-pr-analyzer/flaky-ai-analysis
4343const PRIOR_STATE_PATH = join ( WORKSPACE_ROOT , '.ai-pr-analyzer/flaky-prior-state.json' ) ;
4444
4545// Failure counts bucketed by lookback window (nested: a failure in 7d also
46- // counts in 30d/90d/365d ). Kept as a permissive Record so a future window edit
47- // in Stage 1 doesn't require a matching type change here.
46+ // counts in 30d). Kept as a permissive Record so a future window edit in
47+ // Stage 1 doesn't require a matching type change here.
4848type WindowCounts = Record < string , number > ;
4949
5050interface HistoryFile {
@@ -124,7 +124,7 @@ function readJsonOrEmpty<T>(path: string, emptyShape: T): T {
124124
125125// Fallback window set used only if the Stage 1 artifact predates the `windows`
126126// field; the live artifact always supplies its own list.
127- const DEFAULT_WINDOWS = [ 7 , 30 , 90 , 365 ] ;
127+ const DEFAULT_WINDOWS = [ 7 , 15 , 30 ] ;
128128
129129// Serializes per-file state into a hidden HTML comment appended to the comment
130130// body. Stage 1 reads this on the next push to decide which files need
@@ -133,16 +133,27 @@ function buildStateBlock(state: CommentState): string {
133133 return `${ STATE_MARKER } ${ JSON . stringify ( state ) } -->` ;
134134}
135135
136+ // Builds the table (or an empty-state fallback line) for the "Run history
137+ // flaky detection" section. tableFiles is the union of historically-flaky
138+ // files and files carrying an AI finding — see buildCommentBody — so an
139+ // empty list here only happens if that union itself is empty, which is a
140+ // rare safety fallback rather than the common case.
136141function buildHistoryTable (
137- flakyFiles : HistoryFile [ ] ,
142+ tableFiles : HistoryFile [ ] ,
138143 windows : number [ ] ,
139144 runsSampled : WindowCounts ,
140145) : string {
141- if ( flakyFiles . length === 0 ) return '' ;
146+ if ( tableFiles . length === 0 ) {
147+ const windowKeys = windows . map ( ( d ) => `${ d } d` ) ;
148+ const noRunsSampled = windowKeys . every ( ( key ) => ! runsSampled [ key ] ) ;
149+ return noRunsSampled
150+ ? 'No previous run to analyse for these tests.'
151+ : 'No historical failures found for the changed tests in the sampled runs.' ;
152+ }
142153 const windowKeys = windows . map ( ( d ) => `${ d } d` ) ;
143154 const header = `| File | ${ windowKeys . join ( ' | ' ) } |` ;
144155 const divider = `|---|${ windowKeys . map ( ( ) => '---|' ) . join ( '' ) } ` ;
145- const rows = flakyFiles
156+ const rows = tableFiles
146157 . map ( ( f ) => {
147158 // `failures/runs` — failures for the file over the number of countable
148159 // runs sampled in that window.
@@ -152,7 +163,7 @@ function buildHistoryTable(
152163 return `| \`${ f . path } \` | ${ cells } |` ;
153164 } )
154165 . join ( '\n' ) ;
155- return `### Historical CI failures on main\n\nFailures / runs sampled per window (nested — a failure in 7d is also counted in 30d/90d/365d) :\n\n${ header } \n${ divider } \n${ rows } \n` ;
166+ return `Failures / runs sampled per window:\n\n${ header } \n${ divider } \n${ rows } \n` ;
156167}
157168
158169function buildFindingsSection ( findings : Finding [ ] ) : string {
@@ -199,19 +210,27 @@ function buildCommentBody({
199210 runsSampled : WindowCounts ;
200211 stateBlock : string ;
201212} ) : string {
202- const flakyFiles = historyFiles . filter ( ( f ) => f . flaky ) ;
203- const historyTable = buildHistoryTable ( flakyFiles , windows , runsSampled ) ;
213+ // A file surfaces in the run-history table if it's historically flaky OR
214+ // an AI finding calls it out — otherwise an AI-only finding (zero
215+ // historical failures) would make the table disappear even though the
216+ // finding itself renders.
217+ const findingFiles = new Set ( findings . map ( ( f ) => f . file ) ) ;
218+ const tableFiles = historyFiles . filter ( ( f ) => f . flaky || findingFiles . has ( f . path ) ) ;
219+ const historyTable = buildHistoryTable ( tableFiles , windows , runsSampled ) ;
204220 const findingsSection = buildFindingsSection ( findings ) ;
205221
206222 return `${ MARKER }
207223## 🧪 Flaky unit test detection
208224
209- ${ historyTable }
225+ ### Run history flaky detection
226+
210227[View recent run history](${ runHistoryUrl } )
211228
212- ${ findingsSection }
213229Historical failure rate is a hint, not proof — review each suggestion in context. See the [flaky-test-detection skill](${ SKILL_LINK } ) for the full pattern reference and manual audit workflow.
214230
231+ ${ historyTable }
232+
233+ ${ findingsSection }
215234_This check is informational only and does not block merging._
216235${ stateBlock } `;
217236}
0 commit comments