docs+test: derive the capability lists from the source, and fail the build when they drift - #256
Merged
Merged
Conversation
…build when they drift
A source review of this repo concluded XERJ has no pipeline aggregations. It
has fifteen, shipped and tested. The reviewer had read a hand-maintained list
that stopped at `composite`, and the conclusion nearly became a roadmap item to
build a feature that already exists. The same lists advertised `has_child` and
`has_parent`, which `parse_query` rejects with a 400. Two counts of the same
thing disagreed with each other in the same crate.
Root cause: "what XERJ supports" was written down in prose in six places and
derived from the code in none of them. Every list was a literal someone had to
remember to bump, and nothing failed when they forgot. Correcting the prose
alone would have re-created the defect on the next commit, so this change makes
the lists derived and the derivation enforced.
## What is now the source of truth
- `xerj_query::parser::SUPPORTED_QUERY_TYPES` (50) and `REJECTED_QUERY_TYPES`
(2). `parser::tests::dispatch_table_matches_capability_manifest` reads
`parse_query`'s dispatch arms out of the file's own source
(`include_str!`, bounded by the `match` head and its catch-all arm) and fails
if the constants and the arms differ in either direction.
`manifest_labels_match_observed_behaviour` then proves the labels: every
supported name must not answer `unknown query type`, and every rejected name
must refuse with an explanatory message.
- `xerj_engine::aggs::SUPPORTED_AGG_TYPES` (62), pinned to the agg dispatch
table by the same technique.
- `xerj_console_api::seed::BUILTIN_DASHBOARD_COUNT` (14) — the single place the
dashboard count is written, pinned to `seed_specs()` by
`seeds_every_registry_dashboard`.
## What is now checked
`engine/crates/xerj-engine/tests/docs_capability_lists.rs` compares
`engine/README.md` and `landing/llms-full.txt` against those constants. The
lists live in `<!-- generated:… -->` regions that may contain only backticked
type names and plain-text family labels; a backticked qualifier such as
`` `knn (HNSW-served)` `` is a hard failure rather than a silently mis-parsed
entry, and a missing marker fails loudly instead of skipping the file. A sixth
test holds the README crate map to the workspace members, counting only table
rows so a crate merely name-dropped in prose does not satisfy it.
## Before / after
Wrapping the old lists in markers and running the new test at HEAD reports
exactly the drift the issue describes:
engine/README.md section `agg-types` has drifted from the source of truth.
implemented but undocumented: [62 names, the whole pipeline family among them]
engine/README.md section `rejected-query-types` has drifted...
implemented but undocumented: ["has_child", "has_parent"]
After: 6 passed, 0 failed. Removing one crate-map row reproduces the crate-map
failure; both were watched fail and pass.
## Prose corrected against the source
- `engine/README.md` — 23 query types listed becomes 50 plus the two rejected
ones; 15 aggregations becomes 62. The old table also called `cardinality`
"approximate", contradicting `aggs.rs`; `run_cardinality` collects a
`HashSet` and returns `distinct.len()`, so it is exact. Crate map went from
11 of 16 crates to all 16 — `xerj-autoindex`, the flagship feature, was one
of the five missing.
- `landing/llms-full.txt` §6 — the same two lists, in the doc AI agents read.
- `ROADMAP.md` — "26 publicly-documented query types", "~14 additional", "~49
dispatched / roughly 38 run", "15 aggregations plus ~15 more" and the note
"(The README under-lists these — a docs gap, not a defect.)" all go. So does
the claim that `nested` "returns 0 hits (no real nested-document
indexing/scoring)": the inner query is evaluated per nested element in
`index.rs`, and `test_nested_query` passes at HEAD. What is actually missing
there is narrower and is now stated as such — `score_mode` is parsed and
ignored and `inner_hits` is not parsed at all, an accepted-and-ignored pair
(#204). A stale `parser.rs:330` citation is replaced by a name.
- `aggs.rs` module docs — a nine-row table of "supported aggregation types"
replaced by a pointer to the constant.
- `xerj-console-api` — `lib.rs` said 13 built-in dashboards, `seed.rs` said 14,
`seed_specs()` has 14. The number now appears once, and the prose links to it.
- `demo/playbooks/CONSOLE_UX_REWORK.md` — said 13 and 14 in the same sentence.
## Honest scope
The lists are an *acceptance* claim, not a fidelity claim, and both docs now
say so: a listed type parses, plans and executes, which is not a promise that
every parameter matches Elasticsearch. Per-type gaps stay in ROADMAP.md and the
ES-YAML suite remains the measured answer. `weighted_avg` is deliberately not
in `SUPPORTED_AGG_TYPES` — it still returns a buried error instead of a 400,
which is tracked, not fixed here.
Fixes #211
… not exist, and no pipeline aggs The first pass of #211 fixed the lists in `engine/README.md`, `llms-full.txt`, `ROADMAP.md` and `engine/CLAUDE.md`, and pinned them to the source. It stopped at the repository's markdown. The published docs site carried the identical defect in both directions, and nothing checked it: * `landing/docs/queries.html` shipped cards for **`boosted`** and **`semantic_search`**. Neither string appears anywhere in `engine/crates` (`grep -rn '"boosted"' engine/crates` → nothing); the parser has `boosting` and `semantic`. Both would answer `unknown query type`. `semantic_search` was also an entry in the docs-site search index duplicated into all 44 pages, so the site's own search offered a query type that does not exist. * The page listed 34 of the 50 dispatched types and never mentioned the two that are recognised-and-rejected, so `has_child` looked merely absent rather than deliberately refused. * `landing/docs/aggregations.html` listed 15 of 62 aggregations, with the whole pipeline family missing — the exact omission that made a reviewer conclude XERJ has no pipeline aggregations and nearly file work to build them again. * 21 pages footed a section with `Source · engine/crates/<crate>/…` naming crates that have not existed under those paths since the workspace became `xerj-*`: `logs`, `api`, `common`, `server`, `storage`, `cluster`, `fts`, `compress`, plus an `otlp` crate that never existed (OTLP ingest lives in `xerj-api/src/native.rs`). A reader following one lands nowhere. Two claims in the same card grids are contradicted by the code they describe: `cardinality` was advertised as "bitmap-backed" when `run_cardinality` collects a `HashSet<String>` of every distinct value, and `percentiles` as "t-digest · bounded memory" when `run_percentiles` sorts *all* values into a `Vec<f64>` and interpolates — the source comment names t-digest as the ES *option*, not the algorithm. Both are now described as what the code does; the intro sentence that promised bounded memory is gone, replaced by the columnar-path rule that is actually in `fast_aggs.rs` (`FAST_AGG_MIN_DOCS = 10_000`). ## What is now enforced `docs_capability_lists.rs` grew an HTML extractor (one name per `<div class="item">` card, descriptions deliberately not scanned) and both pages joined the checked set, so the grids are compared for **equality** with `SUPPORTED_QUERY_TYPES` / `REJECTED_QUERY_TYPES` / `SUPPORTED_AGG_TYPES` — a phantom name and a missing family both fail. A card whose text is not a bare type name panics rather than being absorbed, matching the markdown extractor's rule (#204: no accepted-and-ignored input, including in the guard itself). `every_source_pointer_in_the_docs_site_resolves` walks every page under `landing/` and fails on any `engine/crates/<path>` that is not on disk. Watched fail, then pass: re-adding the `boosted` card and renaming `semantic` back reproduces `documented but not implemented: ["boosted", "semantic_search"]`; deleting the pipeline section reproduces the 15 undocumented names; reverting one crate path reproduces `landing/docs/analyzers.html → engine/crates/fts/…`. ## Dashboard count: the third source `seeds_every_registry_dashboard` promised in its name — and `CONSOLE_UX_REWORK.md` promised in prose — that the count is "pinned to the registry list". It only compared `seed_specs().len()` with the constant beside it. The registry is JavaScript (`xerj-ux/src/dashboards/registry.js`), and it is the actual definition of a built-in dashboard; comparing two Rust values to each other left the cross-language half of the drift unchecked, which is how #211 found three different numbers for one thing. The test now reads the `all` array out of `registry.js`, resolves each symbol to its module, takes that module's own `id`, and compares the id *sets* both ways. Dropping `settings` from `registry.js` now fails with `seeded but not in the registry: ["settings"]`. Gate: `cargo fmt --all --check` clean; `cargo clippy -p xerj-console-api -p xerj-engine -p xerj-query --all-targets -D warnings` clean; `xerj-console-api` 43/43, `xerj-query` 173+9, `xerj-engine --lib` 428/428, `docs_capability_lists` 9/9. No runtime code changed — the only non-doc edits are a test file and a `#[cfg(test)]` module. Fixes #211
xerj-org
force-pushed
the
fix/issue-211-doc-drift
branch
from
August 9, 2026 21:00
6bb21da to
aa3ac3c
Compare
…he guard see them Review of PR #256 found the second commit's own claim to be false as written. `aa3ac3c0` said of `semantic_search`: "Neither string appears anywhere in `engine/crates` … Fixed in all 44." It was fixed in the 44 embedded search-index blobs only. The docs site went on publishing the phantom in the two places a human actually reads. Verified against a live instance (release binary, scratch data dir, ES port): {"query":{"semantic_search":{...}}} -> 400 parse error: unknown query type `semantic_search` {"query":{"semantic":{"field":"embedding","text":"…"}}} -> 400 parse error: `query` must be a non-empty string {"query":{"semantic":{"field":"summary","query":"…","k":10}}} -> 200, correct doc first (_score 0.8247) ## What was still wrong * `landing/docs/playbooks/vector-search.html` shipped `{"semantic_search": {"field": "embedding", "text": "…"}}` as *the* worked example under "Semantic search · embed at query time" — the flagship AI-native feature. Two defects in one body: the clause name has never existed (`parse_semantic`, parser.rs:2557, is reached by `semantic`) and the parameter is `query`, not `text`. Rewritten to the real form, with the one-line `semantic_text` mapping that makes it runnable — both snippets executed verbatim against a live instance before being published. * Same page, `hybrid`: published at the top level of the search body and with bare clauses in `queries`. `parse_request` only reads `query`, so the body answers `400 Unknown key for a START_OBJECT in [hybrid]`, and `parse_hybrid` requires each entry to wrap its clause in `query` (`hybrid.queries[0] missing query`). Both corrected and re-run. The `knn` block above it is left alone: top-level `knn` really is handled (es_compat.rs:6991) and returns hits. * `landing/docs/migration-from-es.html` — "32 query types … (knn, semantic_search, hybrid)" and an aggregation list that stopped at `composite`, i.e. the pipeline family omitted. That is the exact by-omission defect #211 was filed for, on a page this PR had already edited. * `engine/README.md` contradicted itself. "100% ES API compatible — drop-in replacement" and "all ES query types" sat 140 lines above this PR's own new "Recognised and deliberately rejected with a 400: has_child, has_parent / Any other query type answers `unknown query type`". Both lines are also refuted by demo/playbooks/ES_COMPATIBILITY.md:65 (40 supported, 9 partial, 9 unsupported of 58 ES catalog types). * "All xerj aggregations are exact" (README) / "complete; all exact" (llms-full.txt) were **added by this PR** — and three lines below, the same generated block lists `sampler`, `random_sampler`, `diversified_sampler`. `run_sampler` (aggs.rs:9640) sorts matched docs by `_score` and truncates to `shard_size` (default 200), so every sub-agg under one runs over a sample; `random_sampler` shares that impl and never reads ES's `probability` (the string does not occur in aggs.rs). Narrowed to the claim that is true — no probabilistic sketch in the metric path — with the sampling family named as the deliberate exception, in the README, in llms-full.txt, and on landing/docs/aggregations.html. * Two more stale counts the same guard could not see: `landing/pricing` (twice) and `landing/demo` both said "38 query types". The parser dispatches 50. ## Why the guard missed all of it, and what changed The marked-region checks only see a list that opted in — three files. The docs site is 60+ pages of prose and samples. Three checks now read the whole published surface (`landing/**/*.html`, `landing/llms*.txt`, `engine/README.md`, `ROADMAP.md`): * `no_published_surface_names_a_phantom_query_type` — a source-derived denylist of names the docs have published that the parser has never dispatched (`boosted`, `semantic_search`), matched on token boundaries so the real MCP tool `xerj_semantic_search` is not a hit. A companion test retires an entry the moment the parser grows the name, so the denylist cannot outlive its reason. * `every_query_clause_in_a_published_sample_is_a_real_query_type` — anything directly under `"query": { … }` in a published sample must be in SUPPORTED ∪ REJECTED. That is the one position in an ES body where a key's meaning is unambiguous, so it needs no denylist. It reads 73 clauses across 11 distinct names today, and asserts it is reading something. * `published_capability_counts_match_the_constants` — a published *number* drifts exactly like a published list (32 / 38 / 50 for the same quantity), so counts now live in `<!-- generated:query-type-count -->` regions pinned to the constants' `.len()`, every occurrence checked, not just the first. Watched fail, then pass — each defect re-introduced on the fixed tree, test run, output read, then reverted: landing/docs/playbooks/vector-search.html:181 names `semantic_search` landing/docs/playbooks/vector-search.html:180 uses `semantic_search` in query position landing/docs/migration-from-es.html publishes 32 for `query-type-count`; the source has 50 landing/pricing/index.html:138 publishes 38 for `query-type-count`; the source has 50 The last one is the proof that the *second* occurrence in a file is checked. ## Gate `cargo fmt --all -- --check` clean · `cargo clippy -p xerj-engine --all-targets -- -D warnings` clean · `docs_capability_lists` 13/13 · `xerj-engine --lib` 428/428 · all other engine test binaries pass. Two conditions did not pass locally and neither contains a line from this change — both live in test binaries built from unmodified source, while the only Rust edited here is `tests/docs_capability_lists.rs`, a separate binary: `painless_script_limits` overflows its stack in a debug build (already recorded on this PR as reproducing at `origin/main`), and `query_string_default_field::field_less_query_string_cross_product_respects_the_request_deadline` is a 150ms wall-clock budget test that ran past its 3s allowance on a box at load average 320 (32 cores). Both passed in CI's Build + Test on this branch head before this commit. Reference-coding: retrieved this time (the server was up; the previous commit recorded it down). `xc.py xerj-search "registerQuery SearchModule QueryBuilder named writeable registry query type names"` returns `elasticsearch/server/src/main/java/org/elasticsearch/search/SearchModule.java` as the top hit — the analogous pattern, one registration site where the wire name and the builder are declared together so the registry is the single source of truth. APPROACH-ONLY (AGPL-3.0 / SSPL-1.0 / Elastic-2.0): nothing copied, and it confirms rather than changes the design already in this PR. A first query for a capability *manifest* returned ESQL datasource plumbing — irrelevant, and recorded as such.
The merge gate re-measured this branch and kept three findings open. All three were real; this is the correction. 1. ROADMAP.md:14 published "All aggregations are exact (no HLL, no sampling)" on a line THIS BRANCH ADDED, while the same branch's engine/README.md, landing/llms-full.txt and landing/docs/aggregations.html had already been corrected to say the opposite. Measured at HEAD: aggs.rs:2934 dispatches sampler and random_sampler to run_sampler; run_sampler (aggs.rs:9640-9659) sorts matches by _score and .take(shard_size) with unwrap_or(200); aggs.rs:2944 truncates diversified_sampler the same way; `grep -c probability aggs.rs` = 0, so ES's probability is accepted and ignored (#204). Three of those aggregations sit inside the 62 the sentence covered. Replaced by an "Exactness, precisely" paragraph that claims only what is measurable — no probabilistic sketch in the metric path, cardinality a true distinct count, terms doc_count precise — and then names BOTH exceptions. The second exception, percentiles with `hdr` (aggs.rs:7460, 7505: a DoubleHistogram auto-ranging replica, so values are quantized), was missing from engine/README.md and llms-full.txt too; both now say there are two exceptions rather than one. 2. ROADMAP.md's own counts were pinned to nothing. `grep -c generated: ROADMAP.md` was 0 and COUNT_DOCS held three HTML pages, so this branch published "50 query types" and "62 types" as hand-typed literals — re-creating, inside its own fix, the drift #211 exists to stop. Adding query type 51 would have left ROADMAP saying 50 with every test green. ROADMAP.md joins COUNT_DOCS and its three numbers move into generated:query-type-count / generated:rejected-query-type-count / generated:agg-type-count regions (HTML comments are invisible in rendered markdown, so the mechanism ports unchanged). The hand-copied 15-name pipeline list is deleted rather than marked — it was a second unguarded copy — and the prose repeats of the numbers are reworded away. The floor on marked counts found rises 5 -> 9. Watched fail: 50 -> 51 gives ROADMAP.md:12 publishes 51 for `query-type-count`; the source has 50 3. parser.rs manifest_labels_match_observed_behaviour could not see a mislabelled type. Moving "has_child" from REJECTED_QUERY_TYPES into SUPPORTED_QUERY_TYPES left both manifest tests green (2 passed; 0 failed), because a recognised-and-refused type never produces ParseError::UnknownQueryType — and the docs guard would then have REQUIRED has_child to be published as a capability. That is the #211 defect, undetected by the test written to detect it. parser.rs:5679 now also asserts the supported-side parse error does not contain "not supported": the phrase REJECTED_QUERY_TYPES must carry is the phrase SUPPORTED_QUERY_TYPES may not carry. Watched fail with has_child relabelled, then reverted and green. Known gaps, now stated in the PR body rather than implied away: the count guard is opt-in (a new page with no marker is unchecked); aggregation NAMES outside a marked region have no phantom denylist the way query types do; and the labels test proves acceptance, not fidelity — `type` is still mapped to match_all and `nested` still ignores score_mode/inner_hits, both counted among the 50 and both documented under Partial. Gate: cargo fmt clean; clippy -p xerj-query -p xerj-engine --all-targets -D warnings clean; xerj-query 173 + 9 passed / 0 failed; xerj-engine --lib 428 passed; docs_capability_lists 13 passed; cargo test -p xerj-engine 681 passed / 0 failed before the pre-existing debug-build stack overflow in painless_script_limits (reproduces at origin/main), with the eight test binaries after it run individually and all passing. No runtime code path is edited, so the ES-YAML conformance gate is untouched by construction.
The merge gate's three findings were closed in the previous commit and
re-measured here (has_child relabelled -> manifest_labels_match_observed_behaviour
fails with the not-supported message; ROADMAP 50 -> 51 ->
"ROADMAP.md:12 publishes 51 for `query-type-count`; the source has 50").
Reviewing the guard itself turned up the defect class it exists to prevent,
inside its own code. Five sites in tests/docs_capability_lists.rs swallowed a
read failure:
every_source_pointer_in_the_docs_site_resolves
html_files: `let Ok(entries) = read_dir(dir) else { return }`
`entries.flatten()`
page body: `read_to_string(page).unwrap_or_default()`
doc_surfaces (feeds the phantom + query-position checks)
walk: the same read_dir / flatten pair
no_published_surface_names_a_phantom_query_type
every_query_clause_in_a_published_sample_is_a_real_query_type
file body: `read_to_string(&file).unwrap_or_default()`
An unreadable or non-UTF-8 page became an empty string, and an empty string
passes every check below by finding nothing -- a confident "no phantom query
type on this page" for a page that was never read. The `pages.len() > 20` /
`files.len() > 20` floors do not catch the directory half either: one
subdirectory going unreadable drops its pages while sixty others keep the
total above the floor.
Both are now hard failures via read_dir_or_panic / read_surface_or_panic,
which name the path in the panic. This is the accepted-and-ignored pattern of
#204, and the file's own module docs and the PR body both claim the guard does
not do it; it does not now.
Watched fail, then pass: a non-UTF-8 landing/docs/__gate_probe.html made all
three site-wide checks fail with
cannot read published surface .../landing/docs/__gate_probe.html: stream did
not contain valid UTF-8 -- an unreadable page must fail this test; treating
it as empty would silently pass every check
then 13/13 green once removed.
Gate: cargo fmt --all -- --check clean; cargo clippy -p xerj-query -p
xerj-engine -p xerj-console-api --all-targets -D warnings clean; xerj-query
173 + 9 passed / 0 failed; xerj-console-api 108 passed / 0 failed; xerj-engine
710 passed / 0 failed across every test binary run with --no-fail-fast, the
sole exception being the pre-existing debug-build stack overflow in
painless_script_limits, which this session re-measured on an engine/ tree
checked out from origin/main and which aborts there identically. No runtime
code path is edited -- the only non-test change on this branch remains the
three `pub const` arrays -- so the ES-YAML conformance gate is untouched.
xerj-org
added a commit
that referenced
this pull request
Aug 10, 2026
Eleven PRs landed on main today and every open branch went CONFLICTING. Nothing here is a defect in either side — main moved underneath this one. Three textual conflicts, all resolved by keeping both intents. **CHANGELOG.md** — both sides appended bullets under the same `## [Unreleased] / ### Fixed` heading. Purely additive on both sides; #207's block is kept ahead of main's `index: false` (#260), phrase-semantics (#265), tied-score (#267) and autoindex-generation (#259) entries. Nothing dropped. **engine/crates/xerj-query/src/parser.rs** — both sides appended to the tail of the same `mod tests`. Ours added the `query_string` char-boundary regression (`a_non_ascii_query_string_is_parsed_or_refused_but_never_panics`), main's #256 added the capability-manifest scraper and its two drift guards (`dispatch_table_matches_capability_manifest`, `manifest_labels_match_observed_behaviour`). Disjoint; both kept, and all three pass together. **engine/crates/xerj-common/src/config.rs** — the only semantic conflict. Ours replaced the hand-maintained field sum with a comment pointing at the measured count; main's side still carried the stale sum (`5+3+2+…= 57 fields`), which #247 had not updated when it added `lifecycle`. Resolved toward ours, because "stop maintaining this by hand" is the whole point of #207 item 10 — but the *number* is then main's to move, and it did. See the follow-up commit. **landing/docs/*.html (44 files)** — one conflict each, all the same generated `docs-index` search blob, which both sides regenerated. Merged at character level from the common ancestor so both edits survive: ours corrected the `[vector] default_quantization` entry (base advertised a `scalar4` mode the engine never accepted), main's #256 renamed `queries.html#semantic-search` to `#semantic` and rewrote its snippet. Verified afterwards that 39 of the 44 pages now differ from main *only* in that blob, and that the remaining five (config, operations, storage, troubleshooting, vectors) differ only by this PR's own stale-default corrections — so #256's rewrites of aggregations.html and queries.html are preserved intact.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #211
An AI agent (Claude Opus 5) wrote this change. Split of verified (commands run, output observed) vs assumed (untested) is at the bottom.
The defect, reproduced at HEAD
The issue reports that internal docs list features that do not exist and omit ones that do. All four claims check out against the source at
origin/main:cargo test -p xerj-engine --test integration test_bare_count_bucket_script_agrees_below_and_above_the_fast_agg_thresholdbucket_scriptruns; it appears in no published listhas_child/has_parentdocumented but rejectedparser.rs::parse_has_childreturnsinvalid(...);ast.rscalls the AST variants removed corpseslib.rssaid 13,seed.rssaid 14,seed_specs()has 14 registry idsRather than reproduce by eye, the drift was reproduced as a test. Wrapping the existing stale lists in the new markers and running the new guard at HEAD prints exactly the issue's two directions:
Root cause, and why the fix is not "edit the prose"
"What XERJ supports" was written in prose in six places and derived from the code in none. Every list was a literal someone had to remember to bump, and nothing failed when they forgot. Correcting the text alone re-creates the defect on the next commit — which is exactly how the current text got there.
So the lists are now derived, and the derivation is enforced:
xerj_query::parser::SUPPORTED_QUERY_TYPES(50) andREJECTED_QUERY_TYPES(2). A unit test readsparse_query's dispatch arms out of the file's own source (include_str!, bounded by thematchhead and its catch-all arm) and fails if the constants and the arms differ in either direction. A second test proves the labels behaviourally in both directions: no supported name may answerunknown query typeor refuse with anot supportedmessage, and every rejected name must refuse with exactly that message. (The second half of the supported-side rule was missing until the fourth pass below — see the correction there.)xerj_engine::aggs::SUPPORTED_AGG_TYPES(62), pinned the same way.xerj_console_api::seed::BUILTIN_DASHBOARD_COUNT(14) — one place, pinned toseed_specs().engine/crates/xerj-engine/tests/docs_capability_lists.rscomparesengine/README.mdandlanding/llms-full.txtagainst those constants, and the README crate map against the workspace members.The checked regions are
<!-- generated:… -->blocks that may hold only backticked type names plus plain-text family labels. A backticked qualifier (`knn (HNSW-served)`) is a hard failure, not a silently mis-parsed entry, and a missing marker fails loudly instead of skipping the file — the guard must not itself become an accepted-and-ignored input (#204).Prose corrected against the source
engine/README.md— 23 query types → 50, plus the 2 rejected ones and why. 15 aggregations → 62. The old table also calledcardinalityapproximate, contradictingaggs.rs;run_cardinalitycollects aHashSetand returnsdistinct.len(), so exact is the correct word. Crate map: 11 of 16 crates → all 16 (xerj-autoindex, the flagship feature, was one of the five missing).landing/llms-full.txt§6 — the same two lists, in the file AI agents actually read.ROADMAP.md— removes "26 publicly-documented query types", "~14 additional", "~49 dispatched / roughly 38 run", "15 aggregations plus ~15 more", and the note "(The README under-lists these — a docs gap, not a defect.)". Also removes a claim that is simply false at HEAD:nesteddoes not "return 0 hits" — the inner query is evaluated per nested element inindex.rs, andtest_nested_querypasses. What is genuinely missing is narrower and now stated as such:score_modeis parsed then ignored andinner_hitsis not parsed at all, an accepted-and-ignored pair filed under Tracking: accepted-and-ignored is the dominant bug class, six instances found in one review #204. A staleparser.rs:330citation is replaced by a name.aggs.rsmodule docs — a nine-row "supported aggregation types" table replaced by a pointer to the constant.xerj-console-api,demo/playbooks/CONSOLE_UX_REWORK.md— the 13/14 disagreements.Honest scope
The lists are an acceptance claim, not a fidelity claim, and both docs now say so: a listed type parses, plans and executes; that is not a promise that every parameter matches Elasticsearch. Per-type gaps stay in
ROADMAP.md; the ES-YAML suite remains the measured answer.weighted_avgis deliberately not inSUPPORTED_AGG_TYPES— it still returns a buried error instead of a 400, which is tracked, not fixed here.Out of scope on purpose: the settings count (#207, has its own issue), and honouring-or-rejecting
nested.score_mode/inner_hits(a behaviour change needing an owner decision).engine/CLAUDE.md— the file the issue names — is gitignored and cannot appear in this diff. It was corrected in place on the working machine: the two stale lists now point at the constants, and four further drifts were removed (an example commit body carrying aCo-Authored-By: Claudetrailer that the repo's own rule forbids;cargo build --releasewith no-plisted as an approved command; "tests NOT yet run against a live XERJ instance", true in April 2026; and a conformance-suite table whose file counts were wrong in every row — measured 200 files, not 182).Gate
Run locally in this worktree:
cargo fmt --all -- --check— cleancargo clippy -p xerj-query -p xerj-engine -p xerj-console-api --all-targets -- -D warnings— cleancargo test -p xerj-query— 173 + 9 passed, 0 failedcargo test -p xerj-console-api— passed, 0 failedcargo test -p xerj-engine— all binaries pass except two pre-existing, non-related conditions on a machine at load average 43: severalpainlesswall-clock-budget tests flake under contention (all 66 pass with--test-threads=1), andpainless_script_limits::call_depth_limit_survives_the_multi_thread_block_in_place_pathoverflows its stack in a debug build. That last one was re-run on a stashed tree atorigin/mainand fails identically there — it is not from this change.docs_capability_lists6/6,parser::tests::dispatch_table_matches_capability_manifest,parser::tests::manifest_labels_match_observed_behaviour,aggs::capability_manifest_tests::dispatch_table_matches_capability_manifest,seed::tests::seeds_every_registry_dashboard.No engine behaviour changes, so the ES-YAML conformance gate is untouched by construction — the only non-doc code added is
pub constarrays and#[cfg(test)]code.Verified vs assumed
Verified (ran the command, read the output): every test result above; the drift output quoted at the top;
bucket_scriptexecuting;nestedfiltering;run_cardinalitybeing exact; 50/2/62 counts extracted from the constants; the crate-map guard failing when a row is deleted; the stack-overflow reproducing atorigin/main.Assumed (not run): that the ES-YAML conformance suite is unaffected — argued from the diff containing no runtime code path, not measured. That CI's runner does not hit the debug-build stack overflow, since
mainis currently green with that test present.Reference-coding: attempted
xc.py xerj-search "registry that enumerates all supported query types or aggregation types by name"; the retrieval server on :9200 was down at the time and the task forbids starting it. Skipping is defensible here anyway — the mandate exempts work confined to this repository's own code, and the only non-trivial addition scrapes this repo's dispatch tables. How tantivy or Elasticsearch registers its own query types is not evidence for how XERJ's docs should be pinned to XERJ's parser.Second pass — the docs site had the same defect (commit 2)
A second agent re-derived the four claims independently before touching
anything, then audited what the first pass had not covered. The first
pass's own claims hold up:
parse_querydispatchSUPPORTED50 +REJECTED2, zero difference either wayhas_child/has_parentare stubsparse_has_child/parse_has_parentare two-lineinvalid(...)calls (parser.rs:3611,:3625)run_pipeline_agg(aggs.rs:2979-2994)DashboardSpecliterals;registry.jsallarray has 14 entriesWhat it missed is that "the docs" is bigger than this repository's markdown.
Query types the docs published that do not exist
landing/docs/queries.htmlshipped cards forboostedandsemantic_search. Neither string occurs anywhere underengine/crates(
grep -rn '"boosted"' engine/crates→ nothing). The parser hasboostingandsemantic; both published names would answerunknown query type.semantic_searchwas also an entry in the docs-site search index, which isduplicated verbatim into all 44 pages — so the site's own search box offered a
query type XERJ has never had. Fixed in all 44.
The page also listed 34 of 50 dispatched types and never mentioned the two that
are recognised-and-rejected, so
has_childread as merely absent rather thandeliberately refused. It now carries all 50 plus a Recognised and rejected
section.
Aggregations: 15 of 62, pipeline family invisible
landing/docs/aggregations.htmlis the page an evaluator reads to answer "doesXERJ do pipeline aggregations?" — and the answer it gave was no, by omission.
It now lists all 62 under Metric / Bucket / Pipeline.
Two implementation claims the source contradicts
cardinality— advertised "Exact · bitmap-backed".run_cardinality(
aggs.rs:6450) collects aHashSet<String>of every distinct value. Exact,yes; bitmap-backed, no — and memory grows with cardinality, the opposite of
what the phrase implies.
percentiles— advertised "t-digest · bounded memory".run_percentiles(
aggs.rs:7451) sorts all values into aVec<f64>and interpolates. Thesource comment names t-digest as the ES option name, not the algorithm.
Memory is O(N).
The page intro promised bounded memory on that basis; it is replaced by the
rule that is actually in
fast_aggs.rs(FAST_AGG_MIN_DOCS = 10_000), and theunmeasured "sub-second SIEM top-N over millions of events" phrasing goes with
it.
21 pages pointed at crates that do not exist
Every docs section ends with
Source · engine/crates/…. Twenty-one namedpre-rename crates —
logs,api,common,server,storage,cluster,fts,compress— plus anotlpcrate that never existed (OTLP ingest isxerj-api/src/native.rs) and anapi/src/middleware/auth.rsthat isxerj-api/src/auth.rs. Every replacement path was checked to exist on diskbefore it was written.
Enforcement, so it cannot come back
docs_capability_lists.rsgained an HTML extractor — one name per<div class="item">card, card descriptions deliberately not scanned, soa name mentioned in prose cannot pass as a capability. Both pages joined the
checked set and are compared for equality with the constants: a phantom
name and a missing family each fail.
matching the markdown extractor's rule — the guard must not itself accept and
ignore (Tracking: accepted-and-ignored is the dominant bug class, six instances found in one review #204).
every_source_pointer_in_the_docs_site_resolveswalks every page underlanding/and fails on anyengine/crates/<path>not on disk.seeds_every_registry_dashboardnow does what its name says. It compared twoRust values to each other; the registry is JavaScript, and that is the
actual definition of a built-in dashboard. It now reads the
allarray out ofxerj-ux/src/dashboards/registry.js, resolves each symbol to its module,takes that module's own
id, and compares the id sets both ways — closing thecross-language half of the drift that produced three different counts.
Watched fail, then pass (each defect re-introduced on the fixed tree, test
run, output read, then reverted):
Gate (second pass, re-run after rebase onto
origin/main)cargo fmt --all -- --checkclean ·cargo clippy -p xerj-console-api -p xerj-engine -p xerj-query --all-targets -- -D warningsclean ·xerj-console-api43/43 ·xerj-query173 + 9 ·xerj-engine --lib428/428 ·docs_capability_lists9/9. No runtime code changed in this commit — the editsare HTML, one integration test, and a
#[cfg(test)]module.Still deliberately out of scope
The settings count (38 / 56 / 60) is #207's, and is untouched here to avoid
colliding with that issue's fix.
nested.score_mode/inner_hitsand thetypequery (accepted, and degraded tomatch_all) are accepted-and-ignoredinputs that need an owner's call on honour-or-reject; they are described
honestly on the page rather than silently fixed.
Reference-coding: skipped, legitimately. The retrieval server on
localhost:9200was down for this session (curl /_cluster/health→ exit 7)and the task forbids starting it — but the mandate also exempts work confined
to this repository, and this change is documentation plus a test that scrapes
this repo's own dispatch tables and HTML. How tantivy or Lucene documents its
own query registry is not evidence for what XERJ's pages should say.
Correction, and a third pass — the phantom was still on the site (commit 3)
The second commit's message overstates what it fixed, and this is the
correction.
aa3ac3c0says ofsemantic_search: "Neither string appearsanywhere in
engine/crates… Both would answerunknown query type… Fixed inall 44." It was fixed in the 44 embedded search-index blobs only. The two
places a human actually reads still shipped the phantom, on files this PR had
already edited:
landing/docs/playbooks/vector-search.html{"semantic_search": {"field": "embedding", "text": "…"}}as the worked example for the flagship AI-native featurelanding/docs/migration-from-es.htmlRe-verified against a live instance — release binary, scratch data dir, ES
port, not the shared retrieval server:
Fixed
vector-search.htmlsemantic example — rewritten to{"query":{"semantic":{"field":…,"query":…,"k":10}}}(parse_semantic,parser.rs:2557, requiresfield+query;kdefaults to 10), with theone-line
semantic_textmapping that makes it runnable. Both snippets wereexecuted verbatim against a live instance before being published.
vector-search.htmlhybrid example — a second broken body on the samepage, not previously flagged. It was published at the top level of the
search body (
parse_requestonly readsquery→400 Unknown key for a START_OBJECT in [hybrid]) with bare clauses inqueries(parse_hybridrequires each entry to wrap its clause in
query→hybrid.queries[0] missing query). Corrected and re-run. Theknnblock above it isleft alone: top-level
knnreally is handled (es_compat.rs:6991) andreturns hits.
migration-from-es.html—semantic_search→semantic, the countcorrected and pinned, the two recognised-and-rejected types explained, and
the pipeline family named with a link to
/docs/aggregations.html.engine/README.mdself-contradiction — "100% ES API compatible —drop-in replacement" and "all ES query types" sat 140 lines above this PR's
own "Recognised and deliberately rejected with a 400 … Any other query type
answers
unknown query type", and are refuted bydemo/playbooks/ES_COMPATIBILITY.md:65(40 supported / 9 partial / 9unsupported of 58 ES catalog types). Replaced with "Broad ES 8.x wire
compatibility", pointing at the measured coverage document.
run_sampler(aggs.rs:9640) sorts matched docs by_scoreand truncatesto
shard_size(default 200), so every sub-agg undersampler/random_sampler/diversified_samplerruns over a sample;random_samplershares that impl and the stringprobabilitydoes notoccur in
aggs.rs. Narrowed to what is true — no probabilistic sketch inthe metric path — with the sampling family named as the deliberate
exception in
engine/README.md,landing/llms-full.txtandlanding/docs/aggregations.html.ROADMAP.mdwas missed on that passand kept the strongest form of the claim on a line this PR adds; it is
corrected in the fourth pass below.
landing/pricing(twice) and
landing/demoboth said "38 query types". The parserdispatches 50.
The guard now reads the whole published surface
The marked-region checks only saw three files that had opted in; the docs site
is 60+ pages of prose and samples. Three new checks read
landing/**/*.html,landing/llms*.txt,engine/README.mdandROADMAP.md:no_published_surface_names_a_phantom_query_type— a source-deriveddenylist of names the docs have published but the parser has never
dispatched (
boosted,semantic_search), matched on token boundaries so thereal MCP tool
xerj_semantic_searchis not a hit. A companion test,the_phantom_list_only_holds_names_the_parser_really_lacks, fails the momentthe parser grows one of those names — the denylist cannot outlive its reason.
every_query_clause_in_a_published_sample_is_a_real_query_type—anything directly under
"query": { … }must be in SUPPORTED ∪ REJECTED.That is the one position in an ES body where a key's meaning is unambiguous,
so it needs no denylist. It asserts it is reading something — the guarded
floor is
checked > 20. (The figure "73 clauses across 11 distinct names"originally written here was measured at the third pass and is stale: the
count at this head is 77, re-measured in the fifth pass by forcing the
floor to fail and reading the number back. The test asserts the floor, not
an exact count, which is why the drift was invisible — a published number
pinned to nothing, the same defect this PR exists to remove, this time in
the PR body rather than the docs.)
published_capability_counts_match_the_constants— a published numberdrifts exactly like a published list (32 / 38 / 50 for the same quantity), so
counts live in
<!-- generated:query-type-count -->regions pinned to theconstants'
.len(). Every occurrence in a file listed inCOUNT_DOCSis checked, not just the first — and
COUNT_DOCSwas three HTML pages onthis pass, missing
ROADMAP.md, which the fourth pass below adds.Watched fail, then pass (each defect re-introduced on the fixed tree, test
run, output read, then reverted):
The last line is the proof that the second marked count in a file is checked.
Gate (third pass)
cargo fmt --all -- --checkclean ·cargo clippy -p xerj-engine --all-targets -- -D warningsclean ·docs_capability_lists13/13 ·xerj-engine --lib428/428 · every other engine test binary passes.
Two conditions did not pass locally, and neither contains a line from this
change — the only Rust edited here is
tests/docs_capability_lists.rs, andboth live in separate test binaries built from unmodified source:
painless_script_limitsoverflows its stack in a debug build (already recordedon this PR as reproducing at
origin/main), andquery_string_default_field::field_less_query_string_cross_product_respects_the_request_deadlineis a 150 ms wall-clock-budget test that ran past its 3 s allowance on a box at
load average 320 (32 cores). Both passed in CI's Build + Test on this
branch head before this commit; CI re-runs on the push.
Reference-coding
Retrieved this time — the server was up, where the previous pass recorded it
down.
xc.py xerj-search "registerQuery SearchModule QueryBuilder named writeable registry query type names"returnselasticsearch/server/src/main/java/org/elasticsearch/search/SearchModule.javaas the top hit: the analogous pattern, one registration site where the wire
name and the builder are declared together so the registry is the single source
of truth. APPROACH-ONLY (AGPL-3.0 / SSPL-1.0 / Elastic-2.0) — nothing
copied, and it confirms rather than changes the design already in this PR. An
earlier query for a capability manifest returned ESQL datasource plumbing;
irrelevant, and recorded as such rather than forced in.
Fourth pass — the three findings the merge gate left open (commit 4)
The merge gate re-measured this branch at
d470eecfand kept three findingsopen. All three were real. They are fixed here, each with the defect
re-introduced on the fixed tree first so the guard was watched failing.
1.
ROADMAP.mdpublished a false claim — one this PR itself addedROADMAP.md:14said, on a+line introduced by this PR:That is false at HEAD, and the same PR's other files already said so:
samplerandrandom_samplerboth dispatch torun_sampleraggs.rs:2934run_samplersorts matches by_scoreand.take(shard_size),unwrap_or(200)aggs.rs:9640-9659diversified_samplertruncates the same wayaggs.rs:2944grep -c probability engine/crates/xerj-engine/src/aggs.rsprobabilityis accepted and ignored (#204)percentileswithhdrquantizes through aDoubleHistogramreplicaaggs.rs:7460,7505Three of those sampling aggregations are inside the very count the sentence
covered, so the release would have shipped
ROADMAP.mdtelling a reader that arandom_samplerjob is exact whileengine/README.mdtold them the same jobsilently truncates to 200 documents. The sentence is replaced by an
Exactness, precisely paragraph that states what is true (no probabilistic
sketch in the metric path —
cardinalityis a true distinct count,termsdoc_countis precise) and then names both exceptions: the sampling familywith its
shard_sizedefault and its ignoredprobability, andhdrpercentiles.
hdris the second exception and was missing everywhere, not just inROADMAP.md.engine/README.mdandlanding/llms-full.txtsaid the samplingfamily was the deliberate exception; both now say there are two.
landing/docs/aggregations.htmlalready described thehdrswitch on thepercentilescard and needed no change.2.
ROADMAP.md's own counts were pinned to nothinggrep -c 'generated:' ROADMAP.mdreturned 0, andCOUNT_DOCSlisted threeHTML pages only. So this PR published
50 query typesand62 aggregation typesinROADMAP.mdas hand-typed literals — recreating, inside its own fix,the drift #211 exists to stop. Adding query type 51 would have left
ROADMAPsaying 50 with every test green.
Fixed:
ROADMAP.mdjoinsCOUNT_DOCS, and its three numbers now live in<!-- generated:query-type-count -->,<!-- generated:rejected-query-type-count -->and
<!-- generated:agg-type-count -->regions. HTML comments are invisible inrendered markdown, so the marker mechanism ports unchanged. The hand-copied
15-name pipeline list is deleted rather than marked — it was a second
unguarded copy — and replaced by a pointer to the machine-checked list. The
prose repeats of the numbers ("those 50 are the dispatch surface", "not among
the 62") are reworded so no unmarked literal remains. The floor on how many
marked counts must be found rises from 5 to 9, so a page dropping its markers
still fails.
Watched fail, then pass —
50→51and62→61on the fixed tree:3.
manifest_labels_match_observed_behaviourcould not see a mislabelled typeThe gate reproduced this by measurement and it reproduced here identically.
Moving
"has_child"fromREJECTED_QUERY_TYPESintoSUPPORTED_QUERY_TYPESleft both manifest tests green, because a recognised-and-refused type never
produces
ParseError::UnknownQueryType— and the docs guard would then haverequired
has_childto be published as a supported capability. That is the#211 defect, undetected by the test written to detect it.
Fixed at
parser.rs:5679: the supported-side loop now also asserts the parseerror does not contain
not supported— the phraseREJECTED_QUERY_TYPESisrequired to carry is the phrase
SUPPORTED_QUERY_TYPESis forbidden to carry.Watched fail, then pass —
has_childrelabelled supported on the fixedtree:
Reverted, both tests pass again (
2 passed; 0 failed).Known gaps, stated plainly
These are not fixed, and no sentence in this PR should be read as claiming
otherwise:
listed in
COUNT_DOCS— now four files — and nothing else. A new page thatpublishes "XERJ supports N query types" without a marker is unguarded, and no
test will notice. There is no repo-wide scanner for numbers in capability
sentences.
have a phantom denylist (
no_published_surface_names_a_phantom_query_type)and a query-position check; aggregations have neither. The three exemplar
names left in
ROADMAP.md(bucket_script,derivative,moving_fn) aretrue today and checked by nobody.
{"<type>": {}}and reads the error. A type that accepts that body and then does nothing
useful still reads as supported —
typeis mapped tomatch_allandnestedignores
score_mode/inner_hits, both documented under Partial inROADMAP.mdand both counted among the 50.weighted_avgstill returns HTTP 200 with a buried error instead of a 400(tracked in
ROADMAP.md), and the settings count (38/56/60) remains Public claims contradicted by the source: cargo-audit and fuzzing are documented but not in CI #207's.Gate (fourth pass)
Run in this worktree,
CARGO_TARGET_DIR=/home/claude/.cargo-shared-target/shard-2:cargo fmt --all -- --check— cleancargo clippy -p xerj-query -p xerj-engine --all-targets -- -D warnings— cleancargo test -p xerj-query— 173 + 9 passed, 0 failedcargo test -p xerj-engine --lib— 428 passed, 0 failedcargo test -p xerj-engine --test docs_capability_lists— 13 passed, 0 failedcargo test -p xerj-engine— 681 passed, 0 failed across every test binary,then aborts in
painless_script_limitsoncall_depth_limit_survives_the_multi_thread_block_in_place_path, whichoverflows its stack in a debug build. Already recorded on this PR as
reproducing on a stashed tree at
origin/main; it contains no line from thischange. The eight test binaries that sort after it were run individually and
all pass (
perf_benchmark,product_experience,query_string_default_field,rc4_w2_storage_hardening,search_bounded_under_ghosts,search_context_ttl,shard_router_write_path,tombstone_only_segment_search).The ES-YAML conformance suite is not re-run for this pass and does not need to
be: the fourth commit touches
ROADMAP.md,engine/README.md,landing/llms-full.txt, one#[cfg(test)]block inparser.rsand oneintegration-test file. No runtime code path is edited.
Reference-coding: skipped, and the reason is the same one the mandate names
as an exemption — every edit here is either this repository's own prose or a
test that scrapes this repository's own constants. How another engine documents
its query registry is not evidence for what XERJ's
ROADMAP.mdshould sayabout
run_sampler'sshard_size.Fifth pass — re-measured the gate's three findings, and found the #204 bug class inside the guard itself (commit 5)
The gate's three findings, re-measured rather than re-read
The fourth pass claims all three are fixed. Each was re-verified here by
re-introducing the defect on the fixed tree and reading the failure, not by
trusting the commit message:
ROADMAP.md:14"All aggregations are exact (no HLL, no sampling)."grep -rn "no HLL|all aggregations are exact"across*.md *.txt *.html *.rsROADMAP.mdcounts pinned to nothing50→51in the marked regionROADMAP.md:12 publishes 51 for `query-type-count`; the source has 50manifest_labels_match_observed_behaviourcannot see a mislabelled type"has_child"moved fromREJECTED_QUERY_TYPESintoSUPPORTED_QUERY_TYPES`has_child` is listed as supported but refuses with a not-supported message(1 passed; 1 failed, where the gate measured 2 passed)The replacement wording in
ROADMAP.mdwas also checked against the sourcerather than against the previous commit:
aggs.rs:2934dispatchessamplerand
random_samplertorun_sampler;run_samplersorts by_scoreand.take(shard_size)withunwrap_or(200);grep -c probability aggs.rsis0; the
hdrbranch (aggs.rs:7458-7520) really does replicate aDoubleHistogramauto-ranging conversion, so "quantized" is the right word;run_cardinalitycollects aHashSetand returnsdistinct.len(). Thenestedrewrite checks out too —index.rs:29116isarr.iter().any(|elem| doc_matches_query(&inner, elem)),score_modeisparsed at
parser.rs:3139and dropped by theQueryNode::Nested { path, query, .. }destructure at
index.rs:26757, andinner_hitsdoes not occur inparser.rsat all.
What that review turned up: the guard was swallowing unreadable pages
Five sites in
tests/docs_capability_lists.rsdiscarded a read failure, so apage that could not be read was scanned as an empty string — and an empty
string passes every check below it by finding nothing:
The failure mode is a confident wrong answer: "no phantom query type on this
page", for a page that was never read. The
pages.len() > 20andfiles.len() > 20floors do not cover the directory half either — onesubdirectory becoming unreadable drops its pages while sixty others keep the
total above the floor.
Both are hard failures now (
read_dir_or_panic/read_surface_or_panic),each naming the offending path. This matters beyond tidiness: this PR's own
prose claims twice that the guard "must not itself become an accepted-and-ignored
input (#204)", and until this commit that was true of the marker and card
extractors but not of the three site-wide walkers added in the second and third
passes.
Watched fail, then pass — a non-UTF-8
landing/docs/__gate_probe.html:Removed, and
docs_capability_listsis 13/13 again. The rest of the new testcode was scanned for the same pattern (
let _ =,if let Ok(..)with no else,.ok(),unwrap_or_default,flatten()) inseed.rsandparser.rs; thereare no other instances.
Known gaps, restated — nothing here is claimed to be fixed
Unchanged from the fourth pass, and still true:
COUNT_DOCSarechecked, and only markers whose section name is in
COUNT_SECTIONS. A newpage publishing "XERJ supports N query types" without a marker — or with a
mistyped marker name — is unguarded, and no test will notice.
have a phantom denylist and a query-position check; aggregations have
neither. The three exemplar names left in
ROADMAP.md(bucket_script,derivative,moving_fn) are true today and checked by nobody.typeis mapped tomatch_allandnestedignoresscore_mode/inner_hits; both arecounted among the 50 and both are documented under Partial in
ROADMAP.md.weighted_avgstill returns HTTP 200 with a buried error instead of a 400,and the settings count (38 / 56 / 60) remains Public claims contradicted by the source: cargo-audit and fuzzing are documented but not in CI #207's.
ROADMAP.md:11's ES-YAML figure ("1,365 / 1,368") is not touched by thisPR and was not re-measured here. It disagrees with the "1,360 / 1,363"
figure further down the same file. Correcting it needs a conformance run and
belongs to whoever owns that number; it is called out rather than quietly
left.
Gate (fifth pass)
Run in this worktree,
CARGO_TARGET_DIR=/home/claude/.cargo-shared-target/shard-2:cargo fmt --all -- --check— cleancargo clippy -p xerj-query -p xerj-engine -p xerj-console-api --all-targets -- -D warnings— cleancargo test -p xerj-query— 173 + 9 passed, 0 failedcargo test -p xerj-console-api— 108 passed, 0 failedcargo test -p xerj-engine --no-fail-fast— 710 passed, 0 failed acrossevery test binary.
--no-fail-fastis the change from the fourth pass: theeight binaries that sort after
painless_script_limitswere run as part ofthe same invocation rather than individually.
cargo test -p xerj-engine --test docs_capability_lists— 13 passed, 0 failedOne condition still does not pass locally:
painless_script_limits::…abortswith
fatal runtime error: stack overflowin a debug build. This pass stoppedasserting that from memory and measured it —
git checkout origin/main -- engine/in this worktree and re-running that one binary aborts identically, so it
is not from this branch. It also passes in CI's Build + Test on this branch
head.
The ES-YAML conformance suite was not re-run and does not need to be: the only
non-test change anywhere on this branch is three
pub constarrays(
SUPPORTED_QUERY_TYPES,REJECTED_QUERY_TYPES,SUPPORTED_AGG_TYPES) plusBUILTIN_DASHBOARD_COUNT; everything else is#[cfg(test)]code, oneintegration-test file, doc comments, markdown and HTML. CI's own ES-compat YAML
conformance check is green on this branch.
Merge-forward check: the branch is 31 commits behind
origin/main. A trialgit merge --no-commit origin/mainin this worktree merges cleanly, anddocs_capability_lists(13/13) and bothparsermanifest tests stay green onthe merged tree — so
main's drift has not invalidated any published list orcount. The merge was aborted; the branch is not rebased.
Reference-coding: skipped, under the mandate's own exemption — every edit
in this pass is either this repository's prose or a test that reads this
repository's own constants and pages. How another engine documents its query
registry is not evidence about
read_to_string(..).unwrap_or_default()inXERJ's guard.