Skip to content

feat(query): a read describes its retrievals and score columns - #1130

Open
ragnorc wants to merge 4 commits into
ModernRelay:mainfrom
ragnorc:feat/read-descriptors
Open

ragnorc wants to merge 4 commits into
ModernRelay:mainfrom
ragnorc:feat/read-descriptors

Conversation

@ragnorc

@ragnorc ragnorc commented Oct 22, 2026

Copy link
Copy Markdown
Contributor

Summary

RFC 0047 rollout step 6: a read says which retrievals produced its order and what each returned score column measures.

The read envelope (POST /query, stored-query calls, query --json, and the --format jsonl metadata line) gains two additive arrays, absent when a read ranks nothing:

"retrievals": [
  { "id": "r0", "kind": "rrf", "arms": ["r1", "r2"], "recall": "exact" },
  { "id": "r1", "kind": "bm25", "binding": "d", "property": "title", "recall": "exact" },
  { "id": "r2", "kind": "bm25", "binding": "d", "property": "title", "recall": "exact" }
],
"metrics": [
  { "column": "fused", "kind": "rrf", "retrieval_id": "r0", "source": "rrf", "descending": true, "recall": "exact" }
]
  • One source of truth. omnigraph_planner::read_descriptors derives both arrays from the accepted physical plan: one retrieval per ranked Scan, per RankFuse and per fusion arm, ids in plan preorder with a fusion before its arms and the arms in argument order; one metric per return column of the root Projection (a return distinct's Aggregate) that reads a _distance, _score or _rrf column a retrieval of the plan writes. Nothing is stored beside the plan.
  • Every door alike. engine::execute derives them before the plan runs and attaches them to the QueryResult, so the ordinary, inspected and replay doors report the same ids for one plan. read_output renders them; a metric naming a retrieval the read does not describe is refused rather than rendered half.
  • recall is the contract, not what one run did: nearest is approximate, bm25 exact, rrf approximate when either arm is. No parameter value (query text or vector) appears.

Three readings of the RFC text, recorded in its decision log: a column computed from a score is not a metric, nor is a stored property of a score column's name on a schema older than the reservation (such a read keeps working); no run establishes embedding counts yet, so nearest reports embedding_coverage as unknown (not_computed); and the Arrow IPC response, which has no JSON envelope, carries neither array.

The RFC's rollout table now records steps 3 (#1066) and 4 (#1069) as merged.

Tests

  • Engine engine_v2_plan_replay.rs: a_read_describes_its_retrievals_and_score_columns (two bm25 arms over one property with two columns returning one fused score, a nearest with its distance projected, a mixed fusion, a return distinct score key, an unranked read; inspected, ordinary and replayed runs agree). The shared replayed helper now requires every replay to reproduce its run's descriptors.
  • Planner bound_plan.rs: a fused plan read back from its serialized form describes itself identically; a fusion arm that lost its ranking is an internal error. In-source descriptors.rs: a stored property named _score is no metric and does not fail the read.
  • Server data_routes.rs: query_envelope_describes_retrievals_and_score_columns (the exact wire shape, ordered arm references, shared score projections, no parameter values, absence on an unranked read); the remote nearest test also checks its retrieval. stored_queries.rs::invoke_stored_read_returns_rows covers the stored-query door.
  • CLI cli_data.rs: ranked_read_describes_its_retrieval_in_json_and_jsonl; parity_matrix.rs::parity_ranked_query_descriptors compares the embedded and remote envelopes; the in-source jsonl test covers both presence and absence.
  • api-types: read_descriptors_render_and_round_trip (wire shape, decode/encode identity for the remote CLI, old payloads, orphan metric refusal).
  • openapi.json regenerated.

Docs

Search guide "What a ranked read reports", the CLI reference's machine-readable positions, the execution guide, the RFC decision log, and a changelog note.

A ranked read's JSON envelope gains two additive arrays derived from the
accepted plan: retrievals (one per ranked scan, per rrf() fusion and per
fusion arm, ids in plan preorder with a fusion before its arms and the
arms in argument order) and metrics (one per returned column whose value
is a score a retrieval of the plan writes, a return distinct group key
included). The planner derives them; execution attaches them to the query
result before the plan runs, so every read door and a replay report the
same ids for one plan. No parameter value is included, and a stored
property named like a score column on an older schema is no metric.

ragnorc commented Oct 22, 2026

Copy link
Copy Markdown
Contributor Author

Recommendation

Do not merge this head yet. The read-descriptor behavior matches RFC 0047. Test Workspace on this commit fails one test, openapi_inventory_matches. Classify the new OpenAPI words, then merge.

This review is a comment. It is not an approval.

What this change does

A ranked read now reports the retrievals that produced its order, and the returned columns that hold a score.

The planner derives that report from the accepted physical plan (read_descriptors in crates/omnigraph-planner/src/descriptors.rs). execute in crates/omnigraph/src/engine/mod.rs attaches it to the query result before the plan runs. The ordinary door, the inspected door, and replay therefore share one set of ids. JSON envelopes gain retrievals and metrics. The surfaces are POST /query, stored-query calls, query --json, and the --format jsonl metadata line. Both arrays are omitted when empty. Old payloads still decode. QueryResult::to_arrow_ipc writes batches only and carries neither array.

recall is the retrieval kind's contract. nearest is approximate even when a run scores every row. bm25 is exact. rrf is approximate when either arm is. embedding_coverage on a nearest retrieval is always {"state":"unknown","reason":"not_computed"}. No parameter value is included. A stored property named _score on an unranked read is not a metric.

Legal queries keep the same rows. This change does not write Lance data, and it does not change index use. Lance ANN search stays approximate. A flat scan stays an execution choice. The declared recall follows the kind, so a client does not depend on a guarantee that disappears when an index is built.

Blocking

  1. The OpenAPI vocabulary inventory does not classify the new guarded words. tests::openapi_inventory_matches panics. The shipped spec has ten unclassified occurrences:
  • MetricKindOutput description, the word column
  • MetricOutput description, the word column, twice
  • MetricOutput.column as a property name and as a required name
  • ReadOutput.metrics description, the word column, twice
  • RecallOutput description, the word row
  • RetrievalKindOutput description, the word column
  • the embedding_coverage field description, the word rows

Add one inventory row per occurrence in tools/omnigraph-vocabulary-guard/graph-vocabulary-inventory.tsv. Keep the wire name column. Classify these rows as retain and result_projection, the same class as ReadOutput.columns and ReadOutput.rows. Put a rationale on each row. Keep the file sorted by occurrence id. A prose edit changes the occurrence hash, so classify the text you intend to ship. Then this command must pass:

cargo test -p omnigraph-vocabulary-guard --locked --lib openapi_inventory_matches

The Graph Vocabulary Guard job is skipped on pull requests, and VOCABULARY_AUDIT_ENABLED is false. The workspace unit test is the check that ran. It fails on this head.

Optional

  1. The field doc on RetrievalOutput.embedding_coverage says the field reports how many ranked rows hold an embedding. EmbeddingCoverage has one variant, NotComputed. Every nearest retrieval emits unknown with reason not_computed. The type doc on EmbeddingCoverageOutput already says a read establishes no embedding count. Use that sentence on the field. The word rows in the current sentence is one of the ten inventory hits. Fix the sentence before you classify that row.

  2. A column computed from a score is not a metric, because the walk keeps only a bare property access. The stored-property case has the unit test a_stored_property_named_like_a_score_is_no_metric. The computed-column case has no execution test. A small case such as bm25(...) > 0 as hit would lock that reading. This is a coverage gap. I could not show a wrong metric for that shape from the code as written.

Tradeoff and liability

Nearest recall stays approximate on the exact overfetch pass. A client must not treat a flat pass as a promise. That promise would disappear when an index is built. This matches RFC 0047 and the Lance alignment fence.

The report is one derived view of the plan. There is no second stored description. Query semantics stay in the plan. Index layout stays derived state.

The new cost is a stable wire surface. Each later envelope array should use the same door. Derive it from the plan, attach it in execute, and render it in read_output. Each new OpenAPI description that uses a guarded word (column, row, rows, table, and the rest of that list) needs an inventory row. Five similar arrays would add wire fields and inventory rows. They would not add a second source of truth, as long as they stay derived.

A future score carrier that is not a bare property access would omit a metric. A cast, or an alias of a group key, is that shape. It is not a legal return today. T9 refuses a rank expression beside an aggregate. T56 refuses distinct plus aggregates. A return distinct of a score stays a property access on the aggregate. The engine test covers that shape.

Other open work

This head conflicts with current main (60bfd19db780fdff3a5178f959c1204143420114). Both sides changed these files:

  • crates/omnigraph-api-types/src/lib.rs
  • crates/omnigraph-cli/tests/integration/cli_data.rs
  • crates/omnigraph-server/tests/integration/data_routes.rs
  • crates/omnigraph/src/engine/mod.rs
  • docs/dev/execution.md
  • docs/user/cli/reference.md
  • docs/user/search/index.md
  • openapi.json

On main, execute still returns the plan run directly. Keep the descriptor attachment on that one function when you rebase.

Open PR #1012 also edits ReadOutput constructors, openapi.json, cli_data.rs, data_routes.rs, and the CLI reference. New ReadOutput values there need empty retrievals and metrics. Open PR #1137 edits cli_data.rs and the CLI reference. Open PR #1140 edits openapi.json and the crate manifests. Open PR #1139 edits operations.rs in omnigraph-api-types and does not define a second read schema. A query tool that returns the route JSON will carry these arrays.

Validation

Reviewed head: 9383fc8f693cbf0b97cb69d359d6aec7f65f856f. Merge base with origin/main: e60eb016941c6a4d41e03e74aa40c923a4ee4c01.

Local, checkout /tmp/pr1130, CARGO_TARGET_DIR=/workspace/target:

cargo test --locked -p omnigraph-planner --lib a_stored_property_named_like_a_score_is_no_metric

Result: 1 passed, descriptors::tests::a_stored_property_named_like_a_score_is_no_metric.

Local, same checkout, CARGO_TARGET_DIR=/tmp/pr1130-vocab-target:

cargo test --locked -p omnigraph-vocabulary-guard --lib openapi_inventory_matches -- --nocapture

Result: tests::openapi_inventory_matches failed. 0 passed, 1 failed, 51 filtered out. The panic lists the same ten occurrences as CI. The shell line after tee printed exit 0 because pipefail was off. The test summary is the result.

Exact-commit CI, run 39746533611, Test Workspace job 119716311280: 4927 tests run, 4926 passed, 1 failed, 40 skipped. The failure is omnigraph-vocabulary-guard tests::openapi_inventory_matches at tools/omnigraph-vocabulary-guard/src/lib.rs:1919. These passed in that job:

  • omnigraph-planner descriptors::tests::a_stored_property_named_like_a_score_is_no_metric
  • omnigraph-planner::integration bound_plan::a_nearest_plan_with_its_vector_reads_back_equal
  • omnigraph-api-types tests::read_descriptors_render_and_round_trip
  • omnigraph-engine::integration engine_v2_plan_replay::a_read_describes_its_retrievals_and_score_columns
  • omnigraph-server::integration data_routes::query_envelope_describes_retrievals_and_score_columns
  • omnigraph-cli read_format::tests::jsonl_format_emits_metadata_first
  • omnigraph-cli::integration cli_data::ranked_read_describes_its_retrieval_in_json_and_jsonl
  • omnigraph-cli::integration parity_matrix::parity_ranked_query_descriptors

GQT ordinary, GQT dst, GQT served, and the DST pinned suite passed on this commit. rustfmt and clippy passed. RustFS S3, default and failpoints, passed. omnigraph-server --features aws passed. The Graph Vocabulary Guard job was skipped, because the workflow skips that job on pull requests.

I did not finish a local rerun of the engine, server, or CLI integration tests. Those passed on CI for this commit. I did not measure performance. This change does not alter storage traffic, so the DST cost golden is unchanged. I did not run S3 or Azure locally.

Regression proof

No GQT before-and-after pair applies. This is a new envelope contract. GQT records rows, counts, result column types, and errors. It has no expectation for retrievals or metrics. Legal queries keep their rows. The arm-count error inside read_descriptors is an internal error for a plan that acceptance should have refused. It is not a user query shape. The Rust tests above are the owners for envelope metadata.

Inline: crates/omnigraph-api-types/src/lib.rs:691 (MetricOutput.column)

Blocking. This property name, and the new OpenAPI descriptions around it, are unclassified vocabulary. openapi_inventory_matches fails on this commit with ten occurrences of column, row, and rows. Keep the wire name column. Add one retain / result_projection row per occurrence in tools/omnigraph-vocabulary-guard/graph-vocabulary-inventory.tsv, sorted by occurrence id. The full list is in the review body.

Inline: crates/omnigraph-api-types/src/lib.rs:654 (embedding_coverage)

Optional. This sentence says the field reports how many ranked rows hold an embedding. The only value the code emits is {"state":"unknown","reason":"not_computed"}. The doc on EmbeddingCoverageOutput already says a read establishes no embedding count. Use that sentence here. The word rows is also one of the unclassified inventory hits, so change this text before you classify that row.

@cursor

cursor Bot commented Oct 24, 2026

Copy link
Copy Markdown

Recommendation

Do not merge this head yet. The read-descriptor behavior still matches RFC 0047. One OpenAPI naming rule from current main fails on this commit. Rename the four string-enum schemas, regenerate the spec, move the inventory rows, then merge.

This review is a comment. It is not an approval.

What this change does

A ranked read reports the retrievals that produced its order, and the returned columns that hold a score.

The planner derives that report from the accepted physical plan (read_descriptors in crates/omnigraph-planner/src/descriptors.rs). execute in crates/omnigraph/src/engine/mod.rs derives the report before the plan runs and attaches it to the query result after a successful run. The ordinary door, the inspected door, and replay share one set of ids. JSON envelopes gain retrievals and metrics on POST /query, stored-query calls, query --json, and the --format jsonl metadata line. Both arrays are omitted when empty. Old payloads still decode. Arrow IPC carries neither array.

recall is the retrieval kind's contract. nearest is approximate. bm25 is exact. rrf is approximate when either arm is. embedding_coverage on a nearest retrieval is {"state":"unknown","reason":"not_computed"}. No parameter value is included.

Legal queries keep the same rows. This change does not write Lance data. Lance ANN search stays approximate. A scan without an index can score every vector, and this report still says approximate for nearest. The client then stays on the contract that remains after an index is built. Lance's vector-search quickstart documents that split: a full scan scores every vector, and an ANN index trades recall for speed. Full-text search uses BM25 and stays the exact arm.

Earlier findings

  1. OpenAPI vocabulary inventory. Resolved. The merge adds nine retain / result_projection rows in tools/omnigraph-vocabulary-guard/graph-vocabulary-inventory.tsv. The tenth hit, the word rows on embedding_coverage, is gone because that sentence changed. The local command below passed. Test Workspace did not reach openapi_inventory_matches: fail-fast stopped after the convention failure and left 254 tests unrun.

  2. embedding_coverage field doc. Resolved. The field now says a read establishes no embedding count, and that the value is always unknown. The type doc on EmbeddingCoverageOutput already said that. openapi.json carries the same sentence.

  3. A column computed from a score. Resolved. a_read_describes_its_retrievals_and_score_columns now runs bm25(...) > 0.0 as hit beside bm25(...) as relevance and expects a metric only for relevance. That test passed on this commit in CI.

Blocking

  1. Four new string-enum schemas end in Output. Current main forbids that suffix on a string enum. docs/dev/http-api.md sets enum-schema-suffixes to Request Output Response. spec_follows_the_api_conventions in crates/omnigraph-server/tests/integration/openapi/conventions.rs checks it. The AWS job on this commit fails with:
  • CoverageUnknownReasonOutput
  • MetricKindOutput
  • RecallOutput
  • RetrievalKindOutput

conventions_reject_new_deviations fails on the same check.

Give each string enum a schema name with no transport suffix. BranchMergeOutcome and EntityKind already follow that rule. #[schema(as = LoadMode)] on LoadModeSchema is the existing way to set the schema name when the Rust name must stay. The compiler result types already use RetrievalKind, Recall, and Metric, so a Rust rename in omnigraph-api-types needs a distinct name or a schema as attribute. Use schema names RetrievalKind, Recall, MetricKind, and CoverageUnknownReason.

Regenerate openapi.json. Move the nine inventory rows onto the new schema paths. A path change changes the occurrence id. Keep each row retain / result_projection, and keep the file sorted by occurrence id.

The JSON values stay nearest, bm25, rrf, exact, approximate, distance, score, and not_computed. Only the component names change. HTTP contract 0.14 is still unreleased, so this is the time to set the names.

Object schemas keep Output. RetrievalOutput, MetricOutput, and EmbeddingCoverageOutput are objects. The failing test listed only the four string enums.

Merge with main

The second parent is current main, 7711e4a3def5c179cf95ec2525a6263819155916. A clean auto-merge conflicts only in openapi.json. The committed tree differs from that auto-merge in four places:

  • openapi.json drops the conflict markers, keeps CoverageUnknownReasonOutput, and takes main's DeploymentOutput.
  • The embedding_coverage description matches the new field doc.
  • The engine test gains the computed-score query.
  • The vocabulary inventory gains the nine rows.

No conflict markers remain. execute still attaches the descriptors on the one read function. Main's edits on that file add the CSV slice size for loads. Main's physical-plan edits add validation removal and CSV source partitions. Those nodes are not ranked scans, fusions, or return projections, so the descriptor walk still sees the same rank shape.

Other open pull requests

#1137 and #1139 merge cleanly onto this head. Both use 7711e4a3 as their merge base with this commit. #1139 calls handlers::server_query for the query tool and returns that JSON, so retrievals and metrics ride along. The tool description still says the result is rows, row_count, and graph_commit_id. Update that sentence when the two changes meet. #1139 does not define a second read schema.

#1012 still conflicts with this head in crates/omnigraph-cli/src/client.rs, crates/omnigraph-cli/tests/integration/cli_data.rs, crates/omnigraph-server/src/handlers.rs, docs/user/operations/server.md, and openapi.json. Any new ReadOutput value on that branch needs empty retrievals and metrics.

Tradeoff and liability

The report stays one derived view of the accepted plan. There is no second stored description. Query semantics stay in the plan. Index layout stays derived state. Nearest recall stays approximate on a full scan, so a client does not depend on a guarantee that disappears when an index is built.

The new cost is a stable wire surface plus the OpenAPI naming rule main now enforces. Each later envelope array should use the same door: derive it from the plan, attach it in execute, and render it in read_output. Each new string enum needs a suffix-free schema name. Each new description that uses a guarded word needs an inventory row. Five similar arrays would add wire fields, schema names, and inventory rows. They would not add a second source of truth while they stay derived.

This merge closes the vocabulary gap and the two coverage gaps from the previous review. It leaves the enum-name rule that main added after the feature was written. Setting the names before merge avoids a later client rename. Shipping the Output suffix would make the next similar enum copy a name the convention test rejects.

Validation

Reviewed head: d0913a76a5355250a443551e4ea1fa41e6ce6ca7. Parents: 9383fc8f693cbf0b97cb69d359d6aec7f65f856f and 7711e4a3def5c179cf95ec2525a6263819155916. origin/main at review time is that second parent.

Exact-commit CI, run 40101672643:

  • Test Workspace job 120894971507: 4707 passed, 1 failed, 40 skipped, 254 not run after fail-fast. Failure: openapi::conventions::conventions_reject_new_deviations. These passed in that job: read_descriptors_render_and_round_trip, ranked_read_describes_its_retrieval_in_json_and_jsonl, parity_ranked_query_descriptors, a_read_describes_its_retrievals_and_score_columns, a_stored_property_named_like_a_score_is_no_metric, query_envelope_describes_retrievals_and_score_columns, jsonl_format_emits_metadata_first, a_nearest_plan_with_its_vector_reads_back_equal.
  • Test omnigraph-server --features aws job 120894971585: spec_follows_the_api_conventions and conventions_reject_new_deviations failed. The first panic lists the four enum names above. invoke_stored_read_returns_rows passed in that job.
  • GQ Logic Tests (ordinary, served, dst, dst-clippy), the DST pinned suite, rustfmt, clippy, RustFS S3 default and failpoints, and Azurite passed.
  • The Graph Vocabulary Guard job was skipped on the pull request, as before.
  • Dependency Guard failed on RUSTSEC-2026-0387 (crypto-bigint 0.5.5 through jsonwebtoken). The nightly dependency guard on main at 7711e4a3 fails the same advisory (run 40060793527). This pull request adds one lock line, the arrow-schema dev-dependency. That advisory is outside this change.
  • CI Gate failed because those jobs failed.

Local, checkout /tmp/pr1130, CARGO_TARGET_DIR=/workspace/target:

cargo test --locked -p omnigraph-vocabulary-guard --lib openapi_inventory_matches

Result: tests::openapi_inventory_matches passed. 1 passed, 51 filtered out.

cargo test --locked -p omnigraph-planner --lib a_stored_property_named_like_a_score_is_no_metric

Result: 1 passed.

I did not finish a second local run of the api-types, engine, server, or CLI tests. Those descriptor tests passed on CI for this commit. I did not measure performance. This change does not alter storage traffic, so the DST cost golden is unchanged. I did not run S3 or Azure locally. I did not rerun openapi_spec_is_up_to_date. Test Workspace cancelled it. The committed embedding_coverage description matches the Rust field doc.

Regression proof

No GQT before-and-after pair applies. This is a new envelope contract. GQT records rows, counts, result column types, errors, and plan facts. It has no expectation for retrievals or metrics. The replay door is a Rust owner (engine_v2_plan_replay.rs). Legal queries keep their rows. The computed-score reading is covered by the engine test that passed on this commit. I added no temporary GQT case.

Inline: crates/omnigraph-api-types/src/lib.rs:623 (RetrievalKindOutput and the three sibling string enums)

Blocking. RetrievalKindOutput (line 623), RecallOutput (line 634), CoverageUnknownReasonOutput (line 670), and MetricKindOutput (line 677) generate string-enum schemas whose names end in Output. Rename those schemas, regenerate openapi.json, and move the inventory rows. The JSON values stay as they are.

The four string enums of the read descriptors become RetrievalKind,
Recall, MetricKind and CoverageUnknownReason, as the OpenAPI conventions
require; their JSON values are unchanged. The vocabulary inventory rows
for their descriptions move to the new schema paths.
@cursor

cursor Bot commented Oct 24, 2026

Copy link
Copy Markdown

Recommendation

Merge this head. The OpenAPI suffix blocker is resolved. This review finds no new blocker.

This review is a comment. It is not a GitHub approval.

What this change does

A ranked read reports the retrievals that set its order. It also reports each returned column that holds a score.

The planner derives both arrays from the accepted plan. execute attaches them to the query result. The ordinary door, the inspected door, and replay share one set of ids.

This commit only renames four string-enum schemas. The names are RetrievalKind, Recall, MetricKind, and CoverageUnknownReason. The JSON values stay nearest, bm25, rrf, exact, approximate, distance, score, and not_computed. Object schemas keep the Output suffix. RetrievalOutput, MetricOutput, and EmbeddingCoverageOutput stay objects.

Earlier findings

  1. OpenAPI vocabulary inventory. Resolved. The nine retain / result_projection rows remain. Three description rows now use the new schema paths. openapi_inventory_matches passes on this head.

  2. embedding_coverage field text. Resolved. This commit does not change that sentence. The field still says a read establishes no embedding count.

  3. A column computed from a score. Resolved. This commit does not change a_read_describes_its_retrievals_and_score_columns. That test passed on this commit in CI.

  4. Four string-enum schemas ended in Output. Resolved. docs/dev/http-api.md sets enum-schema-suffixes to Request Output Response. spec_follows_the_api_conventions checks that rule. The four names no longer use those suffixes. No schema that has an enum array ends in Request, Output, or Response.

Blocking

None.

Optional

None.

Other open pull requests

#1137 and #1139 merge cleanly onto this head. #1139 returns the query-route JSON from the query tool, so retrievals and metrics are in that JSON. The tool text still says the result is rows, row_count, and graph_commit_id. Update that sentence when the two changes meet. #1139 does not define a second read schema.

#1150 merges cleanly. It changes the description of FullTextIndexRequiredOutput only. It does not touch these enums.

#1151 merges cleanly. The merged lock keeps crypto-bigint 0.7.6 and keeps the arrow-schema line on omnigraph-api-types.

#1012 still conflicts in crates/omnigraph-cli/src/client.rs, crates/omnigraph-cli/tests/integration/cli_data.rs, crates/omnigraph-server/src/handlers.rs, docs/user/operations/server.md, and openapi.json. A new ReadOutput value on that branch needs empty retrievals and metrics.

Tradeoff and liability

The report stays one derived view of the accepted plan. This commit adds no second description. It sets the string-enum names before HTTP contract 0.14 ships, so a later client does not rename these schemas. The JSON contract is unchanged.

Nearest recall stays approximate on a full scan. Lance documents that split: a scan with no index scores every vector, and an ANN index trades recall for speed. Full-text search uses BM25. This commit does not change that contract.

Five similar arrays would add wire fields, schema names, and inventory rows. They add no second source of truth while they stay derived from the plan. Each new string enum needs a name with no transport suffix.

Validation

Reviewed head: bbd0cd8c66559adba32b96810789237301b6c887. Parent: d0913a76a5355250a443551e4ea1fa41e6ce6ca7. origin/main at review time is 7711e4a3def5c179cf95ec2525a6263819155916. The pull request is open and mergeable. The head did not move during this review.

The delta is four files: crates/omnigraph-api-types/src/lib.rs, crates/omnigraph-cli/src/read_format.rs, openapi.json, and tools/omnigraph-vocabulary-guard/graph-vocabulary-inventory.tsv. The Rust match from compiler kinds to wire kinds is the same mapping under the new names. No user document names the old schema names.

Local, checkout /tmp/pr1130-rereview at that head, CARGO_TARGET_DIR=/workspace/target:

cargo test --locked -p omnigraph-vocabulary-guard --lib openapi_inventory_matches

Result: tests::openapi_inventory_matches passed. 1 passed, 51 filtered out.

cargo test --locked -p omnigraph-server --test integration openapi::

Result: 106 passed, 0 failed. This includes openapi::conventions::spec_follows_the_api_conventions, openapi::conventions::conventions_reject_new_deviations, and openapi::openapi_spec_is_up_to_date.

A direct read of openapi.json shows RetrievalKind = nearest|bm25|rrf, Recall = exact|approximate, MetricKind = distance|score|rrf, and CoverageUnknownReason = not_computed. The four *Output names are absent.

Exact-commit CI, run 40123494256:

  • Test Workspace job 120959915031 succeeded. Its JUnit report has 4962 tests and 0 failures. These passed there: spec_follows_the_api_conventions, conventions_reject_new_deviations, openapi_spec_is_up_to_date, openapi_inventory_matches, read_descriptors_render_and_round_trip, a_read_describes_its_retrievals_and_score_columns, a_stored_property_named_like_a_score_is_no_metric, query_envelope_describes_retrievals_and_score_columns, invoke_stored_read_returns_rows, ranked_read_describes_its_retrieval_in_json_and_jsonl, parity_ranked_query_descriptors, jsonl_format_emits_metadata_first, and a_nearest_plan_with_its_vector_reads_back_equal.
  • Test omnigraph-server --features aws succeeded.
  • GQ Logic Tests (ordinary, served, dst, dst-clippy), the DST pinned suite, rustfmt, clippy, RustFS S3 (default and failpoints), Azurite, the V5 to V10 format fence, and Storage Upgrade Compatibility succeeded.
  • The Graph Vocabulary Guard job was skipped on the pull request, as before. The workspace unit test is the check that ran.
  • Dependency Guard failed on RUSTSEC-2026-0387 (crypto-bigint 0.5.5). This commit does not change Cargo.lock. The advisory is patched in >= 0.7.6. fix(server): remove crypto-bigint 0.5 for RUSTSEC-2026-0387 #1151 sets 0.7.6. CI Gate failed because Dependency Guard failed. This is not a finding of this pull request.

I did not rerun the engine, route, or CLI descriptor tests locally. They passed in the Test Workspace report for this commit. I did not measure performance. This commit does not change storage traffic, so the DST cost golden is unchanged. I did not run S3 or Azure locally. Those CI jobs passed.

Regression proof

No GQT before-and-after pair applies. This commit renames schemas. It does not change rows, counts, result column types, errors, or JSON values. GQT records those facts and plan facts. It has no expectation for retrievals or metrics. The envelope owners are the Rust tests named above. I added no temporary GQT case.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant