Skip to content

docs: emit a JSON API manifest from the Doxygen XML (EQL v3) - #364

Merged
coderdan merged 3 commits into
eql_v3from
docs/eql-manifest-generator
Jul 6, 2026
Merged

docs: emit a JSON API manifest from the Doxygen XML (EQL v3)#364
coderdan merged 3 commits into
eql_v3from
docs/eql-manifest-generator

Conversation

@coderdan

@coderdan coderdan commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

Adds a structured eql-manifest.json to the docs pipeline, alongside the existing API.md. Targets eql_v3.

Why

The docs V2 EQL reference is hand-written and drifts from the shipped surface (fabricated function names, stale payload, wrong domain names have all slipped in). This exposes the source of truth as machine-readable data so the docs can be generated and verified against it (docs generation, drift-linting, agents).

What it does

tasks/docs/generate/xml-to-json.py + docs:generate:json builds docs/api/json/eql-manifest.json from two authoritative sources:

1. Functions/operators — from the Doxygen XML, reusing xml-to-markdown.py's process_function (same XML, same SQL-via-Doxygen quirk handling), so the manifest and the Markdown reference can't diverge.

2. Encrypted domains / variant matrix — the core of the v3 surface. Read straight from the Rust catalog via eql-codegen dump-catalog (which already serializes eql_domains::CATALOG to JSON) — not by parsing the generated SQL. So it carries authoritative type tokens (integer/bigint/boolean, confirming the docs' int4/int8/bool are drift) and the exact SQL operators each domain supports (supportedOperators), which is more accurate than deriving from CHECK keys (e.g. _ord correctly reports =/<> too, since ORE collapses to equality). json.sh emits eql-catalog.json and feeds it to the converter — no Rust changes needed; dump-catalog already exists.

Packaged into eql-docs-<tag>.{zip,tar.gz} and generated in release-eql.yml. Additive — the Markdown path is unchanged. test_xml_to_json.py covers both parts.

Sample output (verified against the real v3 source)

{
  "name": "eql", "version": "3.0.0", "generatedFrom": "doxygen-xml + catalog",
  "counts": { "functions": 984, "domains": 48 },
  "functions": [ { "name": "hmac_256", "signature": "hmac_256(jsonb)", "returns": {"type":"text"} } ],
  "domains": [
    { "name": "eql_v3.text_search", "type": "text", "variant": "search", "base": "jsonb",
      "capabilities": ["equality","order","match"],
      "supportedOperators": ["=","<>","<","<=",">",">=","@>","<@"] },
    { "name": "eql_v3.integer_ord", "type": "integer", "variant": "ord",
      "capabilities": ["equality","order"], "supportedOperators": ["=","<>","<","<=",">",">="] },
    { "name": "eql_v3.boolean", "type": "boolean", "variant": "", "capabilities": ["storage"], "supportedOperators": [] }
  ]
}

Follow-ups (not in this PR)

  • Hand-written jsonb domainsjson / jsonb_entry / jsonb_query live in hand-written SQL (not the catalog), so they're not in the 48 catalog domains. A small addition (their own source) can fold them in.
  • The catalog dump could also expose per-domain terms + extractor functions (Term::json_key/extractor/ctor) — a few lines in dump.rs — enriching the manifest further.
  • Payload schemas — the versioned eql-payload-*.schema.json could be referenced from the manifest so the payload reference is generated too.

Consumed by the docs side (generator + drift-lint) — cipherstash/docs#46.

https://claude.ai/code/session_01CqDNqLSEEkCi7xAJFq7HJA

@coderabbitai

coderabbitai Bot commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: b0e33b9b-5879-4a93-b03e-be2563e581d9

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch docs/eql-manifest-generator

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

coderdan added a commit to cipherstash/docs that referenced this pull request Jul 5, 2026
…t to domains

The generated functions.mdx now leads with the encrypted-domain variant matrix
(domain × type × variant → capabilities → index terms), consumed from the
manifest's new `domains` array (cipherstash/encrypt-query-language#364). The
drift-lint now covers domain-type references too, not just function calls.

Running it surfaced a real mismatch worth fixing: the hand-written v3 pages
reference eql_v3.int4_*/int8_*/float4_*/float8_* domains, but the shipped SQL
defines eql_v3.integer_*/bigint_*/real_*/double_* — so casts like
$1::eql_v3.int8_ord would fail. Docs-vs-codegen naming needs reconciling; this
is exactly the drift the lint exists to catch.

Claude-Session: https://claude.ai/code/session_01CqDNqLSEEkCi7xAJFq7HJA
coderdan added 3 commits July 6, 2026 14:15
Adds `docs:generate:json` (tasks/docs/generate/xml-to-json.py), which converts
the Doxygen XML into a structured `eql-manifest.json`, reusing xml-to-markdown's
extraction so the JSON manifest and the Markdown reference never diverge in how
they read the XML. Packaged into the `eql-docs-<tag>` release archives and run
in the release workflow after the Markdown step.

The manifest is a machine-readable API surface (per function: signature, brief,
description, params, returns, throws, notes, source) for downstream consumers —
docs generation, agents, and drift-checking hand-written reference pages against
the shipped EQL version. Additive; the Markdown path and outputs are unchanged.

Includes tasks/docs/generate/test_xml_to_json.py.

Claude-Session: https://claude.ai/code/session_01CqDNqLSEEkCi7xAJFq7HJA
Doxygen doesn't extract CREATE DOMAIN, but the domain variants
(eql_v3.<type>_eq / _ord / _ord_ore / _ord_ope / _match / _search) are the core
of the EQL v3 surface — arguably the most important thing to document.

Parse the generated `src/v3/**/*_types.sql` (source of truth: the Rust catalog
in crates/eql-domains) and derive each domain's capability structurally from its
CHECK keys — hm=equality, ob/op=order, bf=match, sv=json — plus the extractor
function per term (hmac_256 / ore_block_256 / bloom_filter). The manifest now
carries a `domains` array (name, type, variant, base, terms, capabilities,
termFunctions, source) alongside `functions`. No DB or Rust build required.

Verified against the real v3 SQL (51 domains): e.g. text_search →
[equality, order, match], integer_ord → [order], storage-only types → [storage].

Claude-Session: https://claude.ai/code/session_01CqDNqLSEEkCi7xAJFq7HJA
The scalar domains are 100% generated from eql_domains::CATALOG, so read the
domain/variant matrix straight from the source of truth via
`eql-codegen dump-catalog` (which already emits JSON) instead of parsing the
generated *_types.sql. No drift from SQL-format changes, authoritative type
tokens (integer/bigint/…, not int4/int8), and the exact SQL operators each
domain supports (new `supportedOperators` field).

More accurate, too: `_ord` domains now correctly report equality + order —
ORE comparison collapses to equality, so `=`/`<>` are supported — which the
CHECK-key derivation missed.

json.sh emits docs/api/json/eql-catalog.json (cargo run -p eql-codegen
dump-catalog) and passes it to the converter. Covers the 48 catalog (scalar)
domains; the 3 hand-written jsonb domains (json/jsonb_entry/jsonb_query) are
not in the catalog and remain a follow-up.

Claude-Session: https://claude.ai/code/session_01CqDNqLSEEkCi7xAJFq7HJA
@coderdan
coderdan force-pushed the docs/eql-manifest-generator branch from ec03a7b to d09852a Compare July 6, 2026 04:18
coderdan added a commit that referenced this pull request Jul 6, 2026
…ifest

Resolves #365 and #366 — both via the catalog dump, no SQL autogen.

eql_domains::CATALOG (Shape::SteVec), but their SQL is deliberately hand-written
(hand-tuned CHECKs, #354) and `scalar_families()` filters them out of the dump.
Add them as a new **additive** `stevec` field on `CatalogDump` — scalar-only
consumers (the fixture-coverage task) read only `types[]`, so they're
unaffected. The manifest now carries all 51 domains (48 scalar + 3 jsonb).

from eql_domains::Term) to each `DomainEntry`, linking a domain to its extractor
functions (e.g. integer_ord -> eql_v3.ord_term). Authoritative — resolves the
docs drift-lint false-flags on eq_term / ord_term / match_term.

Both fields are additive; all eql-codegen + eql-domains tests pass (89 + 91).
The manifest generator maps them through (termFunctions on scalars; the jsonb
family as `json`-capability domains). Full pipeline verified end-to-end
(doxygen -> XML + dump-catalog -> 984 functions + 51 domains).

Stacked on #364.

Claude-Session: https://claude.ai/code/session_01CqDNqLSEEkCi7xAJFq7HJA
@coderdan
coderdan merged commit f35b335 into eql_v3 Jul 6, 2026
19 checks passed
@coderdan
coderdan deleted the docs/eql-manifest-generator branch July 6, 2026 04:48
coderdan added a commit to cipherstash/docs that referenced this pull request Jul 6, 2026
…-lint

Consumes the eql-manifest.json the EQL repo emits from its Doxygen'd SQL
(cipherstash/encrypt-query-language#364) to:

- generate content/docs/reference/eql/functions.mdx — a version-stamped,
  drift-proof catalog of the eql_v3 function surface that the hand-written
  pedagogical pages link to (added to the EQL nav under "Reference");
- drift-lint the hand-written pages: every `eql_v3.<fn>(...)` they reference
  should exist in the manifest for the shipped EQL version. This is what
  would have caught the fabricated function names / stale payload that slipped
  into the v2 docs.

Wired into prebuild. Reads an illustrative sample fixture today (so the format
and lint are reviewable now); swaps to the real json/eql-manifest.json from the
eql-docs release asset once #364 ships — generate-eql-docs.ts already downloads
that tarball. The lint is report-only against the sample and becomes a failing
gate once wired to the real manifest (STRICT).

Claude-Session: https://claude.ai/code/session_01CqDNqLSEEkCi7xAJFq7HJA
coderdan added a commit to cipherstash/docs that referenced this pull request Jul 6, 2026
…t to domains

The generated functions.mdx now leads with the encrypted-domain variant matrix
(domain × type × variant → capabilities → index terms), consumed from the
manifest's new `domains` array (cipherstash/encrypt-query-language#364). The
drift-lint now covers domain-type references too, not just function calls.

Running it surfaced a real mismatch worth fixing: the hand-written v3 pages
reference eql_v3.int4_*/int8_*/float4_*/float8_* domains, but the shipped SQL
defines eql_v3.integer_*/bigint_*/real_*/double_* — so casts like
$1::eql_v3.int8_ord would fail. Docs-vs-codegen naming needs reconciling; this
is exactly the drift the lint exists to catch.

Claude-Session: https://claude.ai/code/session_01CqDNqLSEEkCi7xAJFq7HJA
coderdan added a commit to cipherstash/docs that referenced this pull request Jul 8, 2026
…-lint

Consumes the eql-manifest.json the EQL repo emits from its Doxygen'd SQL
(cipherstash/encrypt-query-language#364) to:

- generate content/docs/reference/eql/functions.mdx — a version-stamped,
  drift-proof catalog of the eql_v3 function surface that the hand-written
  pedagogical pages link to (added to the EQL nav under "Reference");
- drift-lint the hand-written pages: every `eql_v3.<fn>(...)` they reference
  should exist in the manifest for the shipped EQL version. This is what
  would have caught the fabricated function names / stale payload that slipped
  into the v2 docs.

Wired into prebuild. Reads an illustrative sample fixture today (so the format
and lint are reviewable now); swaps to the real json/eql-manifest.json from the
eql-docs release asset once #364 ships — generate-eql-docs.ts already downloads
that tarball. The lint is report-only against the sample and becomes a failing
gate once wired to the real manifest (STRICT).

Claude-Session: https://claude.ai/code/session_01CqDNqLSEEkCi7xAJFq7HJA
coderdan added a commit to cipherstash/docs that referenced this pull request Jul 8, 2026
…t to domains

The generated functions.mdx now leads with the encrypted-domain variant matrix
(domain × type × variant → capabilities → index terms), consumed from the
manifest's new `domains` array (cipherstash/encrypt-query-language#364). The
drift-lint now covers domain-type references too, not just function calls.

Running it surfaced a real mismatch worth fixing: the hand-written v3 pages
reference eql_v3.int4_*/int8_*/float4_*/float8_* domains, but the shipped SQL
defines eql_v3.integer_*/bigint_*/real_*/double_* — so casts like
$1::eql_v3.int8_ord would fail. Docs-vs-codegen naming needs reconciling; this
is exactly the drift the lint exists to catch.

Claude-Session: https://claude.ai/code/session_01CqDNqLSEEkCi7xAJFq7HJA
coderdan added a commit to cipherstash/docs that referenced this pull request Jul 8, 2026
…-lint

Consumes the eql-manifest.json the EQL repo emits from its Doxygen'd SQL
(cipherstash/encrypt-query-language#364) to:

- generate content/docs/reference/eql/functions.mdx — a version-stamped,
  drift-proof catalog of the eql_v3 function surface that the hand-written
  pedagogical pages link to (added to the EQL nav under "Reference");
- drift-lint the hand-written pages: every `eql_v3.<fn>(...)` they reference
  should exist in the manifest for the shipped EQL version. This is what
  would have caught the fabricated function names / stale payload that slipped
  into the v2 docs.

Wired into prebuild. Reads an illustrative sample fixture today (so the format
and lint are reviewable now); swaps to the real json/eql-manifest.json from the
eql-docs release asset once #364 ships — generate-eql-docs.ts already downloads
that tarball. The lint is report-only against the sample and becomes a failing
gate once wired to the real manifest (STRICT).

Claude-Session: https://claude.ai/code/session_01CqDNqLSEEkCi7xAJFq7HJA
coderdan added a commit to cipherstash/docs that referenced this pull request Jul 8, 2026
…t to domains

The generated functions.mdx now leads with the encrypted-domain variant matrix
(domain × type × variant → capabilities → index terms), consumed from the
manifest's new `domains` array (cipherstash/encrypt-query-language#364). The
drift-lint now covers domain-type references too, not just function calls.

Running it surfaced a real mismatch worth fixing: the hand-written v3 pages
reference eql_v3.int4_*/int8_*/float4_*/float8_* domains, but the shipped SQL
defines eql_v3.integer_*/bigint_*/real_*/double_* — so casts like
$1::eql_v3.int8_ord would fail. Docs-vs-codegen naming needs reconciling; this
is exactly the drift the lint exists to catch.

Claude-Session: https://claude.ai/code/session_01CqDNqLSEEkCi7xAJFq7HJA
coderdan added a commit to cipherstash/docs that referenced this pull request Jul 8, 2026
…-lint

Consumes the eql-manifest.json the EQL repo emits from its Doxygen'd SQL
(cipherstash/encrypt-query-language#364) to:

- generate content/docs/reference/eql/functions.mdx — a version-stamped,
  drift-proof catalog of the eql_v3 function surface that the hand-written
  pedagogical pages link to (added to the EQL nav under "Reference");
- drift-lint the hand-written pages: every `eql_v3.<fn>(...)` they reference
  should exist in the manifest for the shipped EQL version. This is what
  would have caught the fabricated function names / stale payload that slipped
  into the v2 docs.

Wired into prebuild. Reads an illustrative sample fixture today (so the format
and lint are reviewable now); swaps to the real json/eql-manifest.json from the
eql-docs release asset once #364 ships — generate-eql-docs.ts already downloads
that tarball. The lint is report-only against the sample and becomes a failing
gate once wired to the real manifest (STRICT).

Claude-Session: https://claude.ai/code/session_01CqDNqLSEEkCi7xAJFq7HJA
coderdan added a commit to cipherstash/docs that referenced this pull request Jul 8, 2026
…t to domains

The generated functions.mdx now leads with the encrypted-domain variant matrix
(domain × type × variant → capabilities → index terms), consumed from the
manifest's new `domains` array (cipherstash/encrypt-query-language#364). The
drift-lint now covers domain-type references too, not just function calls.

Running it surfaced a real mismatch worth fixing: the hand-written v3 pages
reference eql_v3.int4_*/int8_*/float4_*/float8_* domains, but the shipped SQL
defines eql_v3.integer_*/bigint_*/real_*/double_* — so casts like
$1::eql_v3.int8_ord would fail. Docs-vs-codegen naming needs reconciling; this
is exactly the drift the lint exists to catch.

Claude-Session: https://claude.ai/code/session_01CqDNqLSEEkCi7xAJFq7HJA
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