@@ -31,6 +31,19 @@ function sortByUpdatedAt<T extends { updatedAt?: string; createdAt?: string; tim
3131 } ) ;
3232}
3333
34+ function expandConceptTerms ( values : string [ ] ) : string [ ] {
35+ return uniqueStrings ( [
36+ ...values ,
37+ ...values . flatMap ( ( value ) =>
38+ value
39+ . toLowerCase ( )
40+ . split ( / [ ^ a - z 0 - 9 _ . / : - ] + / )
41+ . map ( ( token ) => token . trim ( ) )
42+ . filter ( ( token ) => token . length >= 3 ) ,
43+ ) ,
44+ ] ) ;
45+ }
46+
3447function branchMatches (
3548 value : { branch ?: string } ,
3649 requested ?: string ,
@@ -83,11 +96,14 @@ async function relevantProjectObservations(
8396 . catch ( ( ) => null ) ,
8497 ) ,
8598 ) ;
86- return sortByUpdatedAt (
99+ const matchedObservations = sortByUpdatedAt (
87100 observations . filter (
88101 ( observation ) : observation is CompressedObservation => observation !== null ,
89102 ) ,
90103 ) ;
104+ if ( matchedObservations . length > 0 ) {
105+ return matchedObservations ;
106+ }
91107 }
92108
93109 return ( await projectObservations ( kv , project , branch ) ) . filter ( ( observation ) =>
@@ -136,13 +152,6 @@ export async function refreshComponentDossier(
136152 . filter ( ( insight ) => ! insight . deleted )
137153 . filter ( ( insight ) => ! insight . project || insight . project === project ) ,
138154 ) ;
139- const relatedInsights = insights . filter ( ( insight ) => {
140- const text = `${ insight . title } ${ insight . content } ` . toLowerCase ( ) ;
141- return (
142- text . includes ( filePath . toLowerCase ( ) ) ||
143- text . includes ( basename ( filePath ) . toLowerCase ( ) )
144- ) ;
145- } ) ;
146155 const guardrails = await listScopedGuardrails ( kv , {
147156 project,
148157 branch,
@@ -157,6 +166,25 @@ export async function refreshComponentDossier(
157166 activeOnly : true ,
158167 limit : 20 ,
159168 } ) ;
169+ const dossierConcepts = new Set (
170+ expandConceptTerms ( [
171+ ...observations . flatMap ( ( observation ) => observation . concepts ) ,
172+ ...guardrails . flatMap ( ( guardrail ) => guardrail . relatedConcepts ) ,
173+ ...decisions . flatMap ( ( decision ) => decision . relatedConcepts ) ,
174+ basename ( filePath ) ,
175+ ] ) . map ( ( concept ) => concept . toLowerCase ( ) ) ,
176+ ) ;
177+ const relatedInsights = insights . filter ( ( insight ) => {
178+ const text = `${ insight . title } ${ insight . content } ` . toLowerCase ( ) ;
179+ return (
180+ text . includes ( filePath . toLowerCase ( ) ) ||
181+ text . includes ( basename ( filePath ) . toLowerCase ( ) ) ||
182+ insight . sourceConceptCluster . some ( ( concept ) =>
183+ dossierConcepts . has ( concept . toLowerCase ( ) ) ,
184+ ) ||
185+ insight . tags . some ( ( tag ) => dossierConcepts . has ( tag . toLowerCase ( ) ) )
186+ ) ;
187+ } ) ;
160188 const overlays = sortByUpdatedAt (
161189 ( await kv . list < BranchOverlay > ( KV . branchOverlays ) . catch ( ( ) => [ ] ) )
162190 . filter ( ( overlay ) => overlay . project === project )
0 commit comments