From 620046f7cb27e9cbf56be8713dbf15ac56257b48 Mon Sep 17 00:00:00 2001 From: Radim Marek Date: Wed, 6 May 2026 06:54:03 +0200 Subject: [PATCH 1/2] fix: init should do full primary-only capture --- crates/dry_run_cli/src/main.rs | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/crates/dry_run_cli/src/main.rs b/crates/dry_run_cli/src/main.rs index 338766e..4a5c4c1 100644 --- a/crates/dry_run_cli/src/main.rs +++ b/crates/dry_run_cli/src/main.rs @@ -324,6 +324,12 @@ schema_file = ".dryrun/schema.json" // if --db is provided, introspect and save schema if let Some(db_url) = db { let ctx = DryRun::connect(db_url).await?; + if ctx.is_standby().await? { + anyhow::bail!( + "`dryrun init --db` must run against the primary; \ + planner and activity stats are not available on standbys" + ); + } let snapshot = ctx.introspect_schema().await?; let schema_path = data_dir.join("schema.json"); @@ -338,12 +344,31 @@ schema_file = ".dryrun/schema.json" let key = complete_key(&resolved, &snapshot.database); store.put(&key, &snapshot).await?; + let planner = ctx.introspect_planner_stats(&snapshot.content_hash).await?; + store.put_planner_stats(&key, &planner).await?; + + let activity = ctx + .introspect_activity_stats(&snapshot.content_hash, "primary") + .await?; + store.put_activity_stats(&key, &activity).await?; + eprintln!( "Captured schema: {} tables, {} views, {} functions", snapshot.tables.len(), snapshot.views.len(), snapshot.functions.len() ); + eprintln!( + " Planner stats: {} tables, {} columns, {} indexes", + planner.tables.len(), + planner.columns.len(), + planner.indexes.len() + ); + eprintln!( + " Activity stats: {} tables, {} indexes (label=primary)", + activity.tables.len(), + activity.indexes.len() + ); eprintln!(" Schema: {}", schema_path.display()); eprintln!( " project={} database={}", From 514ff8cc6526c90d8df8548f7be26fbbb625176b Mon Sep 17 00:00:00 2001 From: Radim Marek Date: Wed, 6 May 2026 12:07:39 +0200 Subject: [PATCH 2/2] fix: reload_schema must read history.db before schema.json --- crates/dry_run_cli/src/mcp/server.rs | 30 ++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/crates/dry_run_cli/src/mcp/server.rs b/crates/dry_run_cli/src/mcp/server.rs index dc16aae..c89fa64 100644 --- a/crates/dry_run_cli/src/mcp/server.rs +++ b/crates/dry_run_cli/src/mcp/server.rs @@ -1541,9 +1541,27 @@ impl DryRunServer { } #[tool( - description = "Reload the on-disk schema without restarting. Run after `dryrun dump-schema`." + description = "Reload schema from history.db (with stats) or schema.json (DDL only) without restarting." )] async fn reload_schema(&self) -> Result { + // history.db first; the schema.json fallback drops planner/activity stats + if let (Some(store), Some(key)) = (self.history.as_ref(), self.snapshot_key.as_ref()) + && let Ok(annotated) = store.get_annotated(key, SnapshotRef::Latest).await + { + let body = format!( + "Schema loaded from history.db: {} tables, {} views, {} functions \ + (planner: {}, activity nodes: {})", + annotated.schema.tables.len(), + annotated.schema.views.len(), + annotated.schema.functions.len(), + if annotated.planner.is_some() { "yes" } else { "no" }, + annotated.activity_by_node.len(), + ); + *self.schema.write().await = Some(annotated); + let text = self.wrap_text(&body, None); + return Ok(CallToolResult::success(vec![Content::text(text)])); + } + for candidate in &self.schema_candidates { if !candidate.exists() { continue; @@ -1562,7 +1580,9 @@ impl DryRunServer { })?; let body = format!( - "Schema loaded from {}: {} tables, {} views, {} functions", + "Schema loaded from {} (planner/activity unavailable; \ + run `dryrun snapshot take` or `dryrun init` to capture stats): \ + {} tables, {} views, {} functions", candidate.display(), snapshot.tables.len(), snapshot.views.len(), @@ -1582,8 +1602,10 @@ impl DryRunServer { .collect(); Err(McpError::internal_error( format!( - "no schema file found at any expected location:\n{}\n\n\ - Run `dryrun dump-schema --db ` first.", + "no schema source available: history.db has no entry for the \ + configured snapshot key, and no schema file was found at:\n{}\n\n\ + Run `dryrun init --db ` (with stats) or \ + `dryrun dump-schema --db ` (DDL only).", paths.join("\n") ), None,