@@ -147,9 +147,17 @@ function surfaceGithubWarnings(source: string, warnings: string[]): void {
147147 }
148148}
149149
150- async function computeCandidates ( query : DiscoveryIndexQuery , deps : DiscoveryQueryDeps ) : Promise < DiscoveryIndexCandidate [ ] > {
150+ interface ComputeCandidatesResult {
151+ candidates : DiscoveryIndexCandidate [ ] ;
152+ /** False when any fetchRepoIssues/searchIssues call returned warnings — an incomplete live snapshot is
153+ * inconclusive, not evidence, and must not be promoted into the shared result cache. */
154+ complete : boolean ;
155+ }
156+
157+ async function computeCandidates ( query : DiscoveryIndexQuery , deps : DiscoveryQueryDeps ) : Promise < ComputeCandidatesResult > {
151158 const seen = new Set < string > ( ) ;
152159 const candidates : DiscoveryIndexCandidate [ ] = [ ] ;
160+ let complete = true ;
153161
154162 const addCandidate = ( repoFullName : string , issue : GitHubIssue , verdict : AiPolicyVerdict ) : void => {
155163 const candidate = buildCandidate ( repoFullName , issue , verdict ) ;
@@ -174,28 +182,31 @@ async function computeCandidates(query: DiscoveryIndexQuery, deps: DiscoveryQuer
174182 const verdict = await resolveRepoAiPolicy ( repoFullName , deps ) ;
175183 if ( ! verdict . allowed ) continue ;
176184 const { issues, warnings } = await deps . github . fetchRepoIssues ( repoFullName ) ;
185+ if ( warnings . length > 0 ) complete = false ;
177186 surfaceGithubWarnings ( repoFullName , warnings ) ;
178187 for ( const issue of issues ) addCandidate ( repoFullName , issue , verdict ) ;
179188 }
180189
181190 for ( const org of query . orgs ) {
182191 const searchQuery = `org:${ org } state:open type:issue` ;
183192 const { issues, warnings } = await deps . github . searchIssues ( searchQuery ) ;
193+ if ( warnings . length > 0 ) complete = false ;
184194 surfaceGithubWarnings ( searchQuery , warnings ) ;
185195 await addFromSearch ( issues ) ;
186196 }
187197
188198 for ( const term of query . searchTerms ) {
189199 const searchQuery = `${ term } state:open type:issue` ;
190200 const { issues, warnings } = await deps . github . searchIssues ( searchQuery ) ;
201+ if ( warnings . length > 0 ) complete = false ;
191202 surfaceGithubWarnings ( searchQuery , warnings ) ;
192203 await addFromSearch ( issues ) ;
193204 }
194205
195206 // Deterministic ordering so pagination offsets are stable across a cache lifetime (and identical for two
196- // requests that happen to race a cache miss — see computeCandidates' getOrCompute caller).
207+ // requests that happen to race a cache miss — see runDiscoveryQuery's result-cache caller).
197208 candidates . sort ( ( a , b ) => ( a . repoFullName === b . repoFullName ? a . issueNumber - b . issueNumber : a . repoFullName . localeCompare ( b . repoFullName ) ) ) ;
198- return candidates ;
209+ return { candidates, complete } ;
199210}
200211
201212/**
@@ -210,10 +221,17 @@ async function computeCandidates(query: DiscoveryIndexQuery, deps: DiscoveryQuer
210221export async function runDiscoveryQuery ( query : DiscoveryIndexQuery , deps : DiscoveryQueryDeps ) : Promise < DiscoveryIndexResponse > {
211222 const scopeKey = scopeCacheKey ( query ) ;
212223 let missed = false ;
213- const allCandidates = await deps . resultCache . getOrCompute ( scopeKey , deps . cacheTtlMs , ( ) => {
224+ let allCandidates = deps . resultCache . get ( scopeKey ) ;
225+ if ( allCandidates === undefined ) {
214226 missed = true ;
215- return computeCandidates ( query , deps ) ;
216- } ) ;
227+ const computed = await computeCandidates ( query , deps ) ;
228+ allCandidates = computed . candidates ;
229+ // An incomplete live snapshot is inconclusive, not evidence — return it to this caller but never
230+ // promote it into the shared result cache (mirrors listMigrationFilenamesAtRef's truncated-tree posture).
231+ if ( computed . complete ) {
232+ deps . resultCache . set ( scopeKey , allCandidates , deps . cacheTtlMs ) ;
233+ }
234+ }
217235 incr ( "discovery_index_cache_lookups_total" , { cache : "result" , outcome : missed ? "miss" : "hit" } ) ;
218236 const offset = decodeCursor ( query . cursor ) ;
219237 const page = allCandidates . slice ( offset , offset + query . limit ) ;
0 commit comments