Skip to content

Commit 0c6b540

Browse files
hyperpolymathclaude
andcommitted
manifest: explicit Constraints + conflict-detection + Default-driven init
Step 3 of the bottom-up plan. Three issues in one commit because the changes interlock on OctadConfig's shape and DatabaseConfig's effective_backend signature. V-L2-D1 — explicit `enable_constraints`: Constraints was a first-class concern in ADR-0001 but was treated in code as "implied when count > 2". Promoted to an explicit OctadConfig field with serde default = true. The "+ 1 if count > 2" arithmetic in enabled_count is gone; the new implementation is a straight popcount over the six optional toggles plus 2 inherent dimensions. print_status reads enable_constraints directly. Two new unit tests assert the count is bounded by 2..=8 across all 64 toggle combinations and that the arithmetic is exact. V-L2-E1 — refuse conflicting backend/target_db: effective_backend was value-based: `backend != "postgresql"` was used as a proxy for "user-set", which silently picked sqlite when a user explicitly set `backend = "postgresql"` alongside a legacy `target-db = "sqlite"`. Replaced with a fall-through match that errors loudly on conflict and returns `Ok(default)` otherwise. Signature is now `Result<&str>`; callers in main.rs + print_status propagate. Four new unit tests cover each branch (conflict, agreement, modern-only, legacy-only, default). V-L2-O1 — init_manifest reads Default + adds --force/--name: Template values are now derived from OctadConfig::default() rather than hardcoded strings, so flipping a default in code automatically flows into the generated file. Added --force (overwrite existing) and --name (override project name) flags to `verisimiser init`. A regression test asserts the OctadConfig::default() invariant the template depends on. Test fixtures in codegen/{overlay,query}.rs and the integration test add the new enable_constraints field. tests/integration_test.rs's backward-compat case calls .effective_backend().unwrap() for the new Result signature. Verified locally: - cargo fmt --all -- --check clean - cargo clippy --all-targets -- -D warnings clean - cargo test reports 42 lib + 9 integration = 51 tests, 0 failed (was 35 + 9 = 44; +7 manifest unit tests) Closes #34, #35, #36 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
1 parent f227c60 commit 0c6b540

5 files changed

Lines changed: 234 additions & 86 deletions

File tree

src/codegen/overlay.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,7 @@ mod tests {
289289
enable_lineage: true,
290290
enable_temporal: true,
291291
enable_access_control: true,
292+
enable_constraints: true,
292293
enable_simulation: true,
293294
};
294295
let ddl = generate_sidecar_schema(&schema, &octad);
@@ -309,6 +310,7 @@ mod tests {
309310
enable_lineage: false,
310311
enable_temporal: false,
311312
enable_access_control: false,
313+
enable_constraints: false,
312314
enable_simulation: false,
313315
};
314316
let ddl = generate_sidecar_schema(&schema, &octad);

src/codegen/query.rs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -343,6 +343,7 @@ mod tests {
343343
enable_lineage: true,
344344
enable_temporal: true,
345345
enable_access_control: true,
346+
enable_constraints: true,
346347
enable_simulation: false,
347348
};
348349
let interceptors = generate_interceptors(&schema, &octad, DatabaseBackend::SQLite);
@@ -364,6 +365,7 @@ mod tests {
364365
enable_lineage: false,
365366
enable_temporal: false,
366367
enable_access_control: false,
368+
enable_constraints: false,
367369
enable_simulation: false,
368370
};
369371
let interceptors = generate_interceptors(&schema, &octad, DatabaseBackend::SQLite);
@@ -384,11 +386,15 @@ mod tests {
384386
enable_lineage: false,
385387
enable_temporal: false,
386388
enable_access_control: false,
389+
enable_constraints: false,
387390
enable_simulation: false,
388391
};
389392
let interceptors = generate_interceptors(&schema, &octad, DatabaseBackend::SQLite);
390393

391-
let view = interceptors[0].provenance_view.as_ref().expect("TODO: handle error");
394+
let view = interceptors[0]
395+
.provenance_view
396+
.as_ref()
397+
.expect("TODO: handle error");
392398
assert!(view.contains("verisimdb_posts_with_provenance"));
393399
assert!(view.contains("posts.id"));
394400
assert!(view.contains("posts.title"));
@@ -403,11 +409,15 @@ mod tests {
403409
enable_lineage: false,
404410
enable_temporal: true,
405411
enable_access_control: false,
412+
enable_constraints: false,
406413
enable_simulation: false,
407414
};
408415
let interceptors = generate_interceptors(&schema, &octad, DatabaseBackend::SQLite);
409416

410-
let view = interceptors[0].temporal_view.as_ref().expect("TODO: handle error");
417+
let view = interceptors[0]
418+
.temporal_view
419+
.as_ref()
420+
.expect("TODO: handle error");
411421
assert!(view.contains("verisimdb_posts_with_temporal"));
412422
assert!(view.contains("verisimdb_temporal_versions"));
413423
assert!(view.contains("valid_to IS NULL"));

src/main.rs

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,12 @@ enum Commands {
3434
/// Database backend: postgresql, sqlite, or mongodb.
3535
#[arg(short, long, default_value = "postgresql")]
3636
database: String,
37+
/// Project name (default: "my-augmented-db").
38+
#[arg(short, long)]
39+
name: Option<String>,
40+
/// Overwrite an existing verisimiser.toml.
41+
#[arg(short, long)]
42+
force: bool,
3743
},
3844
/// Parse the target database schema and generate sidecar overlay + interceptors.
3945
Generate {
@@ -86,7 +92,11 @@ enum Commands {
8692
fn main() -> Result<()> {
8793
let cli = Cli::parse();
8894
match cli.command {
89-
Commands::Init { database } => manifest::init_manifest(&database),
95+
Commands::Init {
96+
database,
97+
name,
98+
force,
99+
} => manifest::init_manifest(&database, name.as_deref(), force),
90100

91101
Commands::Generate { manifest, output } => {
92102
let m = manifest::load_manifest(&manifest)?;
@@ -104,7 +114,7 @@ fn main() -> Result<()> {
104114
};
105115

106116
// Determine the backend for SQL dialect selection.
107-
let backend_name = m.database.effective_backend();
117+
let backend_name = m.database.effective_backend()?;
108118
let backend = abi::DatabaseBackend::from_str(backend_name)
109119
.unwrap_or(abi::DatabaseBackend::PostgreSQL);
110120

@@ -139,7 +149,7 @@ fn main() -> Result<()> {
139149
} else {
140150
&m.verisimiser.name
141151
};
142-
let backend = m.database.effective_backend();
152+
let backend = m.database.effective_backend()?;
143153
println!(
144154
"Starting VeriSimiser augmentation for {} ({})",
145155
name, backend
@@ -183,8 +193,7 @@ fn main() -> Result<()> {
183193

184194
Commands::Status { manifest } => {
185195
let m = manifest::load_manifest(&manifest)?;
186-
manifest::print_status(&m);
187-
Ok(())
196+
manifest::print_status(&m)
188197
}
189198

190199
Commands::Octad => {

0 commit comments

Comments
 (0)