Skip to content
Merged
Show file tree
Hide file tree
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
15 changes: 14 additions & 1 deletion crates/codegraph-cli/tests/batch_m_uninit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,8 @@ fn run_in_with_config(registry_dir: &Path, args: &[&str], codegraph_dir: Option<
.current_dir(registry_dir)
.args(args)
.env("CODEGRAPH_HTTP_REGISTRY_DIR", registry_dir)
.env("CODEGRAPH_NO_DAEMON", "1");
.env("CODEGRAPH_NO_DAEMON", "1")
.env("RUST_LOG", "info");
if let Some(configured) = codegraph_dir {
command.env("CODEGRAPH_DIR", configured);
} else {
Expand Down Expand Up @@ -790,6 +791,18 @@ fn explicit_init_recovers_an_owner_mismatched_namespace() {
"explicit init must recover OwnerMismatch: stdout={}, stderr={}",
init.stdout, init.stderr
);
assert!(
!init
.stderr
.contains("replaced stale foreign index state slots")
&& !init
.stderr
.contains("replaced stale foreign index database")
&& !init.stderr.contains("codegraph_store::rebuild")
&& !init.stderr.contains(" INFO "),
"normal init progress must not be split by recovery logger output: stderr={}",
init.stderr
);
assert_eq!(Store::extraction_status(&paths), ExtractionStatus::Current);
let store = Store::open_for_read(&paths, deadline(), || false)
.expect("recovered OwnerMismatch namespace must be readable");
Expand Down
47 changes: 38 additions & 9 deletions crates/codegraph-cli/tests/batch_m_v2_namespace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,8 @@ fn run_in_env(registry_dir: &Path, args: &[&str], envs: &[(&str, &str)]) -> Run
let mut cmd = Command::new(bin());
cmd.args(args)
.env("CODEGRAPH_HTTP_REGISTRY_DIR", registry_dir)
.env("CODEGRAPH_NO_DAEMON", "1");
.env("CODEGRAPH_NO_DAEMON", "1")
.env("RUST_LOG", "info");
for (k, v) in envs {
cmd.env(k, v);
}
Expand Down Expand Up @@ -150,8 +151,8 @@ fn init_writes_default_project_local_codegraph_root() {

/// A real pre-state-slot SQLite index in the selected root is a rebuildable
/// foreign cache, not an unrecoverable contradiction. `init` must acquire its
/// one rebuild lease, replace that database automatically, and explain the
/// one-time replacement at INFO level.
/// one rebuild lease and replace that database automatically without injecting
/// raw logger output into the normal progress UI.
#[test]
fn init_takes_over_real_sqlite_database_without_state_slots() {
let dir = TestDir::new("foreign-db-takeover");
Expand All @@ -168,12 +169,10 @@ fn init_takes_over_real_sqlite_database_without_state_slots() {
run.stdout, run.stderr
);
assert!(
run.stderr.contains("replaced stale foreign index database")
&& run
.stderr
.contains(&paths.current_db().display().to_string())
&& run.stderr.contains("missing state slots"),
"INFO log must name the replaced DB and the Missing-state reason: stderr={}",
!run.stderr.contains("replaced stale foreign index database")
&& !run.stderr.contains("codegraph_store::rebuild")
&& !run.stderr.contains(" INFO "),
"normal init progress must not be split by recovery logger output: stderr={}",
run.stderr
);

Expand All @@ -193,6 +192,36 @@ fn init_takes_over_real_sqlite_database_without_state_slots() {
);
}

#[test]
fn foreign_database_replacement_details_require_debug_logging() {
let dir = TestDir::new("foreign-db-debug-log");
let project = dir.path().join("mini");
copy_tree(&mini_fixture(), &project);
let paths = IndexPaths::resolve(&project, None).expect("resolve selected index root");
stage_foreign_database(&paths);

let run = run_in_env(
dir.path(),
&["init", project.to_str().unwrap()],
&[("RUST_LOG", "codegraph_store::rebuild=debug")],
);
assert!(
run.ok,
"debug init must still replace a Missing-state SQLite index: stdout={} stderr={}",
run.stdout, run.stderr
);
assert!(
run.stderr.contains("replaced stale foreign index database")
&& run
.stderr
.contains(&paths.current_db().display().to_string())
&& run.stderr.contains("missing state slots")
&& run.stderr.contains("DEBUG"),
"explicit debug logging must retain replacement diagnostics: stderr={}",
run.stderr
);
}

#[test]
fn status_json_reports_foreign_database_without_opening_or_mutating_it() {
let dir = TestDir::new("foreign-db-status-json");
Expand Down
8 changes: 6 additions & 2 deletions crates/codegraph-store/src/rebuild.rs
Original file line number Diff line number Diff line change
Expand Up @@ -336,7 +336,9 @@ fn remove_owner_mismatched_state_slots(
.map(|path| path.display().to_string())
.collect::<Vec<_>>()
.join(", ");
tracing::info!(
// Keep successful cache recovery available for opt-in diagnostics without
// splitting the foreground CLI's progress renderer at the default INFO level.
tracing::debug!(
slots = %removed,
reason = "project identity mismatch after move or copy",
"replaced stale foreign index state slots"
Expand Down Expand Up @@ -415,7 +417,9 @@ fn begin_from_authorization(
remove_database_files(paths, &lease)?;
checkpoint(fault, RebuildCheckpoint::DatabaseRemoved)?;
if let Some(path) = replaced_artifact {
tracing::info!(
// This is successful internal recovery, not a user-facing warning.
// DEBUG preserves observability without interleaving raw logs with init.
tracing::debug!(
path = %path.display(),
reason = "missing state slots",
"replaced stale foreign index database"
Expand Down
6 changes: 6 additions & 0 deletions skills/codegraph/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,12 @@ also escalate through `sync`; do not jump to a forced rebuild merely because the
CLI version changed. Follow the exact recovery command printed by `status` or the
failed command.

Missing index-state slots and an all-`OwnerMismatch` index after a project move
or copy are supported `init` recovery cases. When `status`, `sync`, or another
failed command explicitly prints `codegraph init ...`, run that exact command to
replace the stale index; do not keep retrying `sync`. Do not generalize this to
mixed or other corruption when the CLI does not prescribe `init`.

### Start the MCP server

```bash
Expand Down
Loading