diff --git a/.changeset/manifest-extraction-fixes.md b/.changeset/manifest-extraction-fixes.md deleted file mode 100644 index 2b61356b..00000000 --- a/.changeset/manifest-extraction-fixes.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -'@cipherstash/eql': patch ---- - -**The generated API reference was missing `eql_v3.grouped_value` and `eql_v3.lints()` entirely, and described `public.eql_v3_text_match` as storage-only.** Four extraction bugs, all silent — each one dropped or misdescribed a symbol without failing the docs build. - -- **`@example` deleted the symbol it documented.** Doxygen's `\example` takes a *filename*; used as an inline snippet marker it pulled the block out of the member's documentation. The two symbols in the tree that used it were the two missing from the manifest — `eql_v3.grouped_value` lost its whole memberdef, `eql_v3.lints()` was left with an empty description and dropped by the no-documentation guard. Both now use `@code{.sql}` / `@endcode`. -- **`CREATE AGGREGATE` bodies broke the C++ parse.** The trailing `(sfunc = …, stype = …)` is a second parenthesised group, which C++ has no form for, so Doxygen misread the declaration: with a bare argument type it named the member after the *type* (`grouped_value(jsonb)` was extracted as a function called `jsonb`), and with a schema-qualified one it truncated the argument list mid-body. The input filter now strips aggregate bodies, as it already did for dollar-quoted function bodies, and the extractor reads an aggregate's argument types from its declaration and its return type from `@return`. `min`/`max` signatures are now schema-qualified (`min(public.eql_v3_bigint_ord)`, previously `min(eql_v3_bigint_ord)`) and no longer report a parameter named `public.` or a return type of `CREATE AGGREGATE eql_v3`. -- **The `match` capability was computed from the pre-3.0.1 operator spelling.** Fuzzy match became `@@` in 3.0.1, but the manifest still tested `@>` / `<@`, so no domain could be assigned `match` at all: `public.eql_v3_text_match` matched no branch and fell through to the storage-only default, and `text_search` silently lost `match`. Containment on encrypted JSON keeps `@>` / `<@` and is now reported as its own `containment` capability rather than conflated with fuzzy match. -- **`public.eql_v3_json` was in no list at all.** The catalog dump filtered the json family's bare storage domain out of `stevec` as scalar, while `types` iterates `scalar_families()`, which excludes the mixed json family wholesale — so the domain the SQL materializer creates appeared in neither, and never reached the manifest. It is now carried in the json-family inventory with a `scalar` flag, so consumers do not describe it with the SteVec query surface. - -Why: the manifest is the machine-readable contract the documentation and downstream agents build against, and every one of these failed open — a missing symbol or a wrong capability reads exactly like a symbol that does not exist or a domain that cannot be searched. diff --git a/Cargo.lock b/Cargo.lock index 05c54b0f..cc569499 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1131,7 +1131,7 @@ dependencies = [ [[package]] name = "eql-bindings" -version = "3.0.3" +version = "3.0.4" dependencies = [ "eql-domains", "schemars", diff --git a/crates/eql-bindings/Cargo.toml b/crates/eql-bindings/Cargo.toml index 1f491e52..83cf589f 100644 --- a/crates/eql-bindings/Cargo.toml +++ b/crates/eql-bindings/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "eql-bindings" -version = "3.0.3" +version = "3.0.4" edition = "2021" description = "Canonical wire types for EQL payloads — single source of truth for Rust, TypeScript (ts-rs), and JSON Schema (schemars)." # crates.io metadata. `license` is REQUIRED by crates.io — publish fails without diff --git a/crates/eql-bindings/sql/cipherstash-encrypt.sql b/crates/eql-bindings/sql/cipherstash-encrypt.sql index 6800c401..881e063a 100644 --- a/crates/eql-bindings/sql/cipherstash-encrypt.sql +++ b/crates/eql-bindings/sql/cipherstash-encrypt.sql @@ -183,15 +183,17 @@ $$; --! encryption of the same plaintext, so any one represents the group) and it --! matches the eql_v2 original. --! ---! @example ---! -- Group encrypted rows by encrypted equality and project the encrypted ---! -- column. GROUP BY eql_v3.eq_term(...) groups by the HMAC equality term; ---! -- grouped_value(...) returns a representative ciphertext for each group so ---! -- PostgreSQL does not reject the bare column reference. +--! Group encrypted rows by encrypted equality and project the encrypted +--! column. GROUP BY eql_v3.eq_term(...) groups by the HMAC equality term; +--! grouped_value(...) returns a representative ciphertext for each group so +--! PostgreSQL does not reject the bare column reference. +--! +--! @code{.sql} --! SELECT eql_v3.grouped_value(encrypted_foo) AS encrypted_foo, --! count(*) --! FROM some_table --! GROUP BY eql_v3.eq_term(encrypted_foo); +--! @endcode --! --! @see eql_v3_internal.grouped_value_sfunc --! @see eql_v3.eq_term @@ -670,13 +672,12 @@ CREATE CAST (public.eql_v3_json_search AS eql_v3.query_json) --! type picker, which the schema split exists to --! prevent. Move it to `eql_v3_internal`. --! ---! @example ---! ``` +--! @code{.sql} --! SELECT severity, category, object_name, message --! FROM eql_v3.lints() --! WHERE severity = 'error' --! ORDER BY category, object_name; ---! ``` +--! @endcode --! --! @return SETOF record (severity text, category text, object_name text, message text) CREATE OR REPLACE FUNCTION eql_v3.lints() @@ -59436,7 +59437,7 @@ DROP FUNCTION IF EXISTS eql_v3.version(); --! @brief EQL version reporting (self-contained eql_v3 surface) --! --! This file is auto-generated from src/v3/version.template during build. ---! The 3.0.3 placeholder is replaced with the actual release +--! The 3.0.4 placeholder is replaced with the actual release --! version (bare semver, e.g. "3.0.0") supplied via `mise run build --version`, --! or "DEV" for development builds. @@ -59455,14 +59456,14 @@ CREATE FUNCTION eql_v3.version() RETURNS text IMMUTABLE STRICT PARALLEL SAFE AS $$ - SELECT '3.0.3'; + SELECT '3.0.4'; $$ LANGUAGE SQL; --! @brief Schema-level version marker for obj_description() discoverability --! --! Mirrors eql_v3.version() as a comment on the schema so the installed --! version can also be read via obj_description('eql_v3'::regnamespace). -COMMENT ON SCHEMA eql_v3 IS '3.0.3'; +COMMENT ON SCHEMA eql_v3 IS '3.0.4'; --! @file pin_search_path_v3.sql --! @brief Post-install: pin search_path on every eql_v3.* function. --! diff --git a/crates/eql-bindings/sql/release-manifest.json b/crates/eql-bindings/sql/release-manifest.json index 334b2f8f..a4e030c8 100644 --- a/crates/eql-bindings/sql/release-manifest.json +++ b/crates/eql-bindings/sql/release-manifest.json @@ -1,6 +1,6 @@ { - "eqlVersion": "3.0.3", + "eqlVersion": "3.0.4", "schemaVersion": 3, - "installSqlSha256": "257de54a63465c5668264002f24992e9b71b903a32d38a28f0ee67855fddf2a8", + "installSqlSha256": "63104a81aac0aebd59fac3765cbe92c3364a7ecbb0bce99e53fbe518d30a0641", "uninstallSqlSha256": "b1b5131b8175c5d04da9ada108d25c81c5772b15fad79a6c419ebb32d18c60a9" } diff --git a/packages/eql/CHANGELOG.md b/packages/eql/CHANGELOG.md index 78f90972..d78abe30 100644 --- a/packages/eql/CHANGELOG.md +++ b/packages/eql/CHANGELOG.md @@ -1,5 +1,18 @@ # @cipherstash/eql +## 3.0.4 + +### Patch Changes + +- c8ee10f: **The generated API reference was missing `eql_v3.grouped_value` and `eql_v3.lints()` entirely, and described `public.eql_v3_text_match` as storage-only.** Four extraction bugs, all silent — each one dropped or misdescribed a symbol without failing the docs build. + + - **`@example` deleted the symbol it documented.** Doxygen's `\example` takes a _filename_; used as an inline snippet marker it pulled the block out of the member's documentation. The two symbols in the tree that used it were the two missing from the manifest — `eql_v3.grouped_value` lost its whole memberdef, `eql_v3.lints()` was left with an empty description and dropped by the no-documentation guard. Both now use `@code{.sql}` / `@endcode`. + - **`CREATE AGGREGATE` bodies broke the C++ parse.** The trailing `(sfunc = …, stype = …)` is a second parenthesised group, which C++ has no form for, so Doxygen misread the declaration: with a bare argument type it named the member after the _type_ (`grouped_value(jsonb)` was extracted as a function called `jsonb`), and with a schema-qualified one it truncated the argument list mid-body. The input filter now strips aggregate bodies, as it already did for dollar-quoted function bodies, and the extractor reads an aggregate's argument types from its declaration and its return type from `@return`. `min`/`max` signatures are now schema-qualified (`min(public.eql_v3_bigint_ord)`, previously `min(eql_v3_bigint_ord)`) and no longer report a parameter named `public.` or a return type of `CREATE AGGREGATE eql_v3`. + - **The `match` capability was computed from the pre-3.0.1 operator spelling.** Fuzzy match became `@@` in 3.0.1, but the manifest still tested `@>` / `<@`, so no domain could be assigned `match` at all: `public.eql_v3_text_match` matched no branch and fell through to the storage-only default, and `text_search` silently lost `match`. Containment on encrypted JSON keeps `@>` / `<@` and is now reported as its own `containment` capability rather than conflated with fuzzy match. + - **`public.eql_v3_json` was in no list at all.** The catalog dump filtered the json family's bare storage domain out of `stevec` as scalar, while `types` iterates `scalar_families()`, which excludes the mixed json family wholesale — so the domain the SQL materializer creates appeared in neither, and never reached the manifest. It is now carried in the json-family inventory with a `scalar` flag, so consumers do not describe it with the SteVec query surface. + + Why: the manifest is the machine-readable contract the documentation and downstream agents build against, and every one of these failed open — a missing symbol or a wrong capability reads exactly like a symbol that does not exist or a domain that cannot be searched. + ## 3.0.3 ### Patch Changes diff --git a/packages/eql/package.json b/packages/eql/package.json index 4cb518f8..07eed476 100644 --- a/packages/eql/package.json +++ b/packages/eql/package.json @@ -1,6 +1,6 @@ { "name": "@cipherstash/eql", - "version": "3.0.3", + "version": "3.0.4", "description": "Canonical EQL v3 wire types, JSON schemas, and SQL bundle.", "keywords": [ "eql", diff --git a/packages/eql/sql/cipherstash-encrypt.sql b/packages/eql/sql/cipherstash-encrypt.sql index 6800c401..881e063a 100644 --- a/packages/eql/sql/cipherstash-encrypt.sql +++ b/packages/eql/sql/cipherstash-encrypt.sql @@ -183,15 +183,17 @@ $$; --! encryption of the same plaintext, so any one represents the group) and it --! matches the eql_v2 original. --! ---! @example ---! -- Group encrypted rows by encrypted equality and project the encrypted ---! -- column. GROUP BY eql_v3.eq_term(...) groups by the HMAC equality term; ---! -- grouped_value(...) returns a representative ciphertext for each group so ---! -- PostgreSQL does not reject the bare column reference. +--! Group encrypted rows by encrypted equality and project the encrypted +--! column. GROUP BY eql_v3.eq_term(...) groups by the HMAC equality term; +--! grouped_value(...) returns a representative ciphertext for each group so +--! PostgreSQL does not reject the bare column reference. +--! +--! @code{.sql} --! SELECT eql_v3.grouped_value(encrypted_foo) AS encrypted_foo, --! count(*) --! FROM some_table --! GROUP BY eql_v3.eq_term(encrypted_foo); +--! @endcode --! --! @see eql_v3_internal.grouped_value_sfunc --! @see eql_v3.eq_term @@ -670,13 +672,12 @@ CREATE CAST (public.eql_v3_json_search AS eql_v3.query_json) --! type picker, which the schema split exists to --! prevent. Move it to `eql_v3_internal`. --! ---! @example ---! ``` +--! @code{.sql} --! SELECT severity, category, object_name, message --! FROM eql_v3.lints() --! WHERE severity = 'error' --! ORDER BY category, object_name; ---! ``` +--! @endcode --! --! @return SETOF record (severity text, category text, object_name text, message text) CREATE OR REPLACE FUNCTION eql_v3.lints() @@ -59436,7 +59437,7 @@ DROP FUNCTION IF EXISTS eql_v3.version(); --! @brief EQL version reporting (self-contained eql_v3 surface) --! --! This file is auto-generated from src/v3/version.template during build. ---! The 3.0.3 placeholder is replaced with the actual release +--! The 3.0.4 placeholder is replaced with the actual release --! version (bare semver, e.g. "3.0.0") supplied via `mise run build --version`, --! or "DEV" for development builds. @@ -59455,14 +59456,14 @@ CREATE FUNCTION eql_v3.version() RETURNS text IMMUTABLE STRICT PARALLEL SAFE AS $$ - SELECT '3.0.3'; + SELECT '3.0.4'; $$ LANGUAGE SQL; --! @brief Schema-level version marker for obj_description() discoverability --! --! Mirrors eql_v3.version() as a comment on the schema so the installed --! version can also be read via obj_description('eql_v3'::regnamespace). -COMMENT ON SCHEMA eql_v3 IS '3.0.3'; +COMMENT ON SCHEMA eql_v3 IS '3.0.4'; --! @file pin_search_path_v3.sql --! @brief Post-install: pin search_path on every eql_v3.* function. --! diff --git a/packages/eql/sql/release-manifest.json b/packages/eql/sql/release-manifest.json index 334b2f8f..a4e030c8 100644 --- a/packages/eql/sql/release-manifest.json +++ b/packages/eql/sql/release-manifest.json @@ -1,6 +1,6 @@ { - "eqlVersion": "3.0.3", + "eqlVersion": "3.0.4", "schemaVersion": 3, - "installSqlSha256": "257de54a63465c5668264002f24992e9b71b903a32d38a28f0ee67855fddf2a8", + "installSqlSha256": "63104a81aac0aebd59fac3765cbe92c3364a7ecbb0bce99e53fbe518d30a0641", "uninstallSqlSha256": "b1b5131b8175c5d04da9ada108d25c81c5772b15fad79a6c419ebb32d18c60a9" } diff --git a/packages/eql/src/generated/release-manifest.ts b/packages/eql/src/generated/release-manifest.ts index 8ddd9956..e9c53eb0 100644 --- a/packages/eql/src/generated/release-manifest.ts +++ b/packages/eql/src/generated/release-manifest.ts @@ -1,6 +1,6 @@ export const releaseManifest = { - eqlVersion: '3.0.3', + eqlVersion: '3.0.4', schemaVersion: 3, - installSqlSha256: '257de54a63465c5668264002f24992e9b71b903a32d38a28f0ee67855fddf2a8', + installSqlSha256: '63104a81aac0aebd59fac3765cbe92c3364a7ecbb0bce99e53fbe518d30a0641', uninstallSqlSha256: 'b1b5131b8175c5d04da9ada108d25c81c5772b15fad79a6c419ebb32d18c60a9', } as const