@@ -577,7 +577,11 @@ function runPostNativeCha(
577577 AND INSTR(tgt.name, '.') > 0
578578 AND src.file IN (${ ph } )` ,
579579 )
580- . all ( ...chunk ) as Array < { source_id : number ; method_name : string ; caller_file : string | null } > ;
580+ . all ( ...chunk ) as Array < {
581+ source_id : number ;
582+ method_name : string ;
583+ caller_file : string | null ;
584+ } > ;
581585 rows . push ( ...chunkRows ) ;
582586 }
583587 callToMethods = rows ;
@@ -933,12 +937,20 @@ async function runPostNativeThisDispatch(
933937 return { elapsedMs : Date . now ( ) - t0 , targetIds, affectedFiles } ;
934938}
935939
940+ interface PostPassTimings {
941+ gapDetectMs : number ;
942+ chaMs : number ;
943+ thisDispatchMs : number ;
944+ reclassifyMs : number ;
945+ techniqueBackfillMs : number ;
946+ }
947+
936948/** Format timing result from native orchestrator phases + JS post-processing. */
937949function formatNativeTimingResult (
938950 p : Record < string , number > ,
939951 structurePatchMs : number ,
940952 analysisTiming : { astMs : number ; complexityMs : number ; cfgMs : number ; dataflowMs : number } ,
941- thisDispatchMs : number ,
953+ postPass : PostPassTimings ,
942954) : BuildResult {
943955 return {
944956 phases : {
@@ -951,7 +963,11 @@ function formatNativeTimingResult(
951963 edgesMs : + ( p . edgesMs ?? 0 ) . toFixed ( 1 ) ,
952964 structureMs : + ( ( p . structureMs ?? 0 ) + structurePatchMs ) . toFixed ( 1 ) ,
953965 rolesMs : + ( p . rolesMs ?? 0 ) . toFixed ( 1 ) ,
954- thisDispatchMs : + thisDispatchMs . toFixed ( 1 ) ,
966+ gapDetectMs : + postPass . gapDetectMs . toFixed ( 1 ) ,
967+ chaMs : + postPass . chaMs . toFixed ( 1 ) ,
968+ thisDispatchMs : + postPass . thisDispatchMs . toFixed ( 1 ) ,
969+ reclassifyMs : + postPass . reclassifyMs . toFixed ( 1 ) ,
970+ techniqueBackfillMs : + postPass . techniqueBackfillMs . toFixed ( 1 ) ,
955971 astMs : + ( analysisTiming . astMs ?? 0 ) . toFixed ( 1 ) ,
956972 complexityMs : + ( analysisTiming . complexityMs ?? 0 ) . toFixed ( 1 ) ,
957973 cfgMs : + ( analysisTiming . cfgMs ?? 0 ) . toFixed ( 1 ) ,
@@ -1490,8 +1506,14 @@ export async function tryNativeOrchestrator(
14901506 ctx . db = openDb ( ctx . dbPath ) ;
14911507 ctx . nativeFirstProxy = false ;
14921508 } else if ( ! ctx . nativeFirstProxy && ! handoffWalAfterNativeBuild ( ctx ) ) {
1493- // DB reopen failed — return partial result
1494- return formatNativeTimingResult ( p , 0 , analysisTiming , 0 ) ;
1509+ // DB reopen failed — return partial result (no post-pass phases completed)
1510+ return formatNativeTimingResult ( p , 0 , analysisTiming , {
1511+ gapDetectMs : 0 ,
1512+ chaMs : 0 ,
1513+ thisDispatchMs : 0 ,
1514+ reclassifyMs : 0 ,
1515+ techniqueBackfillMs : 0 ,
1516+ } ) ;
14951517 }
14961518 }
14971519
@@ -1513,6 +1535,7 @@ export async function tryNativeOrchestrator(
15131535 // gated below.
15141536 const removedCount = result . removedCount ?? 0 ;
15151537 const changedCount = result . changedCount ?? 0 ;
1538+ const gapDetectStart = performance . now ( ) ;
15161539 const gap = detectDroppedLanguageGap ( ctx ) ;
15171540 if (
15181541 result . isFullBuild ||
@@ -1523,6 +1546,7 @@ export async function tryNativeOrchestrator(
15231546 ) {
15241547 await backfillNativeDroppedFiles ( ctx , gap ) ;
15251548 }
1549+ const gapDetectMs = performance . now ( ) - gapDetectStart ;
15261550
15271551 // Phase 8.5: expand CHA call edges (interface dispatch → concrete implementations).
15281552 // Returns the affected files so role re-classification below can be scoped to
@@ -1531,11 +1555,13 @@ export async function tryNativeOrchestrator(
15311555 // Function-as-object-property methods (`fn.method = function() {}`) are extracted
15321556 // natively by the Rust engine (#1432) and resolved in-build by its edge builder, so
15331557 // no WASM re-parse post-pass is needed for them. `Foo.prototype.bar = fn` likewise.
1558+ const chaStart = performance . now ( ) ;
15341559 const { newEdgeCount : chaEdgeCount , affectedFiles : chaAffectedFiles } = runPostNativeCha (
15351560 ctx . db as unknown as BetterSqlite3Database ,
15361561 // null = full build (scan all call→method edges); array = incremental (gate queries decide scope)
15371562 result . isFullBuild ? null : ( result . changedFiles ?? null ) ,
15381563 ) ;
1564+ const chaMs = performance . now ( ) - chaStart ;
15391565
15401566 // Phase 8.5: this/super dispatch — hybrid WASM re-parse to resolve call sites
15411567 // whose raw receiver info the Rust pipeline does not persist to DB.
@@ -1558,6 +1584,7 @@ export async function tryNativeOrchestrator(
15581584 // files restores correctness without re-running the classifier over the
15591585 // whole graph (which cost ~130ms per build on codegraph itself and was a
15601586 // major part of the v3.12.0 native full-build benchmark regression).
1587+ let reclassifyMs = 0 ;
15611588 if ( chaEdgeCount > 0 || thisDispatchTargetIds . size > 0 ) {
15621589 const affectedFiles = [ ...new Set ( [ ...chaAffectedFiles , ...thisDispatchAffectedFiles ] ) ] ;
15631590 // When edges were inserted but all their endpoint nodes have null `file`
@@ -1566,6 +1593,7 @@ export async function tryNativeOrchestrator(
15661593 // case — scoped classification with an empty set would be a no-op, leaving
15671594 // roles stale for those nodes.
15681595 const scopedFiles = affectedFiles . length > 0 ? affectedFiles : null ;
1596+ const reclassifyStart = performance . now ( ) ;
15691597 try {
15701598 const { classifyNodeRoles } = ( await import ( '../../../../features/structure.js' ) ) as {
15711599 classifyNodeRoles : (
@@ -1582,13 +1610,16 @@ export async function tryNativeOrchestrator(
15821610 } catch ( err ) {
15831611 debug ( `Post-pass role re-classification failed: ${ toErrorMessage ( err ) } ` ) ;
15841612 }
1613+ reclassifyMs = performance . now ( ) - reclassifyStart ;
15851614 }
15861615
15871616 // Backfill the `technique` column on `calls` edges written by the Rust
15881617 // orchestrator, which does not write the column. Runs after all edge-writing
15891618 // phases (including the WASM dropped-language backfill, CHA post-pass, and
15901619 // this/super dispatch) so every new edge in this build cycle gets a label.
1620+ const techniqueBackfillStart = performance . now ( ) ;
15911621 backfillEdgeTechniquesAfterNativeOrchestrator ( ctx . db , ! ! result . isFullBuild , result . changedFiles ) ;
1622+ const techniqueBackfillMs = performance . now ( ) - techniqueBackfillStart ;
15921623
15931624 // Re-count nodes/edges now that all edge-writing post-passes have run: the
15941625 // Rust orchestrator captured its counts before the JS post-passes added
@@ -1633,5 +1664,11 @@ export async function tryNativeOrchestrator(
16331664 }
16341665
16351666 closeDbPair ( { db : ctx . db , nativeDb : ctx . nativeDb } ) ;
1636- return formatNativeTimingResult ( p , structurePatchMs , analysisTiming , thisDispatchMs ) ;
1667+ return formatNativeTimingResult ( p , structurePatchMs , analysisTiming , {
1668+ gapDetectMs,
1669+ chaMs,
1670+ thisDispatchMs,
1671+ reclassifyMs,
1672+ techniqueBackfillMs,
1673+ } ) ;
16371674}
0 commit comments