Conversation
Adds the encrypted-int4 fixture generator and benchmark dataset generation tooling: tasks/fixtures/ and tasks/bench.toml, the tests/benchmarks/ harness, the CipherStash Proxy docker-compose used to encrypt fixture data, the int4 fixture install migration, and bench-data test coverage. Registers the new task files in mise.toml and ignores local mise credential overrides.
Generator no longer shells out to a CipherStash Proxy container to encrypt fixture values. `cipherstash-client` 0.35 is now a direct dependency of the SQLx test crate and the new `fixtures::cipherstash` module owns ZeroKMS bootstrap (cached in a OnceCell), the index-name -> ColumnConfig mapping, and the per-value encrypt helper. The Rust fixture owns configuration and encryption; the DB only owns table structure. Removes: `tests/docker-compose.proxy.yml`, the `proxy:up`/`proxy:logs`/ `proxy:down` mise tasks, the `mise run proxy:up` step from `test:sqlx`, and the `restart_proxy_and_wait` / `insert_through_proxy` / `PROXY_PORT` plumbing in `driver.rs`. The working-table `payload` column is now plain `jsonb` (no `eql_v2_encrypted` composite) and no `add_search_config` rows are written to `eql_v2_configuration` during generation. `mise run test:sqlx` now needs `CS_CLIENT_ACCESS_KEY` (or `CS_CLIENT_ID` + `CS_CLIENT_KEY`) and `CS_WORKSPACE_CRN` in the process env so `AutoStrategy::detect()` / `EnvKeyProvider` can pick them up.
`cipherstash::encrypt_store` now takes a slice and returns a `Vec`, so a fixture run issues one `encrypt_eql` call regardless of value count instead of one per value. The 14-row `eql_v2_int4` fixture drops from 14 ZeroKMS round trips to one; the planned bench fixture (~10k rows) gets the same treatment. Empty input short-circuits before `cipher()` so a caller with nothing to encrypt does not pay the bootstrap cost. `driver::insert_direct` now does one batched encrypt then a per-row INSERT loop — the INSERT is invariant across rows so the SQL string is lifted out of the loop. The working table is local Postgres and the per-row execute cost is in microseconds, so batching the INSERTs is not worth the dynamic-SQL complexity. Test coverage closes the gap flagged in the PR review: - Cheap unit tests (no live ZeroKMS): `index_type_for` mapping for unique/ore/match plus the unknown-name error path; an empty-batch short-circuit test that proves `cipher()` is not reached when there is nothing to encrypt (visible because the test runs without CS_* env vars). - Live tests gated by `fixture-gen` + `#[ignore]`: single-value round trip, batch length + per-payload identifier check, and a distinct-plaintexts → distinct `hm` assertion that mirrors the fixture-tests' equality term check at the unit-test layer.
`test:sqlx` copies `release/cipherstash-encrypt.sql` into `tests/sqlx/migrations/001_install_eql.sql` so the EQL extension is applied to each per-test database. Without an explicit build dep a stale release artifact silently ships an old EQL extension — visible when regression-guard migrations (e.g. 003_install_ste_vec_data.sql) fail on a `_encrypted_check_c` shape the current source has already fixed. Declaring `depends = ["build"]` makes the release artifact fresh on every direct invocation of `test:sqlx`; the top-level `test.sh` already builds, so CI behaviour is unchanged.
The eql_v2_int4 fixture generator encrypts via cipherstash-client, whose EnvKeyProvider requires CS_CLIENT_ID + CS_CLIENT_KEY to load the client key. test:sqlx regenerates fixtures every run, so CI needs that pair — but f8dfd92 only wired CS_CLIENT_ACCESS_KEY + CS_WORKSPACE_CRN (ZeroKMS auth), leaving the generator failing with "CS_CLIENT_ID environment variable not set". Add the client-key pair to the test job env. Also correct comments in mise.toml, tasks/fixtures.toml, Cargo.toml, and FIXTURE_SCHEMA.md that framed the two credential pairs as alternatives: auth (access key + workspace CRN) and key material (client id + key) are distinct roles and both are required.
feat(fixtures): plug-in framework + eql_v2_int4 reference fixture
|
Important Review skippedDraft detected. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
Render eql_v2_<T> jsonb-backed domain families (types, functions, operators, aggregates) from a minimal TOML manifest. Term capabilities are fixed in terms.py (hm -> equality, ore -> equality+ordering); output is byte-identical and headed AUTO-GENERATED — DO NOT EDIT. Hardening: _sql_str() quote-doubler at every SQL interpolation boundary, distinct-fixture-value validation in spec.py, SQL-identifier validation of manifest domain names, and codegen:domain / codegen:domain:all mise tasks. mise run build regenerates all domains every build. Part of PR #239 (eql_v2_int4 variant family).
Four jsonb-backed domains for encrypted int4: storage-only eql_v2_int4 (every operator blocked), eql_v2_int4_eq (hm; =, <>), and the ordered pair eql_v2_int4_ord / eql_v2_int4_ord_ore (ore; = <> < <= > >=). Domain CHECK pins the envelope version (VALUE->>'v' = '2'). Unsupported operators are error-throwing placeholders carrying an explanatory comment. Uniform extractors eql_v2.eq_term/ord_term keep functional indexes engaging without ::jsonb casts. Committed reference baselines guard byte parity. Part of PR #239.
MIN/MAX aggregates on ord-capable int4 domains route comparison through the domain's ORE operators — no decryption. min/max are associative, so the state function doubles as combinefunc; with PARALLEL SAFE sfuncs and parallel = safe, PostgreSQL can use partial/parallel aggregation on the large GROUP BY workloads these aggregates exist to serve. Part of PR #239.
Add blocker_language, blocker_strict, domain_over_domain, and domain_opclass structural lints enforcing the encrypted-domain footguns (blockers must be plpgsql and non-STRICT; no domain-over-domain; no opclass on a domain). pin_search_path recognises the converged extractor/wrapper names intrinsically. Part of PR #239.
…guard One ScalarType impl plus an ordered_numeric_matrix! invocation generates the full SQLx suite for a scalar. Fixture values are single-sourced from the manifest. Coverage includes: - always-on cost-preference proof (~5000 rows, enable_seqscan ON) that asserts on the EXPLAIN node type (Index/Index Only/Bitmap Index Scan), not an index-name substring; eq_count pinned to == 1 so the derived <> count is load-bearing - a live-DB structural guard querying pg_operator that fails if any native jsonb operator is absent from the generator's blocked surface - ORDER BY NULLS FIRST/LAST coverage for ordered domains Part of PR #239.
…angelog Add encrypted-domain implementation spec and generator reference; document both aggregate paths in eql-functions / sql-support; record the int4 family under CHANGELOG Added. CLAUDE.md gains the encrypted-domain materializer guidance and footgun list. Part of PR #239.
Pin third-party actions to commit SHAs, set permissions: contents: read and persist-credentials: false on checkouts, and add a codegen job gating the PG matrix. Part of PR #239.
The jsonb_operator_surface guard queried pg_operator for every operator with a jsonb operand and asserted the set is a subset of the 20 known native jsonb operators. It swept in EQL's own cross-type operators on the legacy eql_v2_encrypted composite (`eql_v2_encrypted ~~ jsonb`, `jsonb ~~ eql_v2_encrypted`) — they take a jsonb operand but are not native and are unreachable from a storage scalar domain — failing CI with ["~~", "~~*"]. Exclude operands typed eql_v2_encrypted so the guard tests only the native jsonb surface a domain can fall through to. The deliberate design is unchanged: int4 has no LIKE, operator_surface.py pins exactly 20 operators and excludes ~~/~~*, and the matrix native_absent_ops arm asserts ~~/~~* parse-error on storage domains. Verified: full encrypted_domain suite 239 passed / 0 failed (was 238/1); operator_surface Python tests 11 passed; no codegen change.
Move the int4 matrix `cargo expand` snapshot and its regeneration tooling into this stacked PR so the main int4 PR (#239) no longer carries the ~37k-line generated snapshot. The snapshot is a body-level fidelity backstop for the `ordered_numeric_matrix!` / `scalar_domain_matrix!` macros — it catches changes *inside* generated test bodies, complementing the name-inventory snapshot (`int4_matrix_tests.txt`, checked in test-eql.yml) that catches add/remove of whole arms. - tests/sqlx/snapshots/int4_expanded.rs — the expanded matrix snapshot - .github/workflows/macro-expand-eql.yml — nightly, non-blocking drift check - mise.toml — the `test:matrix:expand` regeneration task (pinned nightly)
Hardens the non-blocking macro-expand snapshot lane: 1. Pin cargo-expand to 1.0.122 (was unpinned). cargo-expand drives the rustfmt pass, so an unpinned version can drift the snapshot even with a frozen macro + nightly. 2. Single-source the pinned nightly date in mise.toml. The workflow now greps `nightly-YYYY-MM-DD` from mise.toml instead of hardcoding it, so there is nothing to bump in lockstep — the date lives in one place. 3. Don't truncate the snapshot before a possibly-failing expand: the mise task now expands into a mktemp file and `mv`s on success, so a transient expand failure no longer leaves a 0-byte snapshot locally. 4. SHA-pin the third-party actions (checkout, mise-action, rust-cache), reusing the exact SHAs already pinned in test-eql.yml (commit 41c7496). 5. Document the intended body-only-change nightly gap (no pull_request trigger) in the workflow header comment.
…xture! Recovered from orphaned commit 0a60f71 (dropped by a reset during the stacked-PR shuffle). The eql_v2_int4 fixture file was ~95% boilerplate shared with future scalar types: the spec() builder, the fixture-gen generator test, and the property-test module differed only in name, the Rust plaintext type, and the value const. Add a scalar_fixture!(name, ty, values) macro that stamps out all three. MIN/MAX in the signed-extremes test derive from <$ty>. The int2 hunk from the original commit is dropped — int2 is not on this branch. Test-infra only; no caller-observable change. Fixture property tests pass (3/3); generate() still compiles under --features fixture-gen.
cargo fmt --check (tasks/test/lint.sh) flagged scalar_fixture.rs: two assert! lines in the generated property-test arm exceed the line width, so rustfmt wraps them. The file was committed unformatted in 4098c69 and CI lint catches it. Formatting only — the macro expands identically, no behaviour change.
feat: eql_v2_int4 variant family (v3)
Introduce a separate eql_v3 schema for the encrypted-domain type families
and move the int4 family into it, dropping the redundant version prefix:
eql_v3.int4{,_eq,_ord,_ord_ore}, with extractors/wrappers/aggregates
(eql_v3.eq_term, ord_term, eq/neq/lt/lte/gt/gte, min/max) also in eql_v3.
The core index-term types (eql_v2.hmac_256, eql_v2.ore_block_u64_8_256)
stay in eql_v2 and are referenced cross-schema. eql_v2 is unchanged.
- codegen: DOMAIN_SCHEMA/CORE_SCHEMA in templates.py; schema-qualified
domain_name; schema-v3 REQUIRE edges in generate.py
- new src/schema-v3.sql; blocker helper moved to eql_v3
- pin_search_path: pin loop + structural skip broadened to eql_v3
- lints: operator/blocker/domain_over_domain/domain_opclass recognisers
extended to eql_v3
- splinter: scope + eql_v3 allowlist rows
- SQLx harness + family/lint tests + codegen tests + reference baseline
- uninstallers drop eql_v3; docs, CHANGELOG, CLAUDE.md updated
Resolves the open PR #239 review thread asking to move the family to eql_v3.
The generator/test-quality hardening that was previously bundled here
(_sql_str, brief disambiguation, placeholder/aggregate rationale comments,
assert_index_scan_uses) now lands separately on v3-domain-type-int4, since
it is schema-independent and useful to every scalar type.
The int4 domain family moved from eql_v2 to eql_v3, but three generated matrix tests still hardcoded eql_v2. Fixes the CI failures on PG 15/16/17: - scale_default_combos used eql_v2.ord_term as the index extractor, but the ord column is eql_v3.int4_ord (extractor is eql_v3.ord_term). - the aggregate parallel-safety introspection query filtered pg_proc on 'eql_v2'::regnamespace, finding no min/max aggregate (now in eql_v3). Test-only; no production SQL change.
The domain_over_domain and domain_opclass lint messages hard-coded
'eql_v2_*' and recommended eql_v2.eq_term/ord_term. Now that these
lints also target eql_v3 domains, a message firing on an eql_v3 domain
pointed at the wrong surface. Drop the version-specific label
('another encrypted-domain', 'an encrypted-domain type') and build the
extractor recommendation from the offending domain's own schema
(%s.eq_term / %s.ord_term via tn.nspname) so remediation is correct in
either namespace.
Addresses CodeRabbit review feedback on #247.
The feature-gated scale-preference sweep arm asserted plan_text.contains(index) on raw EXPLAIN text, which can false-pass on an incidental mention of the index name. Switch it to the JSON-plan helper assert_index_scan_uses, matching the always-on default-category arm and every other EXPLAIN assertion in the file, so the sweep proves a genuine Index/Index-Only/Bitmap-Index scan node rather than a substring. Addresses CodeRabbit review feedback on #247.
Add the int2 ordered numeric scalar to the generated encrypted-domain
family, stacked on the int4 reference. Four jsonb-backed domains
(eql_v2_int2{,_eq,_ord,_ord_ore}) are generated from the new
tasks/codegen/types/int2.toml manifest by the existing type-generic
materializer — no generator behaviour changes.
- Register the int2 ScalarKind (i16, MIN -32768 / MAX 32767 / zero) in
tasks/codegen/scalars.py, with test_scalars.py coverage.
- Commit the generated fixture-value const
tests/sqlx/src/fixtures/int2_values.rs (single source of truth shared by
the fixture generator and the matrix oracle).
- Wire the SQLx matrix oracle: impl ScalarType for i16, the eql_v2_int2
fixture via the scalar_fixture! macro (mirroring eql_v2_int4), and the
sealed EqlPlaintext impl for i16 (small_int cast, Plaintext::SmallInt,
smallint oracle column).
- Add the ordered_numeric_matrix! invocation and the int2 matrix test-name
inventory snapshot.
- Record the new family in CHANGELOG.md.
Keep the codegen reference int4-only: it is a golden master for the
type-generic generator, so one anchor detects all template/term drift. New
scalar types add no per-type baseline; documented in the spec and
tests/codegen/reference/README.md. int2 is guaranteed by the int4 reference,
the int2_values.rs staleness guard + test_scalars.py, and the SQLx matrix.
The test task hand-listed only eql_v2_int4 for fixture regeneration, so the int2 matrix test's compile-time include_str! of eql_v2_int2.sql failed in CI (fixtures are gitignored and regenerated each run). Add a fixture:generate:all task that enumerates tasks/codegen/types/*.toml — the same manifests codegen:domain:all drives — and regenerates the fixture for every type declaring a [fixture] table, then call it from the test task. New scalar types are now picked up automatically.
feat: move int4 encrypted-domain family into eql_v3 schema
…_domain Also repoint src/lint/lints.sql's REQUIRE from the moved src/schema-v3.sql to src/v3/schema.sql so the combined build's dependency graph still resolves.
…iant (D9, D13) Also add the v3 installer/uninstaller to the build task's MISE outputs list (and tasks/uninstall-v3.sql to sources) so the incremental cache tracks them.
… build The combined-build pin_search_path allowlist is eql_v2-scoped; the self-contained eql_v3 SEM functions (composite/jsonb args) would be pinned, silently breaking v3 functional-index inlining. Mirror the eql_v2 treatment, allowlist them in splinter, and add a direct regression guard.
… eql_v3 SEM fork The ord_term extractor now returns eql_v3.ore_block_u64_8_256 (D12), so the CREATE-OR-REPLACE mutation redefinitions must declare the eql_v3 return type and construct eql_v3 SEM terms; the eq-reroute mutations move to eql_v3 SEM too. The drop_operator_classes fixture now also drops the new eql_v3 ORE btree opclass, which the Supabase build's **/*operator_class.sql glob likewise excludes.
…, fix blocker doc path Hoist the src/v3 path strings into named constants in generate.rs (byte-identical output — parity holds). Remove the now-dead Term::returns() (codegen builds the extractor return type from CORE_SCHEMA + ctor) and its legacy eql_v2 test assertions. Repoint the shared blocker's doc comment to src/v3/scalars/<T>/.
The eql_v3 SEM index-term functions are a hand-port of the eql_v2 originals. The scalar matrix already exercises the array comparator's happy path end-to-end against real ciphertext fixtures, but several branches are structurally unreachable there and were tested only on the eql_v2 copies. Add a sibling family test module covering them: - differential v2<->v3 parity on real `ob` fixtures (both sides routed through extractor -> composite -> compare_..._terms, so the schema prefix is the only variable) — the strongest guard against a faithful-port slip; - the 'Ciphertexts are different lengths' RAISE; - NULL-term ordering branches the STRICT wrappers bypass; - array NULL + empty/cardinality recursion base cases; - has_* presence checks, the missing-`ob` RAISE, and the NULL-jsonb short-circuit. Verified non-vacuous: a deliberately broken comparator fails T1/T2/T3 while the independent T4/T5 stay green.
…entity names Addresses CodeRabbit review: the artifact/test self-containment assertions only matched schema-qualified eql_v2. references; extend them to also reject eql_v2_<entity> names (eql_v2_encrypted, eql_v2_configuration) while still allowing prose mentions of eql_v2 in doc comments. Verified the v3 artifact and src/v3 contain zero eql_v2_ occurrences.
…e SCHEMA
With eql_v3 fully self-contained, the encrypted-domain families and the SEM
index-term types they call live in one schema, so there is no second schema to
point the core types at. Replace the CORE_SCHEMA/DOMAIN_SCHEMA pair with one
SCHEMA = "eql_v3" constant; the templates read it via the {{ schema }} global.
Output is byte-identical (golden parity holds).
…ardening - Cargo.toml: update stale fixture command to fixture:generate:all - eql-functions.md: index examples use distinct _eq/_ord columns (a column carries a single domain, so eq_term/ord_term apply to different columns) - scalars/mod.rs: header describes the scalar_types!(matrix_suites) layout - codegen-parity.sh: ls *.sql -> portable find (no set -e abort on empty dir) - inlinability.rs: narrow arity-1 hmac_256 match to the jsonb overload
…ators The six comparison operator backing functions (_eq, _neq, _lt, _lte, _gt, _gte) were missing required @param and @return Doxygen tags, failing docs:validate:required-tags with 6 errors and 6 warnings. Tags follow the eql_v2 sibling src/ore_block_u64_8_256/operators.sql convention.
cargo fmt --check was failing CI (test:lint and test:crates jobs) on this file; apply rustfmt with no logic changes.
…t consts Make the SQLx scalar-matrix harness type-agnostic ahead of the first non-integer scalar, without adding one. Three integer assumptions are lifted: - `ScalarType::FIXTURE_VALUES` (a `const`) becomes `fn fixture_values()`, so a scalar whose values can't be const-constructed can return a borrow of a lazily-built `Vec` instead. Integer impls still hand back their `eql_scalars::<T>_VALUES` const. - New `min_pivot()` / `max_pivot()` trait methods replace the matrix's direct `<T>::MIN` / `<T>::MAX` pivot references, so a scalar without an inherent `::MIN`/`::MAX` const can supply an explicit sentinel. - The ORDER BY arms build their `WHERE` clause from `to_sql_literal(zero)` instead of a hardcoded `> 0`, so a non-integer plaintext column typechecks. Behaviour-preserving for the existing `int4` / `int2` types: the integer `min_pivot`/`max_pivot` resolve to `Self::MIN`/`Self::MAX`, `to_sql_literal(0)` renders `0`, and the generated test names are unchanged. The int4 cargo-expand snapshot is regenerated to track the method-based bodies.
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
- scalar_domains.rs: document fixture_values() stable-order contract (callers compare element-wise and index positionally without sorting) - eql-tests-macros: assert emitted min_pivot/max_pivot bodies instead of loose MIN/MAX substrings that also match the doc comment 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
feat(int8): add eql_v3.int8 encrypted-domain type family
…test hardening Collates and resolves code-review feedback on the self-contained eql_v3 PR. Inlinable SEM helpers (coderdan threads): - Convert eql_v3.jsonb_array_to_bytea_array and eql_v3.jsonb_array_to_ore_block_u64_8_256 from LANGUAGE plpgsql to inlinable LANGUAGE sql IMMUTABLE (no SET), using a CASE-scalar-subquery form so JSON-null/empty-array inputs still return NULL rather than raising (a naive FROM-SRF + WHERE rewrite would regress null to error). - These take a bare jsonb (not a domain), so pin_search_path.sql's structural skip does not cover them; opt them in via its documented 'eql-inline-critical' COMMENT marker so they install unpinned and the planner can inline them. Add matching splinter allowlist rows. The eql_v2 copies stay plpgsql by design. Direct SEM tests added (sem.rs). Stale references: - eql-functions.md / sql-support.md: v3 extractors now document eql_v3 SEM return types, not eql_v2. - pin_search_path.sql header, scalar_types.rs and mutations.rs comments. Test/build hardening: - writer.rs validates the AUTO-GENERATED ownership header before writing. - eql-scalars int_values! fails at compile time on narrowed-fixture overflow. - parity.rs asserts the generated file set, not just per-file contents. - mise.toml: shared test:sqlx:prep so test:sqlx:watch gets the same prep. - build.sh v3-only build rejects REQUIRE edges outside src/v3. - fixtures: single-source PAYLOAD_COLUMN const; enforce 63-byte identifier limit. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Self-contained eql_v3 schema + standalone v3 installer
refactor(tests): generalise scalar matrix harness off integer-inherent consts
Add the `eql_v3.date` encrypted-domain scalar — the first non-integer ordered type — on top of the integer-agnostic harness refactor (parent PR). The SQL codegen needs no change (domains are jsonb-backed and token-driven); the work is one catalog row plus the temporal wiring the refactor enabled. Catalog (`eql-scalars`): `ScalarKind::Date` (`chrono::NaiveDate`), `Fixture::Date(&str)` (zero-dep ISO strings), `DATE_FIXTURES` (16 dates incl. the three matrix pivots), and `pub const DATE` appended to `CATALOG`, with mirrored panic / pivot-presence / token-order tests. Harness: an explicit `[temporal]` marker in the `scalar_types!` dispatch list drives the divergences from the integer path — the `impl ScalarType` for a temporal scalar is hand-written (chrono values can't be a `const` slice; pivots are explicit sentinels), and `scalar_fixture!` stamps a pivot-presence assert instead of the integer signed-extreme asserts. Adds `impl ScalarType for NaiveDate` (LazyLock-parsed values, `min_pivot`/`max_pivot` sentinels, quoted `to_sql_literal`), `EqlPlaintext for NaiveDate` (Cast::DATE), the sqlx `chrono` feature + direct `chrono` dep, the CHANGELOG entry, and a temporal-kinds note in the adding-a-scalar reference.
feat(scalars): add eql_v3.date encrypted-domain type + temporal wiring
… reference CATALOG now includes the non-integer ordered scalar (date) alongside the integers, so the 'only the integer scalars today' wording was stale. Addresses CodeRabbit feedback on PR #256.
ScalarKind loses the five partial accessors that panicked on non-integer kinds; bounds now live on the total BoundedIntKind, reached via ScalarKind::as_bounded_int(). Date::min_symbol() is now a compile error. A CATALOG invariant test replaces the deleted #[should_panic] tests.
Update the adding-a-scalar reference's `kind` bullet to reflect that the bounded-numeric accessors moved to the total BoundedIntKind sub-enum, and add the implementation plan under docs/superpowers/plans/.
refactor(eql-scalars): total BoundedIntKind sub-enum (replaces panicking ScalarKind accessors)
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.
THIS IS THE EQL_V3 STACK.
VERY WIP.