You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The original detailed audit was an in-flight branch snapshot and is preserved in this issue's edit history. The removal work it tracked is now integrated on remove-v2; the remaining release-readiness work is consolidated in #816.
The final contract is:
EQL v3 is the sole authoring and write generation.
Existing EQL v2 ciphertext remains readable through the core native client.
Final integrations use Encryption, the @cipherstash/stack-drizzle package root, and encryptedSupabase.
The typed Encryption client supports audited decrypt, including through DynamoDB.
@cipherstash/nextjs receives only package-specific release notes.
Already-published RC changesets are not rewritten; still-pending entries and the final GA summary carry the corrected migration guidance and owning package metadata.
Remaining gate
#816 covers the last adapter correctness fixes and proof gates: nested PostgREST OR preservation, nullish-search fail-closed handling, safe non-row result modes, LIKE escaping, legacy Supabase call diagnosis, Date parity, examples/e2e/Drizzle integration typechecks, concrete Supabase domain guidance, and CLI/wizard skill parity including Prisma Next.
The two deferred type-surface items share one root cause
#780's Not in this PR section defers encryptQuery in the published .d.ts collapsing its plaintext parameter to never under private-field type erasure, noting it is pre-existing on both remove-v2 and main.
While documenting the WASM entry for #754 (PR #777) I hit what looks like the same defect from the other side, and it is worth scoping the two together rather than separately.
Symptom A — cross-entry schema incompatibility. A schema authored with @cipherstash/stack/v3 does not typecheck against @cipherstash/stack/wasm-inline's Encryption, and the reverse fails too:
Type 'EncryptedTextSearchColumn' is not assignable to type 'AnyEncryptedV3Column'.
Types have separate declarations of a private property 'columnName'.
Symptom B — the deferred one. Reproduced against a fresh dist/ build on 972a8a85:
TS2345: Argument of type '"alice@example.com"' is not assignable to parameter of type 'never'.
Both stem from the v3 column classes' type identity not surviving .d.ts emission intact — EncryptedV3Column carries private readonly columnName / private readonly definition (packages/stack/src/eql/v3/columns.ts:434-437), and TypeScript compares classes with private members nominally.
The obvious fix is wrong
Dropping private looks like a one-line fix and is not. columns.ts:426-433 says why:
the private definition field carries the literal eqlType/castAs/capabilities, so two otherwise-empty subclasses (e.g. EncryptedBooleanColumn and EncryptedDateColumn, both storage-only) are NOT mutually assignable. This nominality is what keeps plaintext inference precise.
Those privates are load-bearing — removing them would make storage-only domains mutually assignable and degrade the inference the v3 surface exists to provide. I had suggested exactly that fix in an earlier revision of #777's description and have since retracted it there.
The generalisable point for this issue
#780's own note on symptom B nails the reason neither surfaced: "invisible because the type tests import source rather than dist/."
That applies to every type-level claim in this stack, not just these two. Finding 13 in my review comment on #772 is a third case — Awaited<ReturnType<typeof EncryptionV3>> now silently resolves to the nominal client, so stack-drizzle's M1 guard became a duplicate of the next test while test:types stayed green; and tsc in that package reports hard TS2739s in five files nothing type-checks.
Given §"Before the rc.5 publish" already calls for a re-sweep of skills/ and the READMEs because nothing type-checks them, the analogous gate for the type surface is worth adding: at least one type test that consumes dist/ rather than src/. Without it, PRs 9–12 will land the authoring-surface changes with the same blind spot that let both of these through.
Happy to file symptoms A and B as a single issue against the type surface if that is more useful than carrying them here — flagging the connection first so they don't get scoped as two unrelated papercuts.
This gives four mergeable workstreams. Skills, README, pending-changeset, and tracking-text corrections travel with their owning workstream rather than creating another hygiene PR.
#780 is already merged and should not be recreated. Its deliberately deferred Encryption declaration/type work is covered by #815.
Closing — both residuals now have homes (2026-07-30)
This tracker's own body already delegates: "the remaining release-readiness work is consolidated in #816." The removal work it tracked is integrated on main (c8b1325a) via #772 (d5a22338), and the final contract it states is verified there — EQL v3 is the sole authoring and write-generation surface, existing v2 ciphertext still reads through the core client, integrations use Encryption / the @cipherstash/stack-drizzle package root / encryptedSupabase, typed Encryption supports audited decrypt including through DynamoDB, and published RC changesets were left unrewritten.
Two things were still pointing here. Both are now re-homed, so this can close without orphaning anything:
Re-pointing that tests.yml comment from this issue to #531 is a one-line change tracked as a checklist item in #531. Until it lands, the CI comment references this closed issue.
Activity
coderdan commentedon Jul 24, 2026
The two deferred type-surface items share one root cause
#780's Not in this PR section defers
encryptQueryin the published.d.tscollapsing its plaintext parameter toneverunder private-field type erasure, noting it is pre-existing on bothremove-v2andmain.While documenting the WASM entry for #754 (PR #777) I hit what looks like the same defect from the other side, and it is worth scoping the two together rather than separately.
Symptom A — cross-entry schema incompatibility. A schema authored with
@cipherstash/stack/v3does not typecheck against@cipherstash/stack/wasm-inline'sEncryption, and the reverse fails too:Symptom B — the deferred one. Reproduced against a fresh
dist/build on972a8a85:Both stem from the v3 column classes' type identity not surviving
.d.tsemission intact —EncryptedV3Columncarriesprivate readonly columnName/private readonly definition(packages/stack/src/eql/v3/columns.ts:434-437), and TypeScript compares classes with private members nominally.The obvious fix is wrong
Dropping
privatelooks like a one-line fix and is not.columns.ts:426-433says why:Those privates are load-bearing — removing them would make storage-only domains mutually assignable and degrade the inference the v3 surface exists to provide. I had suggested exactly that fix in an earlier revision of #777's description and have since retracted it there.
The generalisable point for this issue
#780's own note on symptom B nails the reason neither surfaced: "invisible because the type tests import source rather than
dist/."That applies to every type-level claim in this stack, not just these two. Finding 13 in my review comment on #772 is a third case —
Awaited<ReturnType<typeof EncryptionV3>>now silently resolves to the nominal client, sostack-drizzle's M1 guard became a duplicate of the next test whiletest:typesstayed green; andtscin that package reports hardTS2739s in five files nothing type-checks.Given §"Before the rc.5 publish" already calls for a re-sweep of
skills/and the READMEs because nothing type-checks them, the analogous gate for the type surface is worth adding: at least one type test that consumesdist/rather thansrc/. Without it, PRs 9–12 will land the authoring-surface changes with the same blind spot that let both of these through.Happy to file symptoms A and B as a single issue against the type surface if that is more useful than carrying them here — flagging the connection first so they don't get scoped as two unrelated papercuts.
fix(stack): refuse EQL v2 wire over an all-v3 schema set (A-8)
fix(stack): refuse EQL v2 wire over an all-v3 schema set (A-8)
fix(stack): refuse EQL v2 wire over an all-v3 schema set (A-8)
tobyhede commentedon Jul 28, 2026
Consolidated execution tracks
The remaining work is now tracked by outcome rather than PR count:
This gives four mergeable workstreams. Skills, README, pending-changeset, and tracking-text corrections travel with their owning workstream rather than creating another hygiene PR.
#780 is already merged and should not be recreated. Its deliberately deferred Encryption declaration/type work is covered by #815.
fix(stack): refuse EQL v2 wire over an all-v3 schema set (A-8)
docs(ci,stack-drizzle): keep the error counts and #778 in the gate co…
tobyhede commentedon Jul 29, 2026
Closing — both residuals now have homes (2026-07-30)
This tracker's own body already delegates: "the remaining release-readiness work is consolidated in #816." The removal work it tracked is integrated on
main(c8b1325a) via #772 (d5a22338), and the final contract it states is verified there — EQL v3 is the sole authoring and write-generation surface, existing v2 ciphertext still reads through the core client, integrations useEncryption/ the@cipherstash/stack-drizzlepackage root /encryptedSupabase, typedEncryptionsupports audited decrypt including through DynamoDB, and published RC changesets were left unrewritten.Two things were still pointing here. Both are now re-homed, so this can close without orphaning anything:
.github/workflows/tests.yml:169-176cites this issue as the owner of the deliberately-deferred typecheck gap (@cipherstash/stack147 errors,stash21,@cipherstash/stack-supabase11, plus theV3_MATRIX.indexesroot cause). Finish adapter correctness and release verification for the v2 removal #816 covers only thestack-drizzleclause, so the rest would have been orphaned. It has been added to Improve CI: add tsc --noEmit + TSDoc/doc-example validation gates, expand Node matrix to 26 #531, which already owns "atypecheckscript per package coveringsrc/and__tests__/".Re-pointing that
tests.ymlcomment from this issue to #531 is a one-line change tracked as a checklist item in #531. Until it lands, the CI comment references this closed issue.