Skip to main content
← Back to list
01Issue
BugShippedSwamp CLIPublic
Assigneesstack72

Relationships

#3696 v3 join check refuses a fresh managedConfig checkout on S3/GCS: the datastore extension's auto-install writes the managed lockfile first (regression of #3690)

Opened by stack72 · 10/21/2026· Shipped 10/21/2026

Background

swamp-club#3690 (2d4b4e970, release 20261021.000812.0) added a join check: the first time a checkout opens a v3 datastore (no _read_model_v3 state yet), swamp refuses if the checkout's .swamp/ already holds records, because a v3 datastore starts empty. It runs in resolveDatastoreForRepo after the format guard, and in holdV3Writer and v3RepositoryFactoryConfig. Files a checkout keeps as its own are skipped (isCheckoutLocalKey in src/infrastructure/datastore_v3/record_path_guard.ts).

The bug (regression of #3690)

A fresh checkout of a managedConfig repo on an S3 or GCS v3 datastore is refused on its very first command. No user data is involved. The check counts a file swamp itself has just written.

Seen in swamp-uat: every Datastore UAT run since 20261021.000812.0-sha.2d4b4e97 fails all eight s3-v3 and gcs-v3 shards, 64 failures, for example run 39522050355 on 20261021.003131.0-sha.764fd4d5. The last green run was 20261020.231557.0-sha.bc7bbaa6. The filesystem, filesystem-v3, s3 and gcs shards stay green. Every failure is a managedConfig row (withClonePair managedConfig, every_mutation_syncs … [managed-config], managed_config_test), with:

Command "swamp datastore status" failed (exit 1):
Error: /tmp/swamp-uat-…/.swamp holds records (config), but .swamp.yaml now names a v3 datastore. A v3 datastore starts empty … Run `swamp doctor datastores --repair` …
  Resolving   @swamp/s3-datastore not found locally, searching registry...
 Installing   @swamp/s3-datastore@2026.10.20.2 …

Why:

  1. In a fresh checkout the datastore extension isn't installed, so resolveDatastoreForRepo auto-installs it from the registry before the join check runs.
  2. With managedConfig, that install writes the managed lockfile .swamp/config/upstream_extensions.json (paths.ts "Returns the .swamp/config/upstream_extensions.json path").
  3. isCheckoutLocalKey skips config/pulled-extensions/… but not the lockfile, so the join check counts config as holding records and refuses.
  4. filesystem-v3 doesn't auto-install anything, so it isn't hit. #3690's own bucket test registers the extension directly, so it never ran the auto-install.

Impact: every teammate joining a managedConfig repo on S3/GCS v3 is refused on their first command. Following the suggested doctor datastores --repair -y moves swamp's freshly installed lockfile aside for nothing, and the next command re-installs it and is refused again.

What to do

  1. Run the join check before anything swamp writes on that command, which means before the datastore extension's auto-install in resolveDatastoreForRepo. The check needs only .swamp.yaml's format and namespace and the local .swamp/; it doesn't need the provider. Keep the later calls in holdV3Writer and v3RepositoryFactoryConfig as they are.
  2. Count the managed lockfile (config/upstream_extensions.json) as the checkout's own in isCheckoutLocalKey (or in the join check's own-file rule). swamp regenerates it, and on v3 the datastore holds its committed copy. That keeps any other early write of it from tripping the check. Check whether anything else swamp writes under .swamp/config/ before the first open needs the same: the extension install's other files, the managed config's local index.
  3. Leave genuine records refused. A checkout holding v2 definitions, workflows, vault configs or data is still refused, as #3690 intends.

Tests

Each must fail on main first.

  • Integration: a fresh managedConfig checkout of a bucket v3 datastore, on the in-memory remote or the opt-in S3 run, with the datastore extension auto-installed rather than pre-registered. Its first command (datastore status, then a write) succeeds, and its v3 state is created.
  • Unit: isCheckoutLocalKey(["config", "upstream_extensions.json"]) is true. A config/ file that is a real record (a definition or vault config under the managed config tier) is still counted.
  • The #3690 refusal still holds: a checkout with v2 records is refused, managedConfig or not.
  • swamp-uat: the s3-v3/gcs-v3 Datastore UAT shards pass unchanged against a build of the fix.

Severity: high. A regression in a published release that blocks every new checkout of a managedConfig repo on v3 buckets. v3 is opt-in, so fix it promptly rather than as an emergency.

Blocked by: nothing.

02Bog Flow
✓OPEN✓TRIAGED✓IN PROGRESS✓SHIPPED+ 1 MOREASSIGNED+ 5 MOREREVIEW+ 10 MOREPR_MERGED+ 2 MORESESSION_SUMMARIZED

Shipped

10/21/2026, 1:48:09 AM

Click a lifecycle step above to view its details.

03Sludge Pulse
stack72 assigned stack7210/21/2026, 1:12:10 AM

Sign in to post a ripple.