Relationships
↔ sibling #2621#3117 datastore config migrate writes its sentinel before pushing; after a failed push a re-run reports 'already completed' and never publishes
Opened by stack72 · 10/6/2026· Shipped 10/6/2026
Summary
swamp datastore config migrate writes its "already migrated" sentinel (config/managed-config-migrated.json) into the local cache before it pushes to the datastore. If the push fails, the command exits non-zero, but every re-run finds the local sentinel, reports alreadyMigrated: true, exits 0 and pushes nothing. The datastore never receives the config, and nothing tells the user to run swamp datastore sync --push.
Where it happens (swamp 5517e708)
src/domain/datastore/managed_config_migration.ts:- :44-59: the "already migrated" check stats the sentinel in the local cache only.
- :129-135: after copying, the sentinel is written unconditionally, before returning.
src/cli/commands/datastore_config_migrate.ts:- :126-181: the migration runs inside a root unit of work. The push runs only after the body has completed (
pushWhen: "completed"), so the sentinel is already on disk when it starts. - :153-161: the
alreadyMigratedbranch returns early.pushedstays false, so the root's push does nothing. - :129-133: the push is a plain
pushNamespace. Unlike other managedConfig writes since #2752, a failure is not wrapped inManagedConfigUnpublishedError, so the user sees the raw sync error with no "Run 'swamp datastore sync --push' to publish it."
- :126-181: the migration runs inside a root unit of work. The push runs only after the body has completed (
Recovery exists but is undiscoverable. The failed push leaves the cache marked as having unpushed changes, so an explicit swamp datastore sync --push, or any later config write such as model create, uploads the migrated files. Neither the error nor the "already completed" message says so.
Steps to reproduce
- A repo on
@swamp/s3-datastore(or@swamp/gcs-datastore) against a local emulator. - Make the emulator unreachable, for example
docker compose pause. swamp datastore config migrate: exits non-zero with the raw push error.- Restore the emulator, then run
swamp datastore config migrateagain. It prints "Config migration already completed" (--json:{"alreadyMigrated":true,"managedConfigSet":false}) and exits 0. - A second repo that joins the datastore and pulls finds an empty config tier.
swamp model get <name>for a model the first repo migrated is not found.
This was found by reading the source. It has not yet been reproduced against a paused emulator.
Expected
- A failed push leaves migrate re-runnable. Either:
- the sentinel is written (or published) only after a successful push; or
- a re-run checks the sentinel in the datastore, not only in the local cache, and pushes when the datastore does not have it.
- A failed push fails the way other managedConfig writes do since #2752: non-zero exit, local copy kept, and a message that names
swamp datastore sync --push.
UAT
swamp-uat will cover this in tests/cli/datastore/config/migrate_test.ts as part of swamp-uat#490. The test cuts the datastore during the first migrate, restores it, runs migrate again, and checks that a clone joining afterwards sees the migrated definitions.
Shipped
Click a lifecycle step above to view its details.