From fd64f8abc441bdf6c62742dd9a727b9f7cd4aab8 Mon Sep 17 00:00:00 2001 From: Ragnor Comerford Date: Wed, 3 Jun 2026 15:23:32 +0200 Subject: [PATCH] feat(config): version-gate scaffold for the typed schema MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit load_config reads the optional top-level 'version:' discriminator and rejects unsupported versions (>1) before parsing; no-version (legacy) and 'version: 1' both still parse via the existing lenient struct. Forward-compat gate (RFC-002 ยง3) added as a no-op so the typed GraphLocator schema can tighten in following commits without breaking legacy files. 14 config tests pass (incl. version:1 parses, version:2 rejected). --- crates/omnigraph-config/src/lib.rs | 57 +++++++++++++++++++++++++++++- 1 file changed, 56 insertions(+), 1 deletion(-) diff --git a/crates/omnigraph-config/src/lib.rs b/crates/omnigraph-config/src/lib.rs index b308b72..3f9e444 100644 --- a/crates/omnigraph-config/src/lib.rs +++ b/crates/omnigraph-config/src/lib.rs @@ -538,7 +538,9 @@ fn load_config_in(cwd: &Path, config_path: Option<&PathBuf>) -> Result(&fs::read_to_string(path)?)? + let text = fs::read_to_string(path)?; + check_config_version(&text)?; + serde_yaml::from_str::(&text)? } else { OmnigraphConfig::default() }; @@ -552,6 +554,24 @@ fn load_config_in(cwd: &Path, config_path: Option<&PathBuf>) -> Result Result<()> { + let value: serde_yaml::Value = serde_yaml::from_str(text)?; + if let Some(version) = value.get("version").and_then(serde_yaml::Value::as_u64) { + if version != 1 { + bail!( + "unsupported config version {version}; this build supports version 1 \ + (omit `version:` for the legacy schema)" + ); + } + } + Ok(()) +} + fn absolute_base_dir(cwd: &Path, path: &Path) -> Result { let path = if path.is_absolute() { path.to_path_buf() @@ -945,4 +965,39 @@ cli: Some("DEMO_TOKEN") ); } + + #[test] + fn version_one_parses_like_legacy() { + let temp = tempdir().unwrap(); + fs::write( + temp.path().join("omnigraph.yaml"), + "version: 1\ngraphs:\n local:\n uri: ./demo.omni\ncli:\n graph: local\n", + ) + .unwrap(); + let config = load_config_in(temp.path(), None).unwrap(); + assert_eq!(config.cli_graph_name(), Some("local")); + assert_eq!( + PathBuf::from( + config + .resolve_target_uri(None, None, config.cli_graph_name()) + .unwrap() + ), + temp.path().join("./demo.omni") + ); + } + + #[test] + fn unsupported_config_version_errors() { + let temp = tempdir().unwrap(); + fs::write( + temp.path().join("omnigraph.yaml"), + "version: 2\ngraphs:\n local:\n uri: ./demo.omni\n", + ) + .unwrap(); + let err = load_config_in(temp.path(), None).unwrap_err().to_string(); + assert!( + err.contains("unsupported config version 2"), + "config version > 1 must be rejected: {err}" + ); + } }