Relationships
#834 fix: datastore sync --push deletes the namespace registration manifest (canonical namespace flow un-registers itself)
Opened by anthony · 6/26/2026· Shipped 6/26/2026
Summary
swamp datastore sync --push deletes the {namespace}/.namespace.json registration manifest from the bucket. registerNamespace() writes the manifest directly to the object store and never materializes it into the local cache, so a namespace-scoped push treats it as a remote orphan and removes it. The canonical multi-repo flow — namespace set -> namespace migrate --confirm -> sync --push — therefore silently UN-registers the namespace it just registered: namespace list returns empty and repoId conflict-detection is defeated.
This is NOT "namespace set doesn't call registerNamespace" — it does, correctly (per #542). The manifest is written by set, survives migrate (local-only), and is destroyed by the following push.
Repro (minimal; @swamp/gcs-datastore; isolated throwaway prefix)
swamp repo init
swamp extension pull @swamp/gcs-datastore
swamp datastore setup extension @swamp/gcs-datastore --config '{"bucket":"B","prefix":"P","projectId":"..."}' # NO namespace
swamp datastore namespace set ns
# -> gs://B/P/ns/.namespace.json EXISTS
swamp datastore namespace migrate --confirm
# -> manifest still EXISTS (migrate is local-only; prints "run sync --push")
swamp datastore sync --push
# -> "Pushed 1 files"; gs://B/P/ns/.namespace.json is now GONE
swamp datastore namespace list # -> "No namespaces registered in this datastore"Control: set -> push WITHOUT an intervening migrate pushes 0 files and does NOT delete the manifest. The deletion happens specifically during a push that actually syncs the namespace subtree (checkpointed: manifest present after set and after migrate, absent immediately after push).
Root cause (hypothesis)
registerNamespace (datastores/gcs.ts) writes {namespace}/.namespace.json straight to the bucket; it is not part of the local cache tree. The namespace-scoped push reconciles the remote {namespace}/ subtree against the local cache and deletes remote objects with no local counterpart — including the manifest. Push should treat .namespace.json (and other reserved manifest/index files like .datastore-index.json/.catalog-export.json) as protected, not orphans.
Impact
- The documented canonical flow (
set -> migrate -> sync --push, manual "Add a namespace to an existing repository") destroys its own registration. namespace list-> empty; foreign-catalog discovery (listNamespaces) cannot enumerate the namespace.- repoId conflict-detection is inert: a second repo can claim the same namespace undetected.
- Data isolation (driven by the
.swamp.yamlnamespace, not the manifest) still works, so this is SILENT — the layout looks correct while registration is gone. Re-creating the manifest by hand is only temporary: the nextsync --pushdeletes it again.
Environment
swamp 20260626.005336.0-sha.f302d18e; @swamp/gcs-datastore. Confirmed on a live GCS datastore and reproduced twice in clean throwaway prefixes.
Related
#547 (extensions implement registerNamespace), #542 (namespace set registers manifests), #559 (setup-with-namespace-config path) — this is a distinct sink: push deletes what set wrote.
Upstream repository: https://github.com/systeminit/swamp-extensions
Environment
- Extension:
@swamp/gcs-datastore@2026.06.24.1 - swamp:
20260626.005336.0-sha.f302d18e - OS:
linux(x86_64) - Deno:
2.8.3 - Shell:
/bin/zsh
Shipped
Click a lifecycle step above to view its details.