diff --git a/crates/omnigraph-api-types/src/lib.rs b/crates/omnigraph-api-types/src/lib.rs index 28146026..32bc7534 100644 --- a/crates/omnigraph-api-types/src/lib.rs +++ b/crates/omnigraph-api-types/src/lib.rs @@ -401,8 +401,8 @@ pub struct QueryCatalogEntry { pub params: Vec, } -/// Response for `GET /queries`: the `mcp.expose` subset of a graph's -/// stored-query registry, each with typed parameters. +/// Response for `GET /queries`: every stored query in a graph's +/// registry, each with typed parameters. #[derive(Debug, Clone, Serialize, Deserialize, ToSchema)] pub struct QueriesCatalogOutput { pub queries: Vec, diff --git a/crates/omnigraph-cli/src/cli.rs b/crates/omnigraph-cli/src/cli.rs index 94bec5af..2b1a8619 100644 --- a/crates/omnigraph-cli/src/cli.rs +++ b/crates/omnigraph-cli/src/cli.rs @@ -397,8 +397,10 @@ pub(crate) enum ClusterCommand { #[arg(long)] json: bool, }, - /// Apply the config-only (query/policy) subset of the plan to the local - /// cluster catalog. Graph/schema changes are deferred to a later stage. + /// Converge the cluster to its config: create graphs, apply schema updates + /// (soft drops), write stored-query/policy catalog resources, and execute + /// approved graph deletes, in one ordered run. Serving picks up the applied + /// revision after an `omnigraph-server --cluster` restart. Apply { /// Cluster config directory containing cluster.yaml. #[arg(long, default_value = ".")] diff --git a/crates/omnigraph-server/src/handlers.rs b/crates/omnigraph-server/src/handlers.rs index 7de38d20..1571164d 100644 --- a/crates/omnigraph-server/src/handlers.rs +++ b/crates/omnigraph-server/src/handlers.rs @@ -1026,7 +1026,7 @@ pub(crate) async fn server_invoke_query( tag = "queries", operation_id = "list_queries", responses( - (status = 200, description = "Stored-query catalog (the mcp.expose subset, with typed params)", body = QueriesCatalogOutput), + (status = 200, description = "Stored-query catalog (every stored query, with typed params)", body = QueriesCatalogOutput), (status = 401, description = "Unauthorized", body = ErrorOutput), (status = 403, description = "Forbidden", body = ErrorOutput), ), @@ -1034,10 +1034,11 @@ pub(crate) async fn server_invoke_query( )] /// List the graph's exposed stored queries as a typed tool catalog. /// -/// Returns the `mcp.expose == true` subset of the `queries:` registry, each +/// Returns every stored query in the `queries:` registry, each /// with its MCP tool name, read/mutate flag, description/instruction, and /// typed parameters — enough for a client to register them as tools without -/// fetching `.gq` source. Read-gated; the catalog is graph-wide (branch +/// fetching `.gq` source. Cluster-served graphs have no per-query expose flag, +/// so the catalog lists them all. Read-gated; the catalog is graph-wide (branch /// independent — `read` is authorized against `main`). **Not** Cedar-filtered /// per query yet, so it can list a query whose `invoke_query` the caller /// lacks (a known gap until per-query authorization lands). diff --git a/docs/dev/docs-issues.md b/docs/dev/docs-issues.md new file mode 100644 index 00000000..d045f4b2 --- /dev/null +++ b/docs/dev/docs-issues.md @@ -0,0 +1,68 @@ +# User Docs Coherence Ledger + +**Last review:** 2026-06-20 (against 0.7.1) +**Status:** all open findings resolved — living ledger for future audits. + +This page tracks stale or incoherent user-doc claims found during broad docs +reviews. Findings are validated against current **code/behavior**, not just +cross-doc consistency. Record new findings as they surface; mark them resolved +(with the fixing commit) once the public pages are corrected. + +## Resolved — 2026-06-20 docs/user coherence sweep + +Every finding from the 2026-06-20 review was validated (all reproduced) and +fixed. Branch `docs/user-coherence-0-7-1`. + +| Pri | Finding | Resolution | +|---|---|---| +| P1 | `cluster apply` documented as catalog-only / "Stage 3A" with graph+schema deferred — in both `cli/reference.md` and the shipped CLI help (`cli.rs`) | Rewrote both to describe the real converge behavior (creates graphs, applies schema with soft drops, writes catalog, executes approved deletes in one ordered run); `deferred` now means the genuinely-unsupported case (standalone schema delete). | +| P1 | Stored-query exposure had two contracts: `server.md` documented a per-query `mcp:{expose:false}` knob; cluster docs said all queries are listed | Confirmed in code: cluster registry has no expose field (`QueryConfig`), boot bridge hardcodes `expose: true` (`omnigraph-server` settings), no GQ-level annotation. Removed the knob from `server.md`; documented "every applied query is listed; per-query exposure may become a Cedar-policy decision later". | +| P1 | The same stale "`mcp.expose == true` subset" contract lived in the **OpenAPI surface**: utoipa annotations (`handlers.rs:1029,1037`, `omnigraph-api-types/src/lib.rs:404`) drove `openapi.json` (Greptile catch on #293) | Updated the three Rust doc-comment/annotation strings to "every stored query" and regenerated `openapi.json` (`OMNIGRAPH_UPDATE_OPENAPI=1`); drift test green. Same-change per AGENTS.md rule 4. | +| P2 | `schema/index.md` claimed `allow_data_loss` honored "uniformly across transports" incl. HTTP `POST /schema/apply` | Scoped to the direct/embedded path; added that cluster-managed graphs evolve via `cluster apply` (soft drops only) and the HTTP route is 409-disabled for cluster serving. | +| P2 | `/load` missing from admission / body-limit / rate-limit / manifest-conflict prose (named `/ingest` only); constants called it "Ingest body limit" | Documented `/load` as canonical everywhere with `/ingest` as the deprecated alias; renamed the constant to "Load (bulk-write) body limit". | +| P2 | CLI "Bearer token resolution" section listed removed `omnigraph.yaml` keys (`graphs..bearer_token_env`, `auth.env_file`) | Replaced with a pointer to the keyed-credential model (`OMNIGRAPH_TOKEN_` → `~/.omnigraph/credentials` → `OMNIGRAPH_BEARER_TOKEN`); no plaintext-in-config path. | +| P2 | Flat route names in a cluster-only server (`POST /query`, `POST /mutate`, `GET /queries`, `POST /queries/{name}`) | Added a one-line note that the per-graph subsections use shorthand under `/graphs/{id}/…`; the endpoint table is already fully qualified. | +| — | `version` printed `omnigraph 0.3.x` | → `0.7.x`. | +| — | `search/indexes.md` used deprecated `ingest --mode merge` | → `load --mode merge`. | +| — | `config.md` `deferred` disposition described as "graph/schema change, later phase" | → "an unsupported change (e.g. standalone schema delete)". | +| — | Stale stage labels (`Stage 3A`, `Stage 2C`, `Stage 1`) in active reference docs | Removed / reworded to plain language; release notes keep history. | + +## Open — surfaced 2026-06-20, not yet fixed + +- **Stale "config-only apply" / "Stage 3A" comments in `omnigraph-cluster` + source** (internal rustdoc, not user docs — out of scope for the docs sweep + above): `src/types.rs:147` ("Applied changes execute (config-only query/policy + catalog writes)"), `src/types.rs:265` ("Output of config-only cluster apply"), + `src/diff.rs:256`, and `src/tests.rs:1129` ("config-only apply (Stage 3A)"). + Apply now also runs graph creates, schema applies, and approved deletes + (`diff.rs:411` `GraphCreate` / `SchemaApply`; the Stage-4 create/schema/delete + executors + tests `apply_creates_graph_and_unblocks_dependents`, + `apply_schema_update_and_dependent_query_in_one_run`, + `apply_blocks_graph_delete_without_approval`). Update these comments in a + cluster-crate change. +- **Cross-repo drift from this sweep** (separate repos — track here, fix in a + follow-up in each repo): + - `omnigraph-ts` SDK ships a stale generated `spec/openapi.json` + + `packages/sdk/src/generated/types.gen.ts` still describing the `GET /queries` + catalog as the `mcp.expose` subset. Regenerate from this repo's + `openapi.json` once the SDK's deferred refresh happens (the SDK is known to + lag the API by design). + - `omnigraph-cookbooks/docs/best-practices.md` (~line 372) still describes + client-side auth as resolving through the removed `bearer_token_env` chain. + Update to the keyed-credential model (`OMNIGRAPH_TOKEN_` → + credentials file → `OMNIGRAPH_BEARER_TOKEN`). + +## Verification checklist (re-run on the next docs audit) + +```bash +rg -n "Stage [0-9]|graph/schema changes are deferred|reserved for later stages" docs/user crates/omnigraph-cli/src/cli.rs +rg -n "POST /query|POST /mutate|GET /queries|POST /queries/\{name\}|POST /schema/apply" docs/user +rg -n "ingest --mode|Ingest body limit|/ingest" docs/user +rg -n "0\.3\.x|bearer_token_env|auth\.env_file" docs/user +rg -n "expose: false|mcp\.expose" docs/user +``` + +Expected: active user docs have no matches for stale phrases, or the remaining +matches are explicitly marked as deprecated aliases, "no longer exist" notes, or +route shorthand disclaimed relative to `/graphs/{id}`. Release notes are allowed +to preserve historical behavior. diff --git a/docs/dev/index.md b/docs/dev/index.md index 9fe743f4..23f06107 100644 --- a/docs/dev/index.md +++ b/docs/dev/index.md @@ -41,6 +41,7 @@ constraints. User-facing behavior should still be documented through | Error taxonomy and serialization | [errors.md](../user/operations/errors.md) | | Constants and tunables | [constants.md](../user/reference/constants.md) | | Transaction model public contract | [transactions.md](../user/branching/transactions.md) | +| User-doc coherence cleanup ledger | [docs-issues.md](docs-issues.md) | ## Project Operations diff --git a/docs/user/cli/reference.md b/docs/user/cli/reference.md index 17092265..3b97800c 100644 --- a/docs/user/cli/reference.md +++ b/docs/user/cli/reference.md @@ -28,7 +28,7 @@ Top-level command families and subcommands. Graph-targeting commands accept a po | `policy validate \| test \| explain` | Cedar tooling against a cluster's applied policies (`--cluster `; `--graph ` picks a graph's bundle when several apply). `test` takes `--tests `; `explain` takes `--actor`/`--action`/`--branch`/`--target-branch` | | `queries list \| validate` | inspect a cluster's applied stored-query registry (`--cluster `; `--graph ` to scope one graph). `list` prints each query's kind (read/mutation), name, typed params, and `[mcp: …]` exposure; a query's `@description`/`@instruction` are shown as indented `description:` / `instruction:` lines when declared (omitted otherwise). `--json` emits `{name, mcp_expose, tool_name, mutation, params}` plus `description`/`instruction` **only when present** — matching the HTTP `GET /queries` catalog ([server.md](../operations/server.md)). `validate` type-checks the registry and exits non-zero on a broken query | | `profile list \| show []` | read-only inspection of `~/.omnigraph/config.yaml` profiles. `list` shows each profile's binding (server/cluster/store) + default graph and marks the `$OMNIGRAPH_PROFILE`-active one; JSON keeps `binding` and adds `scope_kind`, `target`, `valid`, and `error`; `show` resolves one profile's scope (endpoint + default graph), defaulting to the active profile, else the flat operator defaults | -| `version` / `-v` | print `omnigraph 0.3.x` | +| `version` / `-v` | print `omnigraph 0.7.x` | ## Command capabilities @@ -189,22 +189,26 @@ omnigraph cluster import --config company-brain --json omnigraph cluster force-unlock --config company-brain --json ``` -`--config` is a directory containing `cluster.yaml`; it defaults to `.`. -Stage 3A accepts graphs, schemas, stored queries, and policy bundle file +`--config` is a directory containing `cluster.yaml`; it defaults to `.`. The +config declares graphs, schemas, stored queries, and policy bundle file references. `cluster plan` reads local JSON state from `/__cluster/state.json`; a missing file means empty state. Plan, apply, refresh, and import acquire `__cluster/lock.json` by default and release -it before returning. `cluster apply` executes only stored-query/policy catalog -writes (content-addressed under `__cluster/resources/`) and requires an -existing `state.json`; graph/schema changes are deferred with warnings, and -applied resources do not serve traffic until an `omnigraph-server --cluster -` restart picks them up. `cluster status` reads state only and reports any existing -lock metadata. `force-unlock` removes a lock only when the supplied id exactly -matches the lock file. `refresh` requires an existing `state.json`; `import` -creates one only when it is missing. Both observe declared graphs read-only at -`/graphs/.omni`. External state backends, graph/schema -apply, automatic stale-lock breaking, `plan --refresh`, pipelines, UI specs, -embeddings, aliases, and bindings are reserved for later stages. See +it before returning. `cluster apply` converges the cluster to its config in one +ordered run: it creates declared graphs, applies schema updates (soft drops +only — see [schema](../schema/index.md)), writes stored-query/policy catalog +resources (content-addressed under `__cluster/resources/`), and executes +approved graph deletes; it requires an existing `state.json` (run `import` +first). Applied state does not serve traffic until an `omnigraph-server +--cluster ` restart picks up the new revision. Standalone schema deletes +remain unsupported and are reported as `deferred` with a warning. `cluster +status` reads state only and reports any existing lock metadata. `force-unlock` +removes a lock only when the supplied id exactly matches the lock file. +`refresh` requires an existing `state.json`; `import` creates one only when it +is missing. Both observe declared graphs read-only at +`/graphs/.omni`. External state backends, automatic +stale-lock breaking, `plan --refresh`, pipelines, UI specs, embeddings, +aliases, and bindings are not yet supported. See [cluster-config.md](../clusters/config.md). ## Output formats (`query` command, alias: `read`) @@ -221,9 +225,12 @@ Precedence (high to low): explicit `--params` / `--params-file`, alias positiona ## Bearer token resolution (CLI) -1. `graphs..bearer_token_env` -2. `OMNIGRAPH_BEARER_TOKEN` global env -3. `auth.env_file` referenced `.env` +See **Credentials keyed by server name** above: a remote command resolves its +token via `OMNIGRAPH_TOKEN_` env → the `[]` section in +`~/.omnigraph/credentials` → the default `OMNIGRAPH_BEARER_TOKEN` env, and a +keyed token is only ever sent to the server it is keyed to. Plaintext tokens are +never stored in operator config; the removed `omnigraph.yaml` keys +(`graphs..bearer_token_env`, `auth.env_file`) no longer exist. ## Duration parsing (cleanup) diff --git a/docs/user/clusters/config.md b/docs/user/clusters/config.md index 04811ec2..d9fdc1a9 100644 --- a/docs/user/clusters/config.md +++ b/docs/user/clusters/config.md @@ -212,7 +212,7 @@ resource is planned as a create. If present, the file must use this shape: ``` `state_revision`, `resource_statuses`, `approval_records`, `recovery_records`, -and `observations` are optional so older Stage 1 state fixtures keep working. +and `observations` are optional so earlier state fixtures keep working. Missing `state_revision` is treated as `0`. Resource status values are `pending`, `planned`, `applying`, `applied`, `drifted`, `blocked`, or `error`. @@ -238,9 +238,10 @@ profile in the ledger; pre-profile ledgers are backfilled by an Update with catalog changes and count toward convergence. Each plan change carries a `disposition` field — an honest preview of what -`cluster apply` will do with it in this stage: `applied` (executes), `derived` -(a `graph.` composite-digest update that converges automatically once its -query digests land), `deferred` (graph/schema change, later phase), or +`cluster apply` will do with it: `applied` (executes — graph creates, schema +updates, catalog writes, approved deletes), `derived` (a `graph.` +composite-digest update that converges automatically once its query digests +land), `deferred` (an unsupported change, e.g. a standalone schema delete), or `blocked` (query/policy gated by an unapplied or missing dependency, with the condition in `reason`). @@ -496,5 +497,5 @@ matches the argument. A wrong id, missing lock, invalid lock JSON, or unsupporte lock version exits non-zero and leaves the file untouched. This is manual recovery for abandoned local locks. OmniGraph does not perform -PID-liveness checks, TTL expiry, stale-lock breaking, or automatic unlock in -Stage 2C. +PID-liveness checks, TTL expiry, stale-lock breaking, or automatic unlock +today. diff --git a/docs/user/operations/server.md b/docs/user/operations/server.md index 18032e9d..3f6bcd0d 100644 --- a/docs/user/operations/server.md +++ b/docs/user/operations/server.md @@ -40,7 +40,7 @@ storage root, with no local config directory. `--bind`, ### Stored-query validation at startup -If a graph declares a `queries:` registry (see [cli-reference](../cli/reference.md)), the server **loads and type-checks every stored query against that graph's live schema at startup**. Query parse/type failures quarantine that graph; if no graph remains healthy, startup refuses. Two MCP-exposed queries claiming the same tool name are likewise graph-local startup failures. Non-blocking advisories (e.g. an MCP-exposed query with a vector parameter an agent cannot supply) are logged. Validate offline before deploying with `omnigraph queries validate`. Discover the exposed queries as a typed tool catalog with `GET /queries`, and invoke one over HTTP with `POST /queries/{name}` (both below). +If a graph declares a `queries:` registry (see [cli-reference](../cli/reference.md)), the server **loads and type-checks every stored query against that graph's live schema at startup**. Query parse/type failures quarantine that graph; if no graph remains healthy, startup refuses. Two MCP-exposed queries claiming the same tool name are likewise graph-local startup failures. Non-blocking advisories (e.g. an MCP-exposed query with a vector parameter an agent cannot supply) are logged. Validate offline before deploying with `omnigraph queries validate`. Discover the stored queries as a typed tool catalog with `GET /queries`, and invoke one over HTTP with `POST /queries/{name}` (both below). ## Endpoint inventory @@ -57,7 +57,7 @@ graph id from the cluster's applied revision: | POST | `/graphs/{id}/export` | bearer + `export` | NDJSON stream | | POST | `/graphs/{id}/mutate` | bearer + `change` | mutation (canonical; `query`/`name`; accepts legacy `query_source`/`query_name` as serde aliases) | | POST | `/graphs/{id}/change` | bearer + `change` | **deprecated** alias of `/mutate` (carries `Deprecation: true` + `Link: ; rel="successor-version"`) | -| GET | `/graphs/{id}/queries` | bearer + `read` | list the `mcp.expose` stored queries as a typed tool catalog | +| GET | `/graphs/{id}/queries` | bearer + `read` | list the graph's stored queries as a typed tool catalog | | POST | `/graphs/{id}/queries/{name}` | bearer + `invoke_query` (+ `change` for a stored mutation) | invoke a named query from the `queries:` registry; deny == 404 | | GET | `/graphs/{id}/schema` | bearer + `read` | get current `.pg` source | | POST | `/graphs/{id}/schema/apply` | bearer + `schema_apply` (target=`main`) | disabled for cluster-backed serving; returns 409 and points operators at `omnigraph cluster apply` + restart | @@ -76,12 +76,17 @@ Server-level management endpoints: |---|---|---|---| | GET | `/graphs` | bearer + `graph_list` on `Server::"root"` | list ready/served graphs | +> The per-graph subsections below name routes in shorthand (`GET /queries`, +> `POST /query`, `POST /mutate`, `POST /queries/{name}`); every one is served +> under the `/graphs/{id}/…` prefix shown in the table — only `/graphs` and +> `/healthz` are flat. + ### Stored-query catalog (`GET /queries`) -List the graph's **`mcp.expose`** stored queries as a typed tool catalog — enough for a client (e.g. an MCP server) to register each as a tool without fetching `.gq` source. Each entry: `{ name, tool_name, description, instruction, mutation, params }`, where each param is `{ name, kind, item_kind?, vector_dim?, nullable }`. `kind` is one of `string | bool | int | bigint | float | date | datetime | blob | vector | list` (decomposed so a consumer maps it with a closed `switch`, never re-parsing GQ type spelling). `bigint` (I64/U64), `date`, `datetime`, and `blob` are carried as JSON **strings** — a 64-bit integer loses precision as a JSON number, dates are ISO strings, and a blob is a URI string. +List the graph's stored queries as a typed tool catalog — enough for a client (e.g. an MCP server) to register each as a tool without fetching `.gq` source. Each entry: `{ name, tool_name, description, instruction, mutation, params }`, where each param is `{ name, kind, item_kind?, vector_dim?, nullable }`. `kind` is one of `string | bool | int | bigint | float | date | datetime | blob | vector | list` (decomposed so a consumer maps it with a closed `switch`, never re-parsing GQ type spelling). `bigint` (I64/U64), `date`, `datetime`, and `blob` are carried as JSON **strings** — a 64-bit integer loses precision as a JSON number, dates are ISO strings, and a blob is a URI string. - **Read-gated** (works in default-deny mode). The catalog is **graph-wide** (branch-independent; `read` is authorized against `main`). -- **`mcp.expose` defaults to `true`** — declaring a query in `queries:` lists it; set `mcp: { expose: false }` to keep it HTTP/service-callable but hidden from the catalog. +- **Every stored query in the applied registry is listed.** Cluster-served graphs have no per-query expose flag today — every query in the cluster `queries:` registry appears in the catalog. (Per-query exposure may become a Cedar-policy decision in a later release; see [cluster-config](../clusters/config.md).) - **Not Cedar-filtered per query (yet).** A caller with `read` but not `invoke_query` can *list* a query they can't *invoke* (which would 404). Closing that gap is future per-query authorization; for now the catalog is a discovery surface and `invoke_query` remains the invocation gate. ### Stored-query invocation (`POST /queries/{name}`) @@ -163,8 +168,8 @@ Uniform `ErrorOutput { error, code?, merge_conflicts[], manifest_conflict? }` wi caller's pre-write view of one table's manifest version was stale. `ManifestConflictOutput { table_key, expected, actual }` tells the client which table to refresh and retry. This is the conflict shape produced by -concurrent `/mutate` (or its `/change` alias) or `/ingest` calls landing -the same `(table, branch)` race. +concurrent `/mutate` (or its `/change` alias), `/load` (or its deprecated +`/ingest` alias) calls landing the same `(table, branch)` race. HTTP status codes used: 200, 400, 401, 403, 404, 409, 429, 500. @@ -191,7 +196,8 @@ Cedar policy authorization runs **before** admission accounting so denied requests don't consume admission slots. Today admission gates every mutating handler: `/mutate` (and its -deprecated alias `/change`), `/ingest`, `/branches/{create,delete,merge}`, +deprecated alias `/change`), `/load` (and its deprecated alias `/ingest`), +`/branches/{create,delete,merge}`, and `/schema/apply`. Read-only endpoints (`/snapshot`, `/query`, `/read`, `/export`, `/branches` GET, `/commits`, `/schema` GET) are not admission-gated. @@ -199,7 +205,7 @@ admission-gated. ## Body limits - Default: 1 MB -- `/ingest`: 32 MB +- `/load` (and its deprecated `/ingest` alias): 32 MB ## Auth model (`bearer + SHA-256`) @@ -227,7 +233,7 @@ See [deployment.md](../deployment.md) for token-source operational details. - CORS — not configured; add `tower_http::cors` if needed. - Rate limiting — per-actor admission control gates `/mutate` (alias - `/change`), `/ingest`, `/branches/{create,delete,merge}`, + `/change`), `/load` (alias `/ingest`), `/branches/{create,delete,merge}`, `/schema/apply` (see "Per-actor admission control" above). No global rate limiter is configured; add `tower_http::limit` if a graph-wide cap is needed. diff --git a/docs/user/reference/constants.md b/docs/user/reference/constants.md index ec19f4d8..3da9a2b0 100644 --- a/docs/user/reference/constants.md +++ b/docs/user/reference/constants.md @@ -18,7 +18,7 @@ | Expand CSR-build cost factor | `CSR_BUILD_FACTOR = 1.5` | traversal | | Expand mode override | `OMNIGRAPH_TRAVERSAL_MODE` (`indexed`\|`csr`; unset = cost-based auto) | traversal | | Default body limit | `1 MB` | HTTP server | -| Ingest body limit | `32 MB` | HTTP server | +| Load (bulk-write) body limit | `32 MB` | HTTP server (`/load`; shared by the deprecated `/ingest` alias) | | Default embed provider/model | `openai-compatible` / `openai/text-embedding-3-large` | engine embedding | | OpenAI-direct embed model | `text-embedding-3-large` | engine embedding | | Gemini-direct embed model | `gemini-embedding-2` | engine embedding | diff --git a/docs/user/schema/index.md b/docs/user/schema/index.md index 105281c0..df82a23d 100644 --- a/docs/user/schema/index.md +++ b/docs/user/schema/index.md @@ -72,6 +72,8 @@ Applying a plan reports whether it was supported, the steps applied, and the res `DropProperty` and `DropType` steps default to `Soft` mode: the catalog tombstones the entry but the prior column / dataset remains time-travel-reachable via `snapshot_at_version(prev)` until `omnigraph cleanup` runs. Soft drops are reversible. -Pass `--allow-data-loss` (CLI) or `allow_data_loss: true` (HTTP `POST /schema/apply` body, SDK `SchemaApplyOptions`) to promote every drop in the plan to `Hard` mode. Hard drops run `cleanup_old_versions` on the affected dataset immediately after the manifest publish, making the prior column / dataset unreachable. **Irreversible.** +Pass `--allow-data-loss` (CLI `schema apply`) or `allow_data_loss: true` (SDK `SchemaApplyOptions`) to promote every drop in the plan to `Hard` mode. Hard drops run `cleanup_old_versions` on the affected dataset immediately after the manifest publish, making the prior column / dataset unreachable. **Irreversible.** -The flag is honored uniformly across transports — `omnigraph schema apply --allow-data-loss`, `POST /schema/apply { schema_source, allow_data_loss: true }`, and `apply_schema_with_options(.., SchemaApplyOptions { allow_data_loss: true })` produce identical plans and identical effects. +This is the **direct/embedded** schema-apply path — `omnigraph schema apply --store …` and the embedded SDK `apply_schema_with_options(.., SchemaApplyOptions { allow_data_loss: true })` produce identical plans and identical effects. + +**Cluster-managed graphs are different.** A graph served from a cluster evolves only through `omnigraph cluster apply`, which performs **soft drops only** (no `allow_data_loss` path), and the HTTP `POST /schema/apply` route is **disabled (returns 409) for cluster-backed serving** — see [server](../operations/server.md) and [cluster-config](../clusters/config.md). Direct `schema apply` against a cluster-managed storage path is likewise refused. diff --git a/docs/user/search/indexes.md b/docs/user/search/indexes.md index 57935cd9..af8c1287 100644 --- a/docs/user/search/indexes.md +++ b/docs/user/search/indexes.md @@ -22,7 +22,7 @@ list/`Blob` columns → none. > **Coverage and cost.** Each indexed column adds index files and build time, and > an index only covers the fragments it was built over. Rows appended after the -> index was built (e.g. by `ingest --mode merge`) are scanned unindexed until a +> index was built (e.g. by `load --mode merge`) are scanned unindexed until a > reindex extends coverage; see [maintenance](../operations/maintenance.md) → `optimize`. ## L2 — OmniGraph orchestration diff --git a/openapi.json b/openapi.json index 225a9596..03080870 100644 --- a/openapi.json +++ b/openapi.json @@ -1006,7 +1006,7 @@ "queries" ], "summary": "List the graph's exposed stored queries as a typed tool catalog.", - "description": "Returns the `mcp.expose == true` subset of the `queries:` registry, each\nwith its MCP tool name, read/mutate flag, description/instruction, and\ntyped parameters — enough for a client to register them as tools without\nfetching `.gq` source. Read-gated; the catalog is graph-wide (branch\nindependent — `read` is authorized against `main`). **Not** Cedar-filtered\nper query yet, so it can list a query whose `invoke_query` the caller\nlacks (a known gap until per-query authorization lands).", + "description": "Returns every stored query in the `queries:` registry, each\nwith its MCP tool name, read/mutate flag, description/instruction, and\ntyped parameters — enough for a client to register them as tools without\nfetching `.gq` source. Cluster-served graphs have no per-query expose flag,\nso the catalog lists them all. Read-gated; the catalog is graph-wide (branch\nindependent — `read` is authorized against `main`). **Not** Cedar-filtered\nper query yet, so it can list a query whose `invoke_query` the caller\nlacks (a known gap until per-query authorization lands).", "operationId": "cluster_list_queries", "parameters": [ { @@ -1021,7 +1021,7 @@ ], "responses": { "200": { - "description": "Stored-query catalog (the mcp.expose subset, with typed params)", + "description": "Stored-query catalog (every stored query, with typed params)", "content": { "application/json": { "schema": { @@ -2248,7 +2248,7 @@ }, "QueriesCatalogOutput": { "type": "object", - "description": "Response for `GET /queries`: the `mcp.expose` subset of a graph's\nstored-query registry, each with typed parameters.", + "description": "Response for `GET /queries`: every stored query in a graph's\nregistry, each with typed parameters.", "required": [ "queries" ],