diff --git a/package.json b/package.json index 97fe7551..e2b082ad 100644 --- a/package.json +++ b/package.json @@ -43,6 +43,7 @@ "clean": "node -e \"require('fs').rmSync('dist',{recursive:true,force:true});require('fs').rmSync('.tsbuildinfo',{force:true})\"", "prepare": "npm run build:wasm && npm run build && husky && npm run deps:tree", "deps:tree": "node scripts/node-ts.js scripts/gen-deps.ts", + "benchmark": "node --experimental-strip-types --import ./scripts/ts-resolve-loader.js scripts/benchmark.ts", "release": "commit-and-tag-version", "release:dry-run": "commit-and-tag-version --dry-run", "version": "node scripts/node-ts.js scripts/sync-native-versions.ts && git add package.json crates/codegraph-core/Cargo.toml" diff --git a/src/domain/graph/builder/stages/finalize.ts b/src/domain/graph/builder/stages/finalize.ts index 90d23757..f40c5a97 100644 --- a/src/domain/graph/builder/stages/finalize.ts +++ b/src/domain/graph/builder/stages/finalize.ts @@ -37,6 +37,10 @@ export async function finalize(ctx: PipelineContext): Promise { symbols._langId = undefined; } + // Capture a single wall-clock timestamp for the current build — used for + // both the stale-embeddings comparison and the persisted built_at metadata. + const buildNow = new Date(); + const nodeCount = (db.prepare('SELECT COUNT(*) as c FROM nodes').get() as { c: number }).c; const actualEdgeCount = (db.prepare('SELECT COUNT(*) as c FROM edges').get() as { c: number }).c; info(`Graph built: ${nodeCount} nodes, ${actualEdgeCount} edges`); @@ -63,6 +67,22 @@ export async function finalize(ctx: PipelineContext): Promise { } } + // Persist build metadata early so downstream checks (e.g. stale-embeddings) + // can read the *current* build's built_at rather than the previous one. + try { + setBuildMeta(db, { + engine: ctx.engineName, + engine_version: ctx.engineVersion || '', + codegraph_version: CODEGRAPH_VERSION, + schema_version: String(schemaVersion), + built_at: buildNow.toISOString(), + node_count: nodeCount, + edge_count: actualEdgeCount, + }); + } catch (err) { + warn(`Failed to write build metadata: ${(err as Error).message}`); + } + // Orphaned embeddings warning if (hasEmbeddings) { try { @@ -83,6 +103,27 @@ export async function finalize(ctx: PipelineContext): Promise { } } + // Stale embeddings warning (built before current graph rebuild) + if (hasEmbeddings) { + try { + const embedBuiltAt = ( + db.prepare("SELECT value FROM embedding_meta WHERE key = 'built_at'").get() as + | { value: string } + | undefined + )?.value; + if (embedBuiltAt) { + const embedTime = new Date(embedBuiltAt).getTime(); + if (!Number.isNaN(embedTime) && embedTime < buildNow.getTime()) { + warn( + 'Embeddings were built before the last graph rebuild. Run "codegraph embed" to update.', + ); + } + } + } catch { + /* ignore - embedding_meta table may not exist */ + } + } + // Unused exports warning try { const unusedCount = ( @@ -108,21 +149,6 @@ export async function finalize(ctx: PipelineContext): Promise { /* exported column may not exist on older DBs */ } - // Persist build metadata - try { - setBuildMeta(db, { - engine: ctx.engineName, - engine_version: ctx.engineVersion || '', - codegraph_version: CODEGRAPH_VERSION, - schema_version: String(schemaVersion), - built_at: new Date().toISOString(), - node_count: nodeCount, - edge_count: actualEdgeCount, - }); - } catch (err) { - warn(`Failed to write build metadata: ${(err as Error).message}`); - } - closeDb(db); // Write journal header after successful build