feat(cli): add the stash-indexing skill — indexing EQL v3 encrypted columns#773
Conversation
…olumns Closes #753. Integrations that were otherwise correct shipped with zero indexes on encrypted predicates: nothing in the installed skills said encrypted columns *can* be indexed, and the ORE-superuser warning was being over-generalized into "you can't index encrypted columns on Supabase." The new skill condenses the EQL repo's database-indexes reference (byte-identical between main and the eql-bindings-v3.0.2 tag — exactly the @cipherstash/eql version stash ships; all extractor functions verified present in the bundled SQL): - functional-index recipes (eq_term / ord_term / ord_term_ore / match_term / to_ste_vec_query) mapped to the types.* domains - what needs superuser (only the ORE opclass) vs what works on Supabase/managed Postgres, incl. the record_ops silent-failure check - which domains are storage-only by design - engagement requirements, the ORDER BY sort-key and GROUP BY traps - build-at-scale guidance and the EXPLAIN checklist - per-integration DDL placement (no ORM emits index DDL) and rollout timing (after backfill, before switching reads) Wiring: installed for every integration by both the CLI handoffs (SKILL_MAP + BASE_SKILLS) and the wizard's skills prompt; cross-links added from the encryption/cli/drizzle/supabase/prisma-next skills. Also fixes the missing stash-prisma-next SKILL_PURPOSES entry (rendered "(no description)" in the setup prompt) and adds a test guarding every installable skill against that gap. Claude-Session: https://claude.ai/code/session_01BkEpKJC3975NHsKgMrCT8R
🦋 Changeset detectedLatest commit: a4a78db The changes in this PR will be included in the next version bump. This PR includes changesets to release 11 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughAdds the ChangesEQL v3 indexing and skill delivery
Estimated code review effort: 3 (Moderate) | ~25 minutes Sequence Diagram(s)sequenceDiagram
participant PgTable
participant encryptedIndexes
participant EqlV3Column
participant IndexBuilders
PgTable->>encryptedIndexes: provide encrypted columns
encryptedIndexes->>EqlV3Column: read capability metadata
EqlV3Column-->>encryptedIndexes: return supported index domains
encryptedIndexes->>IndexBuilders: build extractor-based indexes
IndexBuilders-->>PgTable: return configured indexes
Possibly related issues
Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 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 |
There was a problem hiding this comment.
Actionable comments posted: 6
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@skills/stash-encryption/SKILL.md`:
- Line 863: Remove the blank line within the blockquote in SKILL.md, keeping
consecutive blockquote lines continuous so Markdownlint rule MD028 passes.
- Around line 862-863: Update the functional-index rollout note in the stash
encryption cutover section to explicitly apply the index-creation step only to
EQL v3 columns, using the existing stash-indexing recipes. Add a clear v2 path
stating that no equivalent functional indexes are required or available, so v2
readers do not follow the v3 instructions.
In `@skills/stash-indexing/SKILL.md`:
- Around line 72-74: Update the copy-paste SQL recipes in SKILL.md, including
the ORE and JSON field-ordering examples, to include the required ANALYZE
statement after index creation. Ensure every recipe matches the documented
requirement that ANALYZE is mandatory; do not weaken that requirement.
- Around line 105-119: Make each published skill self-contained: in
skills/stash-indexing/SKILL.md lines 105-119, retain the field-ordering guidance
and explicitly explain how to derive or obtain the deterministic JSON selector;
in skills/stash-drizzle/SKILL.md lines 82-83, add a minimal Drizzle custom-SQL
CREATE INDEX example; in skills/stash-prisma-next/SKILL.md lines 146-150, add a
minimal Prisma Next migration example; and in skills/stash-supabase/SKILL.md
lines 77-82, add a minimal Supabase migration example, ensuring each site
includes the minimum actionable details without relying on sibling skills.
- Line 8: Revise the headline rule in SKILL.md to apply only to encrypted
domains that carry searchable terms. Explicitly exclude storage-only domains,
which have no term extractor and must not receive indexes, while preserving the
existing guidance to index a functional expression over the term extractor
rather than the encrypted column itself.
- Around line 22-32: Clarify the schematic factory notation in the capability
table: change generic rows to use forms such as types.<T>Eq, types.<T>Ord, and
types.<T>OrdOre, and add concrete v3 examples including types.TextEq,
types.IntegerOrd, and types.TimestampOrdOre. Preserve the existing domain, term,
and index-recipe descriptions.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: a0c4423b-e507-4d61-8de9-9c8b6e9be9b2
📒 Files selected for processing (16)
.changeset/stash-indexing-skill.mdAGENTS.mdpackages/cli/src/commands/init/doctrine/AGENTS-doctrine.mdpackages/cli/src/commands/init/lib/__tests__/build-agents-md.test.tspackages/cli/src/commands/init/lib/__tests__/install-skills.test.tspackages/cli/src/commands/init/lib/__tests__/setup-prompt.test.tspackages/cli/src/commands/init/lib/install-skills.tspackages/cli/src/commands/init/lib/setup-prompt.tspackages/wizard/src/__tests__/install-skills.test.tspackages/wizard/src/lib/install-skills.tsskills/stash-cli/SKILL.mdskills/stash-drizzle/SKILL.mdskills/stash-encryption/SKILL.mdskills/stash-indexing/SKILL.mdskills/stash-prisma-next/SKILL.mdskills/stash-supabase/SKILL.md
Review: "no ORM integration emits this DDL" was underspecified for
Drizzle — its DSL supports expression indexes
(index().using('btree', sql`eql_v3.eq_term(...)`)), so the primary
vehicle is the table definition tracked by drizzle-kit generate, not a
custom-SQL migration. Prisma stays migration-only (its schema language
cannot express functional indexes — upstream limitation); the Supabase
wrapper owns no schema at all. The per-integration section now says so.
Claude-Session: https://claude.ai/code/session_01BkEpKJC3975NHsKgMrCT8R
Review direction on #773: keep stash-indexing general-purpose, move the how-to-apply-it material into each ORM skill, and give Drizzle real API support. The helper (`encryptedIndexes` on the /v3 entry): spread `...encryptedIndexes(t)` in pgTable's extras callback and it derives the functional indexes for every encrypted column from the same per-domain capability record the operator layer gates on — so the emitted indexes and the operators that engage them cannot drift. Named `<table>_<column>_<capability>`, tracked by drizzle-kit generate. Building it surfaced two things: - drizzle-orm ≤0.45's ExtraConfigColumn.getSQLType() recurses into itself (upstream bug), so isEqlV3Column/getEqlV3Column blew the stack on any extras-callback column. getSqlType now recovers the domain from the column's custom-type params instead. - The shipped EQL 3.0.2 bundle has NO eq_term overload for the _ord / _ord_ore domains — eql_v3.eq on them inlines to an ordering-term comparison, so ONE ordering btree serves = and range alike. The stash-indexing capability table and equality recipe followed the EQL doc's overstated claim; both now match the shipped SQL (and the skill explicitly warns against adding an eq_term index to an _ord column). Skills: stash-indexing's per-integration section is now a general pointer list; stash-drizzle gains an Indexing Encrypted Columns section (helper first, manual expression-index DSL second); stash-supabase and stash-prisma-next gain concrete sections with the per-domain DDL. Claude-Session: https://claude.ai/code/session_01BkEpKJC3975NHsKgMrCT8R
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
packages/stack-drizzle/__tests__/v3/indexes.test.ts (1)
9-9: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winExercise
encryptedIndexesthrough the v3 barrel.This imports an internal module instead of the supported
/v3surface. Import from../../src/v3/indexso the behavior test covers the public API.Proposed change
-import { encryptedIndexes } from '../../src/v3/indexes' +import { encryptedIndexes } from '../../src/v3/index'🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/stack-drizzle/__tests__/v3/indexes.test.ts` at line 9, Update the encryptedIndexes import in the v3 indexes tests to use the supported v3 barrel entry at ../../src/v3/index instead of the internal indexes module, so the behavior test exercises the public API.Source: Coding guidelines
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@skills/stash-drizzle/SKILL.md`:
- Around line 395-405: Update the index mapping table to use public v3 factory
names instead of internal type symbols: replace types.TEq with types.TextEq,
types.TOrd with representative types.TextOrd/ types.IntegerOrd, types.TOrdOre
with types.TextOrdOre, and bare types.T with types.Text. Preserve the existing
index mappings and the types.Boolean entry.
---
Nitpick comments:
In `@packages/stack-drizzle/__tests__/v3/indexes.test.ts`:
- Line 9: Update the encryptedIndexes import in the v3 indexes tests to use the
supported v3 barrel entry at ../../src/v3/index instead of the internal indexes
module, so the behavior test exercises the public API.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: d3de5631-89d5-45b9-ba15-117b9adc2b58
📒 Files selected for processing (10)
.changeset/drizzle-encrypted-indexes.mdpackages/stack-drizzle/__tests__/v3/exports.test.tspackages/stack-drizzle/__tests__/v3/indexes.test.tspackages/stack-drizzle/src/v3/column.tspackages/stack-drizzle/src/v3/index.tspackages/stack-drizzle/src/v3/indexes.tsskills/stash-drizzle/SKILL.mdskills/stash-indexing/SKILL.mdskills/stash-prisma-next/SKILL.mdskills/stash-supabase/SKILL.md
🚧 Files skipped from review as they are similar to previous changes (1)
- skills/stash-indexing/SKILL.md
Review: the _ord equality story splits on term injectivity, not on _ord itself. Numeric/date/timestamp ordering terms (OPE and ORE) are injective, so those domains carry no hm, have no eq_term overload, and one ordering btree serves = and range. TEXT ordering terms are non-injective and cannot be relied on for equality, so text_ord / text_ord_ore also carry hm and answer = via eq_term — those columns get an eq_term index alongside the ordering one. Verified against the shipped 3.0.2 bundle (eq on text_ord/text_ord_ore/ text_search_ore inlines to eq_term; on numeric _ord to ord_term) and the stack builders (TextOrd = unique+ope, TextOrdOre = unique+ore). encryptedIndexes already emitted the right pair — it derives from the builders — so this is tests (TextOrd/TextOrdOre coverage), docblock, and skill prose: the stash-indexing capability table now carries the injectivity rationale, and stash-drizzle/supabase/prisma-next qualify the "one index serves =" claim to the numeric domains. Claude-Session: https://claude.ai/code/session_01BkEpKJC3975NHsKgMrCT8R
|
Round 3 ( The corresponding EQL doc fix is up: cipherstash/encrypt-query-language#418. |
The database-indexes page claimed equality rides eq_term/hm on the _ord domains generally. The shipped 3.0.2 bundle disagrees for the numeric-and-time types: their ordering terms (OPE and ORE alike) are injective, so those _ord/_ord_ore domains carry no hm, define no eq_term overload, and eql_v3.eq inlines to an ordering-term comparison — one ordering btree serves = and range. Text ordering terms are non-injective and cannot be relied on for equality, so text_ord/text_ord_ore (and the text_search variants) carry hm and answer = via eq_term. Corrected in five places (the recipe comment, requirement 1, the equality query pattern — now with the numeric-_ord engagement example — the term-check troubleshooting item, and the zero-rows note), plus a new note stating the injectivity rule once. Found while porting this guide into the stash agent skill (cipherstash/stack#753 / cipherstash/stack#773): an eq_term index recommended for a numeric _ord column doesn't compile (no overload), and the "type the column as _ord for equality" guidance pointed users at an index that can't exist. Claude-Session: https://claude.ai/code/session_01BkEpKJC3975NHsKgMrCT8R
An audit of the EQL repo's documentation against the shipped @cipherstash/eql@3.0.2 SQL surfaced four defects that had been copied into the new indexing guidance: - The JSON containment GIN recipe was a PostgreSQL syntax error: a cast over a function call is a general expression and needs its own parens in an index_elem — ((eql_v3.to_ste_vec_query(col)::jsonb) jsonb_path_ops). Verified both forms against Postgres 17. Fixed in stash-indexing, stash-supabase, and stash-prisma-next (the Drizzle helper already emitted the correct form). - The troubleshooting operand-typing example cast a query parameter to the column domain (public.eql_v3_text_eq), whose CHECK requires the ciphertext key 'c' that query payloads deliberately omit — the correct cast is the term-only eql_v3.query_text_eq domain. - The term probe checked hm/ob/bf but not op, the CLLW-OPE term the same page names as the equality-and-range term for _ord domains. - GROUP BY guidance now says which extractor to group on per domain: eq_term only exists on hm-carrying domains; numeric/date/timestamp *Ord/*OrdOre group on their injective ordering term. Also documented a trap the audit exposed: the EQL install SQL begins with DROP SCHEMA eql_v3 CASCADE, so stash eql upgrade / reinstall silently cascade-drops every functional index built on the extractors. stash-indexing and stash-cli (eql upgrade) now say to re-run index migrations + ANALYZE afterwards. Claude-Session: https://claude.ai/code/session_01BkEpKJC3975NHsKgMrCT8R
There was a problem hiding this comment.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
skills/stash-cli/SKILL.md (1)
414-414: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winQualify the “No indexes” remediation for storage-only domains.
Not every encrypted column can or should receive an index: storage-only domains intentionally have no indexing option. Clarify that the Info finding is actionable only for domains with supported functional-index recipes.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@skills/stash-cli/SKILL.md` at line 414, Update the “No indexes” remediation text in SKILL.md to state that it is actionable only for domains with supported functional-index recipes; explicitly exclude storage-only domains, where encrypted columns intentionally have no indexing option.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@skills/stash-cli/SKILL.md`:
- Line 397: Update the upgrade guidance in the install SQL documentation to
instruct users to create and apply a new index migration, or explicitly rerun
the extractor index DDL, after the schema recreation. Retain the requirement to
run ANALYZE, and do not suggest merely rerunning an already-applied migration.
In `@skills/stash-drizzle/SKILL.md`:
- Line 399: Update the mapping row for types.TextEq and numeric *Eq to also
cover date and timestamp equality domains, using wording consistent with the
companion N definition while preserving the existing eql_v3.eq_term index
mapping.
---
Outside diff comments:
In `@skills/stash-cli/SKILL.md`:
- Line 414: Update the “No indexes” remediation text in SKILL.md to state that
it is actionable only for domains with supported functional-index recipes;
explicitly exclude storage-only domains, where encrypted columns intentionally
have no indexing option.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 0df59a30-51c2-4d63-9f40-cfe3318920c7
📒 Files selected for processing (8)
.changeset/drizzle-encrypted-indexes.mdpackages/stack-drizzle/__tests__/v3/indexes.test.tspackages/stack-drizzle/src/v3/indexes.tsskills/stash-cli/SKILL.mdskills/stash-drizzle/SKILL.mdskills/stash-indexing/SKILL.mdskills/stash-prisma-next/SKILL.mdskills/stash-supabase/SKILL.md
🚧 Files skipped from review as they are similar to previous changes (3)
- .changeset/drizzle-encrypted-indexes.md
- packages/stack-drizzle/tests/v3/indexes.test.ts
- packages/stack-drizzle/src/v3/indexes.ts
…atform support Dan's comments: - indexes.ts docblock: example now shows its imports; the injectivity paragraph is rewritten in plain language; the extractor/tableNameOf helpers gained concrete input→output examples. - @cipherstash/stack-drizzle README: new 'Indexing encrypted columns' section with the encryptedIndexes example. - stash-cli: the db push / db activate section is removed (commands remain in the CLI; the skill no longer documents them). Cross-refs in the description, config table, and init steps scrubbed. The v2 cutover flows in stash-encryption/-drizzle/-supabase still reference db push — flagged on the PR for a decision on the v2 lifecycle docs. - ORE operator-class availability is now per-platform instead of 'unavailable on managed Postgres': supported on self-hosted Postgres and AWS RDS/Aurora, refused on cloud-hosted Supabase (the one confirmed platform) — stated consistently across stash-cli, stash-indexing, stash-encryption, and stash-drizzle. CodeRabbit: - stash-encryption cutover note scoped to EQL v3 (v2 rollouts skip it) and converted from blockquote to paragraph (MD028). - stash-indexing: ANALYZE added to the ORE and JSON field-ordering recipes; the JSON selector hash is now derivable in-file (encryptQuery with queryType 'steVecSelector'); reinstall guidance says to add a new migration (runners skip applied ones). - stash-cli eql upgrade: same new-migration wording; db validate 'No indexes' Info finding scoped to term-carrying columns (storage-only domains need no action). - stash-drizzle: equality row covers numeric/date/timestamp *Eq. Claude-Session: https://claude.ai/code/session_01BkEpKJC3975NHsKgMrCT8R
|
Round 4 ( Dan's comments
CodeRabbit
824 CLI + 384 stack-drizzle tests green; Biome clean. |
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
skills/stash-drizzle/SKILL.md (1)
380-391: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick winDocument
encryptedIndexesin the v3 export list.This section introduces
encryptedIndexesas a public import, but the later “Other v3 Exports” list omits it. Add the helper there so the skill remains internally consistent and self-sufficient.Proposed documentation update
-`types`, `makeEqlV3Column`, `getEqlV3Column`, ... +`types`, `encryptedIndexes`, `makeEqlV3Column`, `getEqlV3Column`, ...As per coding guidelines,
SKILL.mdis a public shipped artifact and must remain self-sufficient.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@skills/stash-drizzle/SKILL.md` around lines 380 - 391, Update the “Other v3 Exports” list in SKILL.md to include encryptedIndexes alongside the documented v3 exports, matching its public import and usage in the users table example.Source: Coding guidelines
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Outside diff comments:
In `@skills/stash-drizzle/SKILL.md`:
- Around line 380-391: Update the “Other v3 Exports” list in SKILL.md to include
encryptedIndexes alongside the documented v3 exports, matching its public import
and usage in the users table example.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 9c5c491f-40c4-4516-bb46-3a490834c64d
📒 Files selected for processing (7)
packages/stack-drizzle/README.mdpackages/stack-drizzle/src/v3/indexes.tsskills/stash-cli/SKILL.mdskills/stash-drizzle/SKILL.mdskills/stash-encryption/SKILL.mdskills/stash-indexing/SKILL.mdskills/stash-prisma-next/SKILL.md
🚧 Files skipped from review as they are similar to previous changes (2)
- packages/stack-drizzle/src/v3/indexes.ts
- skills/stash-indexing/SKILL.md
|
Docs/skills focused PR. |
Closes #753.
Problem
No shipped skill taught how to index an EQL v3 encrypted column. Two independent integration evals (#753) produced correct, encrypted, searchable integrations with zero indexes on any encrypted predicate — the installed skills contain no
CREATE INDEXexample, and the ORE-superuser warning was being over-generalized into "you can't index encrypted columns on Supabase."The skill
skills/stash-indexing/SKILL.md(262 lines, single self-sufficient file — required for the Codex/editor-agent inline path). Content is condensed from the EQL repo'sdocs/reference/database-indexes.md, which I verified is byte-identical betweenmainand theeql-bindings-v3.0.2tag — exactly the@cipherstash/eqlversion this repo pins andstash eql installapplies. All six extractor functions the recipes use are verified present in the shipped 3.0.2 SQL bundle.Covers, per the issue's proposed scope:
eq_term(btree-first; hash noted for small tables),ord_term,ord_term_ore,match_termGIN,to_ste_vec_queryGINjsonb_path_ops, and field-level JSON ordering — each tied to thetypes.*factories and raw domain names, with the engaging query shape.record_opssilent-inert-index failure mode and itspg_opclassdetection query.types.T,types.Boolean) called out as having no index option by design.ANALYZE), theORDER BYsort-key /value::jsonb/GROUP BYtraps, build-at-scale guidance (maintenance_work_mem, btree-vs-hash builds, de-TOAST floor), and theEXPLAINchecklist.stash encrypt backfill, before switching reads (also added as a blockquote instash-encryption's cutover step).Note: the skill uses the doc-canonical
eql_v3.match_term(col)GIN form rather than the issue'seql_v3_internal.bloom_filter(...)—match_termexists in 3.0.2, is the supported surface, andeql_v3_internalis internal (the Supabase skill explicitly says not to expose it).Wiring
SKILL_MAP+BASE_SKILLS(CLI) and the wizard's ownSKILL_MAP: installed for every integration — the gap is cross-cutting, per the issue.SKILL_PURPOSES: one-liner for the setup prompt. Also fixes the missingstash-prisma-nextentry, which rendered "(no description)" — with a new test asserting everySKILL_MAP-installable skill has a purpose line, so the gap class can't recur.stash-encryption,stash-cli(itsdb validate"No indexes" Info finding now points somewhere),stash-drizzle,stash-supabase,stash-prisma-next.AGENTS.mdskills list + drift table row; doctrine's common-skills line (also adds the previously missingstash-prisma-nextthere).stash+@cipherstash/wizardminor (precedent: the stash-prisma-next skill addition).Testing
pnpm --filter stash test— 824 pass (incl. updated exact-array install expectations and the new purpose-line guard) against a freshdist/bundle containing the new skillpnpm --filter @cipherstash/wizard test— 148 passnode packages/cli/dist/bin/stash.js manifest --json— everystashcommand the new/edited skill text names resolves (eql install,db validate,encrypt backfill|cutover|drop,status)pnpm run code:check— exit 0namematches the directory; description is a single linehttps://claude.ai/code/session_01BkEpKJC3975NHsKgMrCT8R
Summary by CodeRabbit
stash-indexingskill with end-to-end guidance for functional indexing of encrypted EQL v3 columns (recipes, verification viaEXPLAIN, and large-table build practices).stash-indexingin onboarding/setup flows and across supported integrations.encryptedIndexesto generate recommended functional index builders for encrypted columns.stash-indexingandencryptedIndexes.Update — review round 2 (
b23f9c2d)Per review: the general skill stays general, each ORM skill now carries its own applied-indexing section, and Drizzle gets real API support.
New:
encryptedIndexeson@cipherstash/stack-drizzle/v3. Spread...encryptedIndexes(t)inpgTable's extras callback and it derives the functional indexes for every encrypted column from the same per-domain capability record the operator layer gates on (builder.build().indexes) — the emitted indexes and the operators that engage them cannot drift. Named<table>_<column>_<capability>, tracked bydrizzle-kit generate. 7 new tests pin the mapping, naming, and exact extractor expressions.Two findings from building it:
ExtraConfigColumn.getSQLType()isreturn this.getSQLType()— unconditional self-recursion. Any extras-callback column blew the stack throughisEqlV3Column/getEqlV3Column's fallback path.getSqlTypenow recovers the domain from the column's custom-type params (the same expressionPgCustomColumn's constructor uses) instead of calling it.eq_termoverload for_ord/_ord_oredomains —eql_v3.eqon them inlines toord_term(a) = ord_term(b), so one ordering btree serves=and range alike. The skill's capability table and equality recipe followed the EQL doc's overstated claim ("equality needs hm —_eq,_ord, …"); both now match the shipped SQL, and the skill explicitly warns against adding aneq_termindex to an_ordcolumn. (The EQL repo's doc should get a corresponding fix — noted for follow-up.)Skills reshaped:
stash-indexing§ "Where the Index DDL Goes" is now a general pointer list;stash-drizzlegains a full Indexing Encrypted Columns section (helper first, manual expression-index DSL as the escape hatch);stash-supabaseandstash-prisma-nextgain concrete sections with the per-domain DDL (prisma-next:schema.prismacan't express functional indexes → raw-SQL migration op in the same history that installs the EQL bundle).Verification: 824 CLI + 384 stack-drizzle tests pass (fresh builds), Biome exit 0, no Linear IDs. New changeset:
@cipherstash/stack-drizzleminor.