Skip to content

fix(skills,wizard,cli): clear the residue from the v2 removal and #823 - #838

Merged
tobyhede merged 5 commits into
mainfrom
fix/issue-837
Jul 30, 2026
Merged

fix(skills,wizard,cli): clear the residue from the v2 removal and #823#838
tobyhede merged 5 commits into
mainfrom
fix/issue-837

Conversation

@tobyhede

@tobyhede tobyhede commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Closes #837.

Every item in the checklist shares one root cause: a change updated one copy of something and left the other. All were verified present on main (c8b1325a) before editing.

Shipped skills that contradicted each other in the customer's repo

SKILL_MAP.drizzle installs stash-encryption, stash-drizzle, stash-indexing and stash-cli together, and skills/ ships inside the stash tarball — so both pairs below landed side by side in a customer's repo and disagreed.

skills/stash-drizzle/SKILL.md:64 called the sweep's repair "data-destroying", safe "only on an empty table", and told the reader not to apply a swept migration to a table with live data. #823 made the rewriter add-only, so that was false, and skills/stash-cli/SKILL.md:379 states the opposite correctly — only the stash-cli copy was updated at the time.

I re-verified the replacement text against the code rather than trusting the issue:

Claim Verified against
add-only; adds <column>_encrypted, preserves the source renderSafeAlter emits a single ALTER TABLE … ADD COLUMN "<col>_encrypted" (packages/cli/src/commands/db/rewrite-migrations.ts:846-873)
never emits DROP COLUMN / RENAME COLUMN asserted in both rewriter test suites
cannot prove source type, or twin exists → left untouched SkipReason source-unknown / target-exists, fail-closed on declaredColumns
command exits non-zero sweepIncompletethrow new CliExit(1) (packages/cli/src/commands/eql/migration.ts:332-344)

skills/stash-encryption/SKILL.md:12 pointed at an older EQL v2 schema surface "with chainable capability builders" that "still exists for existing deployments". :201 and :1015 of the same file say the v2 builders and the @cipherstash/stack/client subpath were removed and that v2 is a decrypt-only read path — which matches the code after #829. The pointer resolved to a section asserting its opposite; it now describes the read-compatibility path it actually leads to.

db push residue in wizard source and tests

stash db push was retired with the Proxy lifecycle (#814 / #825), and post-agent.ts:58 already says it "must never run".

  • packages/wizard/src/run.ts:243 — the "Post-agent steps complete" changelog line claimed db push ran. It now names what runPostAgentSteps actually does: package install, eql install, migrations.
  • The three stale test examples (agent/__tests__/interface.test.ts:91, __tests__/interface.test.ts:148, __tests__/format.test.ts:74) now use live commands. db validate resolves against stash manifest --json.
  • Beyond the checklist: packages/wizard/src/bin/wizard.ts:43 promised "No code or schema changes, no db pushes" in the --plan help text — same residue, user-visible, so it is fixed here too.

The 'stash db' allowlist prefix (packages/wizard/src/agent/interface.ts:58,81) is deliberately unchanged: it still serves db validate, db migrate and db test-connection.

Wizard sweep: the reporting gap the CLI copy does not have

rewriteEncryptedMigrations warned about a directory whose sweep threw and then continued past the per-directory report — so files it had already rewritten on disk were never named. sweepMigrationDirs propagates that partial set (rewrite-migrations.ts:944-952) precisely so the caller can report it, and the CLI does (eql/migration.ts:316-321).

It now reports Rewrote N migration file(s) in <dir>/ before the sweep stopped: followed by the file list, and falls through to the skipped-statement report as well. Nothing else changes: the rewritten SQL is additive, and post-agent.ts:81-85 still throws before the migrate prompt, so nothing unreviewed runs.

Two tests cover it — one that the partial set is named, one that the clean path does not borrow the partial wording. Verified the first fails on the pre-fix post-agent.ts and passes after.

Test drift found while verifying

packages/cli/src/__tests__/rewrite-migrations.test.ts lacked the 'switch the application to the' assertion its wizard twin already had. The parity guard compares the two source files, not the two test files, so the drift was invisible to CI.

Deliberately out of scope

The unchecked err as Partial<RewriteSweepError> cast at packages/wizard/src/lib/rewrite-migrations.ts:946 is untouched — it is a fail-closed correctness defect (a non-object throw raises a TypeError inside the catch and escapes sweepMigrationDirs), tracked as item 3 of #836.

Per #837's note about the shared paragraph: this PR owns deleting the false "data-destroying" claim at skills/stash-drizzle/SKILL.md:64. #836 later adds post-sweep reconciliation guidance to the same paragraph. This one must land first — the other order silently reverts the correction.

Changesets

  • stash patch — the two shipped skills (skills/ ships in the tarball).
  • @cipherstash/wizard patch — the db push strings and the sweep report.

No @cipherstash/stack changeset: the stash-encryption wording change is a skills-only edit, and skills ship in the stash and @cipherstash/wizard tarballs, both of which are bumped.

Verification

packages/wizard  344 passed | 5 skipped
packages/cli     895 passed
tsc --noEmit     clean (wizard)
biome check      no errors on changed files

biome check reports one warning in run.ts — an unused INTEGRATIONS import that predates this branch (confirmed by stashing the change and re-running). CI gates on errors only.

Summary by CodeRabbit

  • Documentation

    • Reworded encrypted-column migration guidance to emphasize add-only staging (no drop/rename) and clearer failure/leave-untouched conditions.
    • Updated encryption/EQL v2 compatibility guidance: v2 builders removed for new writes, while decrypt remains for existing v2 payloads.
  • Bug Fixes

    • Wizard output/changelog/help text no longer references database pushes; “plan” now reflects the actual behavior.
    • Improved reporting when migration directory sweeps fail, including listing already-rewritten files and suppressing misleading cross-directory success messaging.
  • Tests

    • Strengthened assertions for guidance text, allowed commands, and partial/failed sweep logging.

@tobyhede
tobyhede requested a review from a team as a code owner July 29, 2026 23:56
@changeset-bot

changeset-bot Bot commented Jul 29, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: e2382d2

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 11 packages
Name Type
stash Patch
@cipherstash/wizard Patch
@cipherstash/basic-example Patch
@cipherstash/e2e Patch
@cipherstash/stack Patch
@cipherstash/stack-drizzle Patch
@cipherstash/stack-supabase Patch
@cipherstash/prisma-next Patch
@cipherstash/bench Patch
@cipherstash/test-kit Patch
@cipherstash/prisma-next-example Patch

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

@coderabbitai

coderabbitai Bot commented Jul 29, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@tobyhede, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 45 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 21a80b5a-97f9-4e62-b7ec-41938d242e7d

📥 Commits

Reviewing files that changed from the base of the PR and between 249ab24 and e2382d2.

📒 Files selected for processing (12)
  • .changeset/shipped-skills-v2-removal-residue.md
  • .changeset/wizard-db-push-residue-and-sweep-report.md
  • packages/wizard/README.md
  • packages/wizard/src/__tests__/format.test.ts
  • packages/wizard/src/__tests__/interface.test.ts
  • packages/wizard/src/__tests__/post-agent.test.ts
  • packages/wizard/src/agent/__tests__/interface.test.ts
  • packages/wizard/src/bin/wizard.ts
  • packages/wizard/src/lib/post-agent.ts
  • packages/wizard/src/run.ts
  • skills/stash-drizzle/SKILL.md
  • skills/stash-encryption/SKILL.md
📝 Walkthrough

Walkthrough

The PR updates wizard migration-sweep reporting, removes stale stash db push references, and reconciles shipped skill documentation with add-only encrypted-column rewrites and EQL v2 read compatibility.

Changes

Wizard migration reporting

Layer / File(s) Summary
Partial sweep reporting
packages/wizard/src/lib/post-agent.ts, packages/wizard/src/__tests__/post-agent.test.ts, .changeset/wizard-db-push-residue-and-sweep-report.md
Wizard reporting now lists migration files rewritten before a sweep error and distinguishes partial failures from successful sweeps, with tests covering both paths.

Wizard output cleanup

Layer / File(s) Summary
Command and status text
packages/wizard/src/bin/wizard.ts, packages/wizard/src/run.ts, packages/wizard/README.md, packages/wizard/src/__tests__/format.test.ts
Help, changelog, README, and formatter fixtures describe migrations instead of stash db push.
Command allowlist coverage
packages/wizard/src/__tests__/interface.test.ts, packages/wizard/src/agent/__tests__/interface.test.ts
Tests use stash db validate in place of the removed stash db push example.

Skill guidance reconciliation

Layer / File(s) Summary
Migration and EQL compatibility guidance
skills/stash-drizzle/SKILL.md, skills/stash-encryption/SKILL.md, packages/cli/src/__tests__/rewrite-migrations.test.ts, .changeset/shipped-skills-v2-removal-residue.md
Documentation describes add-only encrypted-column staging, EQL v2 read compatibility, and updated migration guidance coverage.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Possibly related issues

Possibly related PRs

Suggested reviewers: freshtonic, calvinbrewer, coderdan

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning The PR also edits packages/wizard/README.md, but #837 explicitly says README residue is tracked under #816, so that change is out of scope. Remove the README edits from this PR or move them to the separate README reconciliation issue.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title is concise and clearly refers to the skills/wizard/CLI cleanup from the v2-removal residue.
Linked Issues check ✅ Passed The PR addresses the linked checklist: skill docs, stale db push references, and wizard sweep reporting/tests are all updated as requested.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/issue-837

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 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 `@packages/wizard/src/__tests__/format.test.ts`:
- Line 74: Update the relevant format test to assert that the second list item
contains “npx drizzle-kit migrate” and does not contain “stash db push,”
preserving the existing assertions for the other generated content.
🪄 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: 2fc4a901-a162-4efb-b3cf-cde61746aa71

📥 Commits

Reviewing files that changed from the base of the PR and between c8b1325 and e392ee1.

📒 Files selected for processing (12)
  • .changeset/shipped-skills-v2-removal-residue.md
  • .changeset/wizard-db-push-residue-and-sweep-report.md
  • packages/cli/src/__tests__/rewrite-migrations.test.ts
  • packages/wizard/src/__tests__/format.test.ts
  • packages/wizard/src/__tests__/interface.test.ts
  • packages/wizard/src/__tests__/post-agent.test.ts
  • packages/wizard/src/agent/__tests__/interface.test.ts
  • packages/wizard/src/bin/wizard.ts
  • packages/wizard/src/lib/post-agent.ts
  • packages/wizard/src/run.ts
  • skills/stash-drizzle/SKILL.md
  • skills/stash-encryption/SKILL.md

Comment thread packages/wizard/src/__tests__/format.test.ts

@coderdan coderdan left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch.

@freshtonic freshtonic left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed via git show/git grep against origin/fix/issue-837, with PR-relevant tests run in an isolated worktree.

Requesting changes — for one on-thesis missed residue. The actual code and test changes are correct and I'd otherwise approve.

What's right

  • The partial-sweep reporting fix in post-agent.ts (dropping the erroneous continue, gating the cross-directory summary on !unverified, presence-checking error) is sound, backed by two targeted tests that pass.
  • The two skill corrections are accurate against the code and CLI registry: eql migration --drizzle[ --supabase] and db validate resolve in registry.ts, and the @cipherstash/stack/client subpath the stash-encryption skill says was removed is indeed absent from packages/stack/package.json. Two changesets present and correctly scoped (stash patch for skills, @cipherstash/wizard patch for code/strings). Prior CodeRabbit point (assert the second list item in format.test.ts) is resolved.

Blocker

  • packages/wizard/README.md:23,36 (major): missed residue of exactly the kind this PR exists to kill. The README still says the wizard "shells out to stash eql install / db push after the agent finishes editing" (~L23) and lists post-agent steps as "package install, eql install, db push, framework-specific migrations" (~L36) — the same false db push claim this PR correctly removes from run.ts:243 and wizard.ts:43. README.md is in the wizard package's files array, so it ships in the @cipherstash/wizard tarball; leaving it recreates the "one copy updated, other left" defect #837 is about. The PR already bumps @cipherstash/wizard, so no extra changeset needed — just edit those two lines to name what runPostAgentSteps actually runs (package install, eql install, migrations).
  • Nit while you're in the file: run.ts:17 has a pre-existing unused INTEGRATIONS import (the lone biome warning, author-disclosed) — removing it leaves the changed file warning-free.

Caveat: 6 failures in the full wizard run are all in gateway-messages.test.ts (live-gateway suite, no network/creds here) — not a regression. The deferred err as Partial<RewriteSweepError> cast is legitimately out of scope (→ #836).

Fix the README lines and I'm happy to approve.

tobyhede added 5 commits July 30, 2026 12:55
Every item here has the same root cause: a change updated one copy of something
and left the other. Closes #837.

**`stash-encryption` contradicted itself in the customer's repo.**
`skills/stash-encryption/SKILL.md:12` pointed at an EQL v2 schema surface "with
chainable capability builders" that "still exists", while `:201` and `:1015` of
the same file said the v2 builders are gone and v2 is a decrypt-only read path —
which is what the code does after #829. The opening callout now says that. It is
the first thing an agent reads, and `SKILL_MAP.drizzle` installs this skill into
every Drizzle project.

**`db push` residue.** `stash db push` was retired with the Proxy lifecycle
(#814 / #825) and `post-agent.ts` says it "must never run", but the "Post-agent
steps complete" changelog line still claimed it had, and three tests used it as
their example of an allowed `stash db` command. The tests now use `db validate`,
which is in the manifest. Also dropped "no db pushes" from the `--plan` help
text. The `'stash db'` allowlist prefix is unchanged — it still serves
`db validate`, `db migrate` and `db test-connection`.

**Wizard sweep reporting gap.** When a directory's sweep threw, the `continue` in
`rewriteEncryptedMigrations` skipped the per-directory report, so files it had
already rewritten on disk went unnamed — `sweepMigrationDirs` propagates that
partial set precisely so the caller can report it, and the CLI twin does. Now
reported as "Rewrote N migration file(s) in <dir>/ before the sweep stopped",
with the file list. Behaviour-neutral otherwise: the SQL is additive and the
wizard still throws before the migrate prompt. Two tests pin it, including one
that the clean path does not borrow the partial wording; the first fails without
the fix.

Dropped in the rebase: the `stash-drizzle` add-only correction and the CLI
rewriter test assertion this commit originally carried both landed on main
independently (91452c1), so the tree already has them. The `stash-drizzle`
bullet is gone from the changeset for the same reason.

The `err as Partial<RewriteSweepError>` cast at `rewrite-migrations.ts:946` is
deliberately untouched — it is a fail-closed correctness defect tracked as item 3
of #836, not cleanup.
…arker

The `stash db push` → `drizzle-kit migrate` fixture swap in the previous commit
was unasserted: the test pinned `pc.dim('1.')` and nothing about item 2, so the
retired command could drift back in and the suite would stay green — which is how
it survived the Proxy-lifecycle removal (#814 / #825) here in the first place.

Pins the rendered second item (`2. Run npx drizzle-kit migrate`) and the absence
of `stash db push`, leaving the existing heading/checkmark/inline-code
assertions untouched. Verified the new assertions fail when the fixture is
reverted to `stash db push`.
**Suppress the cross-directory summary when a sweep failed** (review finding 3).
`runPostAgentSteps` prints "Rewrote N migration file(s) in the drizzle output to
add staged encrypted columns while preserving the source columns" off
`totals.rewritten`, which counts a clean directory and a partially-swept one
alike. On the failure path that restated the reassuring framing the new
per-directory report deliberately drops, immediately after it. Gated on the
failure, not on `skipped` — a flagged statement means the sweep finished and the
count is accurate. Test written first and watched fail on the second `info` call.

**Cover the flagged statements a failed sweep leaves behind** (review finding 6).
Removing the `continue` also let a failed directory report its `skipped`
statements, which nothing asserted. Folded into the partial-set test, and
verified load-bearing by gating the skipped block on `error === undefined` and
watching the assertion fail.

**Stop mocking the sweep for the clean path** (review findings 1 and 2). The
clean-arm test overrode `sweepMigrationDirs` where a real fixture works, against
the convention stated at the top of the file — and that override silently made
the file's header comment false, which is exactly the defect class this branch
exists to close. Deleted it; its two assertions now live on the existing
real-fixture test, anchored on `in drizzle/` so the cross-directory summary
cannot satisfy them instead. The header comment now names the two remaining
overrides and why each is unreachable through the real filesystem, and each
override repeats the reason at its call site. Verified by flipping the ternary:
three tests fail, including the folded one.

**Name all four skip reasons in the Drizzle skill** (review finding 4). The
paragraph listed `source-unknown` and `target-exists` but not `already-encrypted`
or `unrecognised-form`, so a reader could infer a hand-authored
`SET DATA TYPE … USING …` gets repaired. Also cut the duplicated statement of the
declaring-migration requirement.

Verified: wizard 344 passed / 5 skipped, cli 895 passed, `tsc --noEmit` clean,
biome clean on the changed files.

Review finding 5 (skills also ship in the `@cipherstash/wizard` tarball, but the
skills changeset is scoped to `stash` alone) is left as-is: it follows repo
precedent (`adapter-split-skills.md`), and both tarballs are bumped here anyway.
It is a question about the convention, not this branch.
The README still named `db push` in two places — as a `stash` prerequisite
("shells out to `stash eql install` / `db push`") and as a post-agent step.
`runPostAgentSteps` never invoked it, so both lines were the same false claim
this branch removes from `run.ts` and `wizard.ts`. README.md is in the wizard
package's `files` array, so it ships in the tarball: leaving it recreates the
one-copy-updated defect #837 is about.

Also removes the unused `INTEGRATIONS` import from `run.ts`, which was the
file's only biome warning.
The rebase onto main lands `sweep.staged` (#836, item 2) under the mocked
`sweepMigrationDirs` result in the partial-set test, which predates it: the
fixture had no `staged`, so `totals.staged.push(...staged)` threw "staged is not
iterable" and the test failed on the wrong error.

The twin is spelled out rather than stubbed to `[]` — the fixture's rewritten
`0001_email.sql` is exactly a file that added one, and `rewriteEncryptedMigrations`
accumulates twins from a directory whose sweep later threw precisely because they
are already on disk and already divergent from `schema.ts` and the snapshot. A
stub would have made the fixture contradict the code path it stands in for.

@freshtonic freshtonic left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-reviewed at head e2382d29, re-checking the prior findings and the four new commits.

Approving. The new commits cleanly resolve my prior major finding and the nit, and address the CodeRabbit review, without regressing the partial-sweep reporting fix or introducing new inaccuracies.

  • [was major] README db push residue — gone (0fc041ac). The prerequisite line now reads "shells out to stash eql install after the agent finishes editing" and post-agent step 5 reads "package install, eql install, framework-specific migrations" — matching what runPostAgentSteps actually runs. No other shipped doc/string carries the false claim (remaining db push hits are the Supabase CLI's own supabase db push, tests asserting absence, the e2e retirement test, and comments).
  • [was nit] unused INTEGRATIONS import (run.ts:17) — removed; Biome now reports zero warnings on the changed files.

Verified the other new commits didn't regress anything

  • 459cf55a ("address review findings") changed no runtime behaviour beyond what was already approved — the reporting fix is intact (if (didStage && !unverified), continue removed with the fall-through report, error === undefined ternary). Its runtime-adjacent change is test-only (dropped an unnecessary sweepMigrationDirs mock on the clean path, moving its assertions onto the real-fixture test — a net move away from mock-behaviour testing). Its stash-drizzle skill edit adds the two previously-missing skip reasons; all four named reasons map exactly to the real SkipReason union at rewrite-migrations.ts:828-836.
  • e2382d29 is a legitimate test-only fixture fix (the rebase brought in sweep.staged from #836, so the pre-existing mock needed a staged entry to avoid "staged is not iterable"); the added shape matches the real DirRewriteResult/StagedColumn. 6a616234 is a genuine behavioural assertion (pins the rendered second step + absence of stash db push).

All PR-relevant suites pass and Biome is clean; changesets present for both stash and @cipherstash/wizard. Note the branch was rebased onto a newer main that absorbed #836/#839/#840, so the authoritative diff is a tight 12 files / +220/-20 (the CLI rewrite-migrations.test.ts change landed via main, not here).

Nice, thorough turnaround.

@tobyhede
tobyhede merged commit 2d7ef56 into main Jul 30, 2026
10 checks passed
@tobyhede
tobyhede deleted the fix/issue-837 branch July 30, 2026 03:37
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.

Residue from the v2 removal and #823: contradictory shipped skills, db push references, wizard sweep gaps

3 participants