@@ -81,15 +81,9 @@ export class KgObservationalService {
8181 s . add ( r . entity ) ;
8282 }
8383
84- const newHashes = new Set < string > ( ) ;
85- const valueRows : Array < {
86- organizationId : string ;
87- connectorId : string ;
88- valueHash : string ;
89- entity : string ;
90- field : string ;
91- direction : string ;
92- } > = [ ] ;
84+ // Edges accumulate across pages; the raw value rows are flushed per page
85+ // (below) so the in-memory set never grows to the size of the whole batch.
86+ let edges = 0 ;
9387 // references edges mined from response field names: key -> details.
9488 const refBumps = new Map <
9589 string ,
@@ -103,7 +97,7 @@ export class KgObservationalService {
10397 // Page through invocations so we never hold more than CHUNK full input/output
10498 // payloads in memory at once. A busy org's payloads can be megabytes each;
10599 // loading thousands together previously OOM'd the backend.
106- const CHUNK = 200 ;
100+ const CHUNK = 100 ;
107101 let processed = 0 ;
108102 while ( processed < MAX_INVOCATIONS_PER_RUN ) {
109103 const page = await this . prisma . toolInvocation . findMany ( {
@@ -124,6 +118,17 @@ export class KgObservationalService {
124118 if ( page . length === 0 ) break ;
125119 processed += page . length ;
126120
121+ // Per-page value occurrences, flushed at the end of each page.
122+ const newHashes = new Set < string > ( ) ;
123+ const valueRows : Array < {
124+ organizationId : string ;
125+ connectorId : string ;
126+ valueHash : string ;
127+ entity : string ;
128+ field : string ;
129+ direction : string ;
130+ } > = [ ] ;
131+
127132 for ( const inv of page ) {
128133 const connectorId = inv . connectorId ! ;
129134 // Skip invocations already covered by this connector's watermark.
@@ -185,16 +190,19 @@ export class KgObservationalService {
185190 }
186191 }
187192 } // for (const inv of page)
188- if ( page . length < CHUNK ) break ;
189- } // while pages
190193
191- if ( valueRows . length ) {
192- await this . prisma . kgValueSeen . createMany ( { data : valueRows } ) ;
193- }
194+ // Flush this page's value occurrences and correlate immediately. correlate
195+ // reads kgValueSeen (which now includes earlier pages), so cross-page
196+ // produces_consumes / same_identity links are still found.
197+ if ( valueRows . length ) {
198+ await this . prisma . kgValueSeen . createMany ( { data : valueRows } ) ;
199+ }
200+ if ( newHashes . size ) {
201+ edges += await this . correlate ( organizationId , [ ...newHashes ] ) ;
202+ }
194203
195- let edges = newHashes . size
196- ? await this . correlate ( organizationId , [ ...newHashes ] )
197- : 0 ;
204+ if ( page . length < CHUNK ) break ;
205+ } // while pages
198206
199207 // Apply references edges mined from response shapes.
200208 const refCache = new Map < string , string > ( ) ;
0 commit comments