diff --git a/crates/omnigraph-config/src/merge.rs b/crates/omnigraph-config/src/merge.rs index d7671ce..f7f63ca 100644 --- a/crates/omnigraph-config/src/merge.rs +++ b/crates/omnigraph-config/src/merge.rs @@ -61,12 +61,13 @@ pub fn merge_layers(layers: Vec) -> (OmnigraphConfig, Provenance) { legacy_keys: _, } = config; - if layer_version.is_some() { - version = layer_version; - } + // `version`/`base_dir` follow the highest *loaded-from-file* layer (project + // over global), like every other scalar — not "any layer that set it". The + // synthetic State layer (not loaded-from-file) contributes neither. if layer_loaded { loaded_from_file = true; base_dir = layer_base_dir; + version = layer_version; } // Settings-objects — deep-merge per leaf. @@ -291,4 +292,15 @@ mod tests { "provenance must iterate in deterministic sorted order" ); } + + #[test] + fn merge_version_follows_highest_loaded_layer() { + // A legacy (no `version:`) project layered under a `version: 1` global + // yields the project's version (None) — highest-precedence wins, like any + // scalar, not "any layer that set it". + let (g, _g) = config("version: 1\n"); + let (p, _p) = config("defaults:\n graph: x\n"); + let (merged, _) = merge_layers(vec![layer(Layer::Global, g), layer(Layer::Project, p)]); + assert_eq!(merged.version, None); + } } diff --git a/docs/user/cli-reference.md b/docs/user/cli-reference.md index 05655ea..115ac86 100644 --- a/docs/user/cli-reference.md +++ b/docs/user/cli-reference.md @@ -25,7 +25,7 @@ A reference for the `omnigraph` binary's command surface and `omnigraph.yaml` sc | `cleanup --keep N --older-than 7d --confirm` | destructive version GC | | `embed` | offline JSONL embedding pipeline | | `policy validate \| test \| explain` | Cedar tooling. Selects `defaults.graph`, else `serve.graphs`, else top-level `policy.file` | -| `config view [--resolved] [--show-origin] [--json] []` | print the merged config; `--show-origin` labels each field with its source layer; `--resolved ` prints the typed locator (embedded/remote) | +| `config view [--resolved] [--show-origin] [--json] []` | print the merged config (null/empty pruned); `--show-origin` labels each field with its source layer; `--resolved ` prints the full typed locator (embedded/remote, incl. region/endpoint/policy). `--resolved` and `--show-origin` are mutually exclusive | | `use ` | set the active graph (writes `~/.omnigraph/state/active.yaml`); a bare command then targets it | | `version` / `-v` | print `omnigraph 0.3.x` | @@ -110,7 +110,8 @@ directory with no project file (the `kubectl`/`gh` posture). Precedence, low → **Global dir resolution:** `OMNIGRAPH_CONFIG` (explicit file) > `OMNIGRAPH_HOME` (dir) > `$XDG_CONFIG_HOME/omnigraph` (if set) > `~/.omnigraph`. The global file is -`/config.yaml`. +`/config.yaml`. An explicit `OMNIGRAPH_CONFIG` that names a missing file is an +**error** (a typo fails loudly); a missing default-location file is simply "no global layer". **Merge semantics:** settings-objects (`defaults`, `serve`) deep-merge per field; the named-resource maps (`servers`, `graphs`, `aliases`) union by key, with a higher