mirror of
https://github.com/ModernRelay/omnigraph.git
synced 2026-06-24 02:38:06 +02:00
docs(user): coherence cleanup aligned with 0.7.1 (#293)
* docs(cli): fix cluster apply semantics — converges graphs+schema, not config-only `cluster apply` creates graphs, applies schema updates (soft drops), writes stored-query/policy catalog resources, and executes approved graph deletes in one ordered run. Both the user docs and the shipped CLI help text still described it as a "Stage 3A" config-only (query/policy) subset that defers graph/schema changes "to a later stage" — wrong since the graph/schema executor landed. - docs/user/cli/reference.md: rewrite the cluster paragraph to describe apply's actual converge behavior; keep deferred for the genuinely-unsupported case (standalone schema deletes); drop the stale "Stage 3A" / "reserved for later stages" framing. - crates/omnigraph-cli/src/cli.rs: fix the `cluster apply` help text to match. Part of the docs/user coherence cleanup (docs/dev/docs-issues.md, P1). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FQ1Hf4eXLsJmeLUkTYBEw7 * docs(server): align stored-query exposure with cluster-only behavior server.md documented a per-query expose knob ("`mcp.expose` defaults to true; set `mcp: { expose: false }` to hide from the catalog") that does not exist in the only deployment mode. Cluster-only serving lists every stored query: the cluster registry has no expose field (`QueryConfig { file }`) and the boot bridge hardcodes `expose: true` for all cluster queries (omnigraph-server settings), and there is no GQ-level expose annotation. This contradicted clusters/config.md, which already states the correct behavior. Replace the knob bullet with the cluster truth (every applied query is listed; per-query exposure may become a Cedar-policy decision later) and drop the "`mcp.expose` stored queries" phrasing from the catalog description, the endpoint table, and the intro. The `mcp_expose` JSON catalog field is unchanged (still emitted, always true in cluster mode). Part of the docs/user coherence cleanup (docs/dev/docs-issues.md, P1). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FQ1Hf4eXLsJmeLUkTYBEw7 * docs(schema): split direct/embedded vs cluster-managed schema apply schema/index.md claimed `allow_data_loss` is "honored uniformly across transports" and listed HTTP `POST /schema/apply` among them. But that route is 409-disabled for cluster-backed serving (already documented in server.md), and cluster-managed graphs evolve only through `cluster apply` with soft drops — there is no cluster HTTP data-loss path. Scope the data-loss flag to the direct/embedded path (`schema apply --store`, SDK), and add a paragraph: cluster-managed graphs use `cluster apply` (soft drops only); HTTP `POST /schema/apply` is 409 for cluster serving; direct apply against a cluster-managed path is refused. Cross-refs server + cluster docs. Part of the docs/user coherence cleanup (docs/dev/docs-issues.md, P2). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FQ1Hf4eXLsJmeLUkTYBEw7 * docs(server): document /load as canonical in limits + admission prose The endpoint table already listed both `/load` (canonical) and `/ingest` (deprecated alias) at 32 MB, but the admission-control, body-limit, rate-limit, and manifest-conflict prose named only `/ingest` — and the constants page called the limit "Ingest body limit". Add `/load` alongside (or ahead of) `/ingest` everywhere, and rename the constant to "Load (bulk-write) body limit" noting the `/ingest` alias shares it. Part of the docs/user coherence cleanup (docs/dev/docs-issues.md, P2). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FQ1Hf4eXLsJmeLUkTYBEw7 * docs(cli): drop stale bearer-token keys + fix version string The "Bearer token resolution (CLI)" section still listed removed omnigraph.yaml keys (`graphs.<name>.bearer_token_env`, `auth.env_file`) — config surfaces that no longer exist and that implied plaintext tokens in config. Replace it with a pointer to the keyed-credential model documented above (`OMNIGRAPH_TOKEN_<NAME>` → `~/.omnigraph/credentials` → `OMNIGRAPH_BEARER_TOKEN`). Also fix the `version` row: the CLI prints 0.7.x, not 0.3.x. Part of the docs/user coherence cleanup (docs/dev/docs-issues.md, P2 + smaller). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FQ1Hf4eXLsJmeLUkTYBEw7 * docs: route-spelling note + drop stale stage/deferred crumbs - server.md: add a one-line note that the per-graph subsections name routes in shorthand (`GET /queries`, `POST /query`, `POST /mutate`, `POST /queries/{name}`) but every one is served under `/graphs/{id}/…` — the endpoint table is already fully-qualified. - clusters/config.md: redefine the `deferred` plan disposition as an unsupported change (e.g. a standalone schema delete) instead of "graph/schema change, later phase" (graph creates and schema updates apply now); drop the "Stage 2C" label from the lock-recovery note. - search/indexes.md: `ingest --mode merge` → canonical `load --mode merge`. Part of the docs/user coherence cleanup (docs/dev/docs-issues.md, P2 + smaller). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FQ1Hf4eXLsJmeLUkTYBEw7 * docs(dev): track user-docs coherence ledger; mark 2026-06-20 findings resolved Convert the scratch review notes into a tracked living ledger and link it from the dev index. All ten findings from the 2026-06-20 docs/user sweep are validated and fixed in this branch (P1 cluster-apply semantics + stored-query exposure; P2 schema-apply paths, /load canonical, bearer-token keys, route shorthand; plus version/ingest/deferred/stage crumbs). The verification grep checklist is retained for future audits. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FQ1Hf4eXLsJmeLUkTYBEw7 * docs(api): align GET /queries OpenAPI contract with cluster-only behavior Greptile P1 on #293: the prose fix in server.md left the OpenAPI surface stale. The utoipa annotations (handlers.rs, omnigraph-api-types QueriesCatalogOutput) still described the catalog as "the `mcp.expose == true` subset", and those drive the checked-in openapi.json — so SDK consumers read a contract the cluster-only server does not honor (it lists every stored query). Update the three Rust doc-comment/annotation strings to "every stored query" and regenerate openapi.json (OMNIGRAPH_UPDATE_OPENAPI=1; drift test green) in the same change, per AGENTS.md rule 4. Ledger updated: this finding resolved, plus the cross-repo drift it surfaced (omnigraph-ts generated spec/types and omnigraph-cookbooks best-practices bearer_token_env) tracked as open follow-ups. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FQ1Hf4eXLsJmeLUkTYBEw7 --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
f6d2cc03e3
commit
9c792649e2
12 changed files with 134 additions and 46 deletions
|
|
@ -401,8 +401,8 @@ pub struct QueryCatalogEntry {
|
|||
pub params: Vec<ParamDescriptor>,
|
||||
}
|
||||
|
||||
/// 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<QueryCatalogEntry>,
|
||||
|
|
|
|||
|
|
@ -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 = ".")]
|
||||
|
|
|
|||
|
|
@ -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).
|
||||
|
|
|
|||
68
docs/dev/docs-issues.md
Normal file
68
docs/dev/docs-issues.md
Normal file
|
|
@ -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.<name>.bearer_token_env`, `auth.env_file`) | Replaced with a pointer to the keyed-credential model (`OMNIGRAPH_TOKEN_<NAME>` → `~/.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_<NAME>` →
|
||||
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.
|
||||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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 <dir>`; `--graph <id>` picks a graph's bundle when several apply). `test` takes `--tests <file>`; `explain` takes `--actor`/`--action`/`--branch`/`--target-branch` |
|
||||
| `queries list \| validate` | inspect a cluster's applied stored-query registry (`--cluster <dir\|uri>`; `--graph <id>` 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 [<name>]` | 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 <LOCK_ID> --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
|
||||
`<config-dir>/__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
|
||||
<dir>` 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
|
||||
`<config-dir>/graphs/<graph-id>.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 <dir>` 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
|
||||
`<config-dir>/graphs/<graph-id>.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.<name>.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_<NAME>` env → the `[<name>]` 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.<name>.bearer_token_env`, `auth.env_file`) no longer exist.
|
||||
|
||||
## Duration parsing (cleanup)
|
||||
|
||||
|
|
|
|||
|
|
@ -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.<id>` 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.<id>`
|
||||
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.
|
||||
|
|
|
|||
|
|
@ -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: <mutate>; 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.
|
||||
|
|
|
|||
|
|
@ -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 |
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
],
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue