feat(server)!: cluster-only server — remove single-graph serving (RFC-011) (#250)

omnigraph-server boots only from --cluster; all HTTP is /graphs/<id>/…; flat single-graph routes and the omnigraph.yaml server boot are removed. GraphRouting/ServerConfigMode collapse to multi-only; openapi.json regenerated to the nested shape; ~100 server route tests migrated; parity/system_local boot from a converged cluster. Gate green (1410 tests).
This commit is contained in:
Andrew Altshuler 2026-06-15 20:17:25 +03:00 committed by GitHub
parent b183db078f
commit 8b01c6e547
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
20 changed files with 988 additions and 1492 deletions

View file

@ -339,6 +339,63 @@ impl SystemGraph {
}
}
/// A converged cluster directory the server can boot from (`--cluster`),
/// serving one graph seeded with the standard fixture. Holds the temp dir
/// alive for the test's lifetime.
pub struct ClusterFixture {
_temp: TempDir,
dir: PathBuf,
}
impl ClusterFixture {
pub fn path(&self) -> &Path {
&self.dir
}
}
/// Build a converged cluster (RFC-011 cluster-only serving) with a single
/// graph `graph_id`, seeded with the `test.jsonl` fixture so reads return
/// data. When `policy_yaml` is `Some`, the bundle is bound to the graph
/// scope. The server boots from the returned path via `--cluster`.
pub fn converged_loaded_cluster(graph_id: &str, policy_yaml: Option<&str>) -> ClusterFixture {
let temp = tempdir().unwrap();
let dir = temp.path().to_path_buf();
fs::copy(fixture("test.pg"), dir.join("graph.pg")).unwrap();
let policy_block = match policy_yaml {
Some(source) => {
fs::write(dir.join("graph.policy.yaml"), source).unwrap();
format!(
"policies:\n graph:\n file: ./graph.policy.yaml\n applies_to: [{graph_id}]\n"
)
}
None => String::new(),
};
fs::write(
dir.join("cluster.yaml"),
format!(
"version: 1\nmetadata:\n name: sys\nstate:\n backend: cluster\n lock: true\ngraphs:\n {graph_id}:\n schema: ./graph.pg\n{policy_block}"
),
)
.unwrap();
output_success(cli().arg("cluster").arg("import").arg("--config").arg(&dir));
output_success(cli().arg("cluster").arg("apply").arg("--config").arg(&dir));
let served_root = dir.join("graphs").join(format!("{graph_id}.omni"));
output_success(
cli()
.arg("load")
.arg("--data")
.arg(fixture("test.jsonl"))
.arg("--mode")
.arg("overwrite")
.arg(&served_root),
);
ClusterFixture { _temp: temp, dir }
}
// ---- helpers moved from the monolithic tests/cli.rs ----
#[allow(unused_imports)]
use lance::Dataset;
@ -788,29 +845,104 @@ rules:
.to_string()
}
/// Per-arm config files carrying the same policy. Both arms address the
/// graph by positional URI, so the TOP-LEVEL policy.file applies on each
/// side (single-graph semantics).
pub fn parity_configs(root: &Path, _local_graph: &Path, remote_graph: &Path) -> (PathBuf, PathBuf) {
/// The graph id the parity cluster serves the remote arm under. The
/// remote arm addresses it with `--graph PARITY_GRAPH_ID` (RFC-011: the
/// server is cluster-only, so a graph selector is required).
pub const PARITY_GRAPH_ID: &str = "parity";
/// Build both arms' configuration (RFC-011 cluster-only server).
///
/// * Local arm: a `--config` file carrying the TOP-LEVEL `policy.file`
/// (single-graph embedded semantics), used as-is by `run_both_with_config`.
/// * Remote arm: a converged cluster directory whose single graph (id
/// `parity`) carries the SAME Cedar bundle (bound to the graph scope).
/// The cluster's derived graph root (`<dir>/graphs/parity.omni`) is
/// seeded with the SAME fixture data as the local twin so the two arms
/// compare like-for-like.
///
/// `local_graph` is overwritten with a byte-for-byte copy of the cluster's
/// seeded served graph so identity-bearing values that are NOT scrubbed
/// (e.g. `graph_commit_id`, edge `id`s in export) match across the arms —
/// the served graph is the source of truth and the local twin mirrors it.
///
/// Returns `(local_config_path, cluster_dir)`. The caller spawns the
/// server with `--cluster <cluster_dir>`.
pub fn parity_configs(root: &Path, local_graph: &Path, _remote_graph: &Path) -> (PathBuf, PathBuf) {
let policy = root.join("parity.policy.yaml");
fs::write(&policy, parity_policy_yaml()).unwrap();
// Local arm config: top-level single-graph policy.
let local_cfg = root.join("local.omnigraph.yaml");
fs::write(
&local_cfg,
format!("policy:\n file: {}\n", policy.display()),
)
.unwrap();
let server_cfg = root.join("server.omnigraph.yaml");
// Remote arm: a cluster directory the server boots from. One graph
// (`parity`), schema = the shared fixture, policy bound to the graph.
let cluster_dir = root.join("parity-cluster");
fs::create_dir_all(&cluster_dir).unwrap();
fs::copy(fixture("test.pg"), cluster_dir.join("parity.pg")).unwrap();
fs::copy(&policy, cluster_dir.join("parity.policy.yaml")).unwrap();
fs::write(
&server_cfg,
cluster_dir.join("cluster.yaml"),
format!(
"server:\n graph: parity\ngraphs:\n parity:\n uri: {}\n policy:\n file: {}\n",
remote_graph.display(),
policy.display()
r#"version: 1
metadata:
name: parity
state:
backend: cluster
lock: true
graphs:
{PARITY_GRAPH_ID}:
schema: ./parity.pg
policies:
parity:
file: ./parity.policy.yaml
applies_to: [{PARITY_GRAPH_ID}]
"#
),
)
.unwrap();
(local_cfg, server_cfg)
// Converge the cluster (creates the empty graph at the derived root),
// then seed it with the same fixture data the local twin holds.
output_success(
cli()
.arg("cluster")
.arg("import")
.arg("--config")
.arg(&cluster_dir),
);
output_success(
cli()
.arg("cluster")
.arg("apply")
.arg("--config")
.arg(&cluster_dir),
);
let served_root = cluster_dir
.join("graphs")
.join(format!("{PARITY_GRAPH_ID}.omni"));
output_success(
cli()
.arg("load")
.arg("--data")
.arg(fixture("test.jsonl"))
.arg("--mode")
.arg("overwrite")
.arg(&served_root),
);
// Mirror the seeded served graph into the local twin so both arms hold
// identical ULIDs / commit ids (the served graph is authoritative).
if local_graph.exists() {
fs::remove_dir_all(local_graph).unwrap();
}
copy_dir(&served_root, local_graph);
(local_cfg, cluster_dir)
}
/// Run one CLI invocation per arm with identical verb args: locally against
@ -853,7 +985,11 @@ pub fn run_both_with_config(
.env("OMNIGRAPH_BEARER_TOKEN", PARITY_TOKEN)
.args(args)
.arg("--server")
.arg(server_url);
.arg(server_url)
// RFC-011: the parity server is cluster-only (multi-graph), so the
// remote arm must name the graph it addresses.
.arg("--graph")
.arg(PARITY_GRAPH_ID);
let remote_out = remote.output().unwrap();
(local_out, remote_out)
}