fix(config): merged version follows the highest loaded layer; doc the review fixes

Merge `version` now follows the highest loaded-from-file layer (project over global),
like every other scalar, instead of 'any layer that set it' — so a legacy project under
a v1 global reports the project's (legacy) version. Document the config view --resolved
output, the --resolved/--show-origin exclusivity, and the OMNIGRAPH_CONFIG-missing error
in cli-reference.md.
This commit is contained in:
Ragnor Comerford 2026-06-05 12:48:31 +02:00
parent a4fd847f7d
commit d5a091336a
No known key found for this signature in database
2 changed files with 18 additions and 5 deletions

View file

@ -61,12 +61,13 @@ pub fn merge_layers(layers: Vec<LoadedLayer>) -> (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);
}
}

View file

@ -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] [<graph>]` | print the merged config; `--show-origin` labels each field with its source layer; `--resolved <graph>` prints the typed locator (embedded/remote) |
| `config view [--resolved] [--show-origin] [--json] [<graph>]` | print the merged config (null/empty pruned); `--show-origin` labels each field with its source layer; `--resolved <graph>` prints the full typed locator (embedded/remote, incl. region/endpoint/policy). `--resolved` and `--show-origin` are mutually exclusive |
| `use <graph>` | 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
`<dir>/config.yaml`.
`<dir>/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