Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 16 additions & 3 deletions src/domain/graph/builder/pipeline.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,10 +88,17 @@ function checkEngineSchemaMismatch(ctx: PipelineContext): void {
);
ctx.forceFullRebuild = true;
}
// When the native engine is active, the Rust addon's version (ctx.engineVersion)
// is written into codegraph_version by setBuildMeta after a native orchestrator
// build. The check must compare against the same version, otherwise JS and Rust
// fight over which version to record — causing every incremental build to be
// promoted to a full rebuild when npm and crate versions diverge.
const effectiveVersion =
ctx.engineName === 'native' && ctx.engineVersion ? ctx.engineVersion : CODEGRAPH_VERSION;
Comment on lines +96 to +97
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 finalize.ts still writes CODEGRAPH_VERSION, re-creating the loop

checkEngineSchemaMismatch now correctly compares against ctx.engineVersion when native is active, but finalize.persistBuildMetadata (stages/finalize.ts:89–101) still writes CODEGRAPH_VERSION as codegraph_version unconditionally. This leaves an inconsistency: any time the JS-pipeline fallback runs a full rebuild (triggered by schema migration, engine switch, etc.), it persists the npm package version, and on the very next build this check sees prevVersion = CODEGRAPH_VERSION ≠ effectiveVersion = ctx.engineVersion, sets forceFullRebuild = true, skips the native orchestrator again, and the cycle repeats indefinitely. Before this PR the same schema-change scenario produced a two-build cycle via the Rust orchestrator; after the PR, this check closes the loop entirely in JS — every subsequent build is a wasted full rebuild.

The symmetric fix is needed in finalize.ts:

// persistBuildMetadata in finalize.ts
const codeVersionToWrite =
  ctx.engineName === 'native' && ctx.engineVersion ? ctx.engineVersion : CODEGRAPH_VERSION;
// …then use codeVersionToWrite for the codegraph_version field in both branches

Fix in Claude Code

const prevVersion = meta('codegraph_version');
if (prevVersion && prevVersion !== CODEGRAPH_VERSION) {
if (prevVersion && prevVersion !== effectiveVersion) {
info(
`Codegraph version changed (${prevVersion} → ${CODEGRAPH_VERSION}), promoting to full rebuild.`,
`Codegraph version changed (${prevVersion} → ${effectiveVersion}), promoting to full rebuild.`,
);
ctx.forceFullRebuild = true;
}
Expand Down Expand Up @@ -631,10 +638,16 @@ async function tryNativeOrchestrator(
const p = result.phases;

// Sync build_meta so JS-side version/engine checks work on next build.
// Use the Rust addon version as codegraph_version when the native
// orchestrator performed the build — the Rust side's check_version_mismatch
// compares this value against CARGO_PKG_VERSION. Writing the JS
// CODEGRAPH_VERSION here would create a permanent mismatch whenever the
// npm package version diverges from the Rust crate version, forcing every
// subsequent native build to be a full rebuild (no incremental).
setBuildMeta(ctx.db, {
engine: ctx.engineName,
engine_version: ctx.engineVersion || '',
codegraph_version: CODEGRAPH_VERSION,
codegraph_version: ctx.engineVersion || CODEGRAPH_VERSION,
schema_version: String(ctx.schemaVersion),
built_at: new Date().toISOString(),
node_count: String(result.nodeCount ?? 0),
Expand Down
Loading