Skip to content

Helo#31

Merged
3m1n3nc3 merged 8 commits into
fix/rollback-step-and-error-surfacingfrom
main
Jul 5, 2026
Merged

Helo#31
3m1n3nc3 merged 8 commits into
fix/rollback-step-and-error-surfacingfrom
main

Conversation

@3m1n3nc3

@3m1n3nc3 3m1n3nc3 commented Jul 5, 2026

Copy link
Copy Markdown
Member

No description provided.

3m1n3nc3 and others added 8 commits July 5, 2026 08:17
Only migrate loaded the project config; the other database-touching commands
read this.app.getConfig('adapter') directly. Under harnesses that hand the
command a fresh CliApp without applying the config (e.g. the Arkstack CLI),
the adapter was undefined — so migrate:fresh silently took the Prisma-schema
path instead of resetting the configured (Kysely) database, i.e. it did not
tear anything down. rollback/seed/models:sync/migrate:history had the same
latent gap.

Each now calls loadArkormConfig() first (idempotent; matches migrate).

migrate:fresh itself is confirmed correct: adapter.resetDatabase() drops all
base tables and enum types in the current schema, then every migration is
re-run from a clean state.

Test: migrate:fresh reaches the adapter reset path when the adapter is only
reachable through arkormx.config (no configureArkormRuntime).
A migration's up()/down() is invoked both to gather its schema operations
and, when it uses DB.raw() directly, as a real side effect. Several flows
re-invoke up() purely to (re)build column-mapping / feature metadata:
MigrateCommand's per-migration plan, and syncPersistedColumnMappingsFromState
/ validatePersistedMetadataFeaturesForMigrations. On rollback, sync re-planned
every *still-applied* migration's up(), replaying its raw SQL (e.g. an ADD
CONSTRAINT) against a schema it was never meant to touch again — throwing
'already exists' and leaving state half-updated so later commands also failed.
migrate survived only because the raw ran twice but idempotently.

- Add a migration-planning context: while active, DB.raw is a no-op. It is
  anchored on globalThis via Symbol.for so the CLI bundle (dist/cli.mjs) and the
  library bundle (dist/index.mjs) share one AsyncLocalStorage — otherwise the
  flag would not cross from getMigrationPlan() to the migration's DB.raw().
- getMigrationPlan(migration, direction, { inert }) runs the body inertly.
- Planning-only callers pass inert: MigrateCommand's plan step, column-mapping
  rebuild, and feature validation. Actual apply/rollback stay non-inert, so the
  raw runs exactly once.

Verified end to end against a scratch database: migrate runs the raw once, and
rollback of a later batch no longer replays a still-applied migration's raw SQL.

Tests: DB.raw runs on normal planning but is suppressed under inert planning
while operations are still collected.
…ffects

fix(migrations): don't replay DB.raw side effects during plan collection
…urfacing

fix(cli): rollback --step default + surface query error causes
@3m1n3nc3 3m1n3nc3 merged commit ccee8c3 into fix/rollback-step-and-error-surfacing Jul 5, 2026
8 checks passed
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.

1 participant