Skip to main content
← Back to list
01Issue
BugShippedExtensionsPublic
Assigneesstack72

Relationships

#3549 S3/GCS datastores: keep v2 sync off v3 buckets (exclude _litestream/, refuse a format-3 marker) for swamp releases before v20261009.154711.0

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

Background

Datastore rework Phase 4E (swamp-club#3534) makes v3 a datastore format on S3 and GCS. swamp datastore setup extension @swamp/s3-datastore|@swamp/gcs-datastore --format 3 writes a format-3 marker at <prefix>/_control/datastore-format through datastoreControlPlaneStore(). Litestream then replicates each checkout's commits.db under <prefix>/_litestream/<fence>/.

Who is exposed

Only swamp releases from before v20261009.154711.0, the first release with #3189's format guard (c4e65dbe6). Every release from then on reads the marker at <prefix>/_control/datastore-format and refuses format 3 on S3, GCS and extension datastores before it writes anything.

An older binary sees a v3 bucket as v2. With no .datastore-index.json, the v2 sync service lists the whole bucket. isInternalCacheFile skips _control/ and _blobs/ but not _litestream/, so it publishes a v2 index over Litestream's objects, pulls the LTX files into its cache, and can push them back as files to sync.

Why the fix belongs in the extensions

Extensions are pinned per repo. A clone of a v3 bucket repo has a lockfile pinning the extension at 2026.10.16.1 or later, and an old binary loads that pinned extension. So a guard in the extension covers binaries that core can no longer fix.

Scope (both on S3 and GCS, one extension release)

  1. Exclude _litestream/ from the file sync, in isInternalCacheFile, as _blobs/ already is (#3492). Do this regardless of part 2: today nothing stops a v2 pull from downloading LTX files into a cache, or a push from treating them as files to sync.
  2. Refuse a v3 bucket in the sync service itself, as defence in depth for binaries older than the guard. createSyncService (or the first pull or push) reads the root marker and refuses format 3 or higher with an "upgrade swamp" message, before writing anything.

Not a blocker

It does not block 4E (swamp-club#3534). E's setup keeps relying on the core guard for every current binary. Ideally this release lands before v3 on buckets is announced, alongside Phase 4 H and I.

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

Shipped

10/16/2026, 8:45:06 PM

Click a lifecycle step above to view its details.

03Sludge Pulse
stack72 assigned stack7210/16/2026, 6:37:29 PM
Editable. Press Enter to edit.

system commented 10/16/2026, 4:49:28 PM

Classified automatically when this issue was filed.

  • Source: Extensions

If you feel this classification is incorrect, add a ripple to tell us so.

stack72 commented 10/16/2026, 4:52:52 PM

Review note on part 2: refuse at the first pull or push, not at createSyncService construction. A construction-time refusal turns any path in new core that still builds a sync service for a v3 bucket (a status or health check, a doctor path, something #3534 misses) into a hard failure for current binaries. Refusing at the first pull or push still stops a pre-guard binary before it publishes an index or moves LTX files. Add a test that a sync service built for a format-3 bucket constructs fine, and refuses pullChanged / pushChanged / preparePush with the upgrade message, writing nothing. Ordering: swamp-club#3550 (the #3546 regression) touches the same *_cache_sync.ts files and should land first; rebase onto it.

Sign in to post a ripple.