feat(cli): RFC-011 Slice A — additive scope/profile addressing (#235)
Some checks failed
CI / Classify Changes (push) Has been cancelled
CI / Check AGENTS.md Links (push) Has been cancelled
CI / Container Entrypoint (push) Has been cancelled
Release Edge / Prepare edge release (push) Has been cancelled
CI / Test Workspace (push) Has been cancelled
CI / Test omnigraph-server --features aws (push) Has been cancelled
CI / RustFS S3 Integration (push) Has been cancelled
Release Edge / Build edge omnigraph-linux-x86_64 (push) Has been cancelled
Release Edge / Build edge omnigraph-macos-arm64 (push) Has been cancelled
Release Edge / Build edge omnigraph-windows-x86_64 (push) Has been cancelled
Release Edge / Smoke Windows installer (push) Has been cancelled

* feat(cli): RFC-011 Slice A — operator-config scope structs (profiles/clusters/defaults)

Additive operator-config surface for the RFC-011 scope model. No behavior
change yet — these structs are parsed but not consumed until the scope
resolver lands.

- OperatorConfig gains `profiles:` (name → OperatorProfile) and `clusters:`
  (name → OperatorCluster { root }) — the latter the only place a storage
  root appears in operator config (RFC-011 storage-root rule).
- OperatorDefaults gains `server` and `default_graph` (the flat-default scope).
- OperatorProfile binds one of {server, cluster, store} + default_graph;
  `binding()` validates exactly-one on use and returns a ScopeBinding.
- Accessors profile()/cluster_root()/default_server()/default_graph();
  unknown-key warnings extended to the new blocks (forward-compat preserved —
  old configs still load, new keys are no longer "unknown").

Tests: parse profiles/clusters/scope-defaults, binding rejects zero/multiple
entities, unknown keys in a profile warn.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* feat(cli): RFC-011 Slice A — scope resolver + --profile/--store, wired (additive)

Translate the new scope inputs into the existing addressing tuple, in front of
the unchanged resolvers. Purely additive: an explicit address
(--uri/--target/--server/--store) passes straight through, so every existing
invocation is byte-for-byte unchanged.

- scope.rs: resolve_scope() with the RFC-011 precedence (explicit > --profile /
  OMNIGRAPH_PROFILE > flat defaults.server), producing the effective
  (server, graph, uri, target) for data verbs and (cluster, cluster_graph) for
  maintenance. Plane×scope capability check (server scope rejected on a
  maintenance verb; cluster scope rejected on a data verb; store rejects --graph)
  fires only on the new paths. 9 unit tests.
- cli.rs: global --profile <NAME> and --store <URI>. (--graph keeps
  requires=server for now; profile/default graph comes from default_graph —
  profile+--graph override is deferred to the --cluster-graph rework.)
- client.rs: the two GraphClient factories call resolve_scope (Plane::Data) up
  front; the explicit branch reproduces today's behavior exactly.
- main.rs: the 15 data call sites forward --profile/--store; the 3 maintenance
  verbs consult the scope (Plane::Storage) only when no explicit per-command
  address is given, so cluster-binding profiles and --store reach
  optimize/repair/cleanup.

Verified: the full omnigraph-cli suite (221 tests) stays green untouched.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* test+docs(cli): RFC-011 Slice A — end-to-end scope test + reference docs

- cli_data.rs: prove --store and a --profile store binding drive a read
  identically to the legacy positional URI (the additive-coexistence contract),
  end to end against a local graph (no server needed).
- cli/reference.md: document profiles/clusters/defaults.server/default_graph,
  the --profile/--store flags, and a "Scopes & profiles" section; note the model
  coexists with legacy addressing (nothing removed yet).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Andrew Altshuler 2026-06-15 02:37:55 +03:00 committed by GitHub
parent ceb37dd4cb
commit a4d08a4184
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 777 additions and 28 deletions

View file

@ -3,6 +3,7 @@
use std::fs;
use assert_cmd::Command;
use serde_json::Value;
use tempfile::tempdir;
@ -801,6 +802,59 @@ fn read_json_outputs_rows_for_named_query() {
assert_eq!(payload["rows"][0]["p.name"], "Alice");
}
#[test]
fn read_via_store_flag_and_profile_match_positional_uri() {
// RFC-011 Slice A: the new scope addressing (--store, and a --profile that
// binds a store) drives a read identically to the legacy positional URI —
// the scope layer is additive, not a behavior change.
let temp = tempdir().unwrap();
let graph = graph_path(temp.path());
init_graph(&graph);
load_fixture(&graph);
let queries = fixture("test.gq");
let read_rows = |cmd: &mut Command| -> Value {
let output = output_success(
cmd.arg("--query")
.arg(&queries)
.arg("--name")
.arg("get_person")
.arg("--params")
.arg(r#"{"name":"Alice"}"#)
.arg("--json"),
);
serde_json::from_slice(&output.stdout).unwrap()
};
// Baseline: positional URI.
let baseline = read_rows(cli().arg("query").arg(&graph));
assert_eq!(baseline["rows"][0]["p.name"], "Alice");
// --store names the same graph directly.
let via_store = read_rows(cli().arg("query").arg("--store").arg(&graph));
assert_eq!(via_store["rows"], baseline["rows"]);
// A profile binding that store, selected with --profile (no positional).
let home = temp.path().join("op-home");
std::fs::create_dir_all(&home).unwrap();
std::fs::write(
home.join("config.yaml"),
format!(
"profiles:\n local:\n store: '{}'\n",
graph.to_string_lossy()
),
)
.unwrap();
let via_profile = read_rows(
cli()
.env("OMNIGRAPH_HOME", &home)
.arg("query")
.arg("--profile")
.arg("local"),
);
assert_eq!(via_profile["rows"], baseline["rows"]);
}
#[test]
fn export_jsonl_outputs_source_rows_for_selected_branch_and_type() {
let temp = tempdir().unwrap();