fix: treat --shared-server as server mode for DoltMode#2947
Conversation
hilmes
left a comment
There was a problem hiding this comment.
Review: fix: treat --shared-server as server mode for DoltMode
Verdict: LGTM with one gap to flag
The Problem
bd init --shared-server set the BEADS_DOLT_SHARED_SERVER env var (for directory resolution) but never set initServerMode = true. Since initServerMode controls what gets written to metadata.json, the file ended up with dolt_mode: "embedded". Every subsequent command read that and operated in embedded mode — including bd dolt start which errored with "not supported in embedded mode."
The Fix
2 files, +13 −0. Two complementary patches:
1. Init fix (init.go, +6 lines):
if sharedServer {
initServerMode = true
}Inserted after the BEADS_DOLT_SERVER_MODE=1 env var check, before serverMode = initServerMode propagates to the global. Now bd init --shared-server writes dolt_mode: "server" to metadata.json. Straightforward.
2. Runtime fix (main.go, +6 lines):
if !doltCfg.ServerMode && doltserver.IsSharedServerMode() {
doltCfg.ServerMode = true
}Inserted between cfg.IsDoltServerMode() and serverMode = doltCfg.ServerMode in PersistentPreRunE. Handles existing installs that already have stale dolt_mode: "embedded" in metadata.json without requiring a re-init. IsSharedServerMode() checks BEADS_DOLT_SHARED_SERVER env var first, then dolt.shared-server in config.yaml.
Correctness ✅
-
Init path:
sharedServeris parsed at line 79, the new block fires beforeserverMode = initServerModeat line 137, and before the env var propagation at line 145. The ordering is correct —initServerModeis fully resolved before any consumer reads it. -
Runtime path: The override fires only when
cfg.IsDoltServerMode()returned false (stale metadata.json) ANDIsSharedServerMode()returns true (config.yaml or env var says shared). BothserverModeandcmdCtx.ServerModeget the corrected value because the override inserts before those assignments. -
No double-setting. New installs (post-fix) will have
dolt_mode: "server"in metadata.json, socfg.IsDoltServerMode()returns true directly. The!doltCfg.ServerModeguard prevents the redundantIsSharedServerMode()call. -
IsSharedServerMode()is well-tested. It checks env var ("1"or"true", case-insensitive) thenconfig.GetBool("dolt.shared-server"). Both sources are idempotent reads.
Edge Cases 🔍
1. --shared-server combined with --server. Both set initServerMode = true. No conflict — idempotent.
2. Existing install: config.yaml has dolt.shared-server: true, metadata.json has dolt_mode: "embedded". The runtime fix catches this: cfg.IsDoltServerMode() returns false, IsSharedServerMode() returns true, override activates. Correct.
3. Existing install: neither config.yaml nor env var indicates shared server, metadata.json says embedded. IsSharedServerMode() returns false, no override. Correctly remains embedded.
⚠️ Gap: loadServerModeFromConfig() at line 158
There is a second code path that resolves server mode — loadServerModeFromConfig() at line 158, called at line 429, before the no-db command early return. It reads cfg.IsDoltServerMode() and sets serverMode + cmdCtx.ServerMode, but does not have the shared-server override.
This means no-db commands (bd doctor, bd bootstrap, bd dolt status, bd context, bd dolt start) that exit through the early return at the no-db check will still see serverMode = false for stale metadata.json installs with dolt.shared-server: true.
In particular: bd dolt start is listed in the no-db command set. If it checks isEmbeddedMode() (which reads the global serverMode), it will still error for stale installs. The PersistentPreRun override only applies to commands that continue past the no-db guard.
Consider applying the same override to loadServerModeFromConfig():
func loadServerModeFromConfig() {
beadsDir := beads.FindBeadsDir()
if beadsDir == "" {
return
}
cfg, err := configfile.Load(beadsDir)
if err != nil || cfg == nil {
return
}
sm := cfg.IsDoltServerMode()
if !sm && doltserver.IsSharedServerMode() {
sm = true
}
serverMode = sm
if cmdCtx != nil {
cmdCtx.ServerMode = sm
}
}This would close the gap for all command paths.
Performance ✅
IsSharedServerMode() is an env var read + a config key lookup. Negligible. Guarded by !doltCfg.ServerMode so it only runs when needed.
Style ✅
- Comments reference the issue number (GH#2946). Clear.
- Minimal diff — no unrelated changes.
- No tests added, though the test plan in the PR body is manual. For a 2-line logic fix with clear before/after behavior, manual verification is reasonable.
Ship the init fix and the PersistentPreRun override. Consider extending loadServerModeFromConfig() with the same shared-server override to close the no-db command gap.
2eb9ad6 to
7679d09
Compare
…ctive (GH#2949) Root cause: ResolveServerMode() and IsDoltServerMode() checked metadata.json dolt_mode=embedded BEFORE runtime env vars, so stale persisted metadata silently overrode active shared-server config. Fixes: - ResolveServerMode: env vars (BEADS_DOLT_SERVER_MODE, BEADS_DOLT_SHARED_SERVER) now checked before metadata.json, preventing stale embedded override - IsDoltServerMode: now checks BEADS_DOLT_SHARED_SERVER env var (shared-server implies server-backed storage) - warnSharedServerEmbeddedMismatch -> repairSharedServerEmbeddedMismatch: auto-repairs stale dolt_mode=embedded in metadata.json instead of just warning - Added 6 regression tests covering the upgrade path Closes gastownhall#2949 Amp-Thread-ID: https://ampcode.com/threads/T-019d4b84-cddd-725a-a3c6-ee7e3631f2aa Co-authored-by: Amp <amp@ampcode.com>
…astownhall#2946) --shared-server sets BEADS_DOLT_SHARED_SERVER for directory resolution but never set initServerMode, so metadata.json recorded DoltMode as "embedded" and all subsequent commands used embedded Dolt despite config.yaml having dolt.shared-server: true. Also override metadata.json at runtime when dolt.shared-server is set, so existing installs with stale metadata.json are handled without re-init. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Two additional fixes for GH#2946: 1. Init auto-starts the shared Dolt server if not already running, since ResolveServerMode classifies shared-server as External which suppresses the normal auto-start path. 2. isEmbeddedMode() now checks doltserver.IsSharedServerMode() as a fallback. Dolt subcommands (status, start, stop) skip DB init in PersistentPreRun, so serverMode is never set from metadata.json. Without this, "bd dolt status" would still report embedded mode even with dolt.shared-server: true in config.yaml. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Closes the gap flagged in PR review: no-db commands (bd dolt start, bd dolt status, bd doctor, etc.) go through loadServerModeFromConfig() which didn't have the shared-server override for stale metadata.json. This ensures isEmbeddedMode() returns false for all command paths when dolt.shared-server is true in config.yaml, not just commands that pass the no-db guard in PersistentPreRun. GH#2946 Co-authored-by: Amp <amp@ampcode.com> Amp-Thread-ID: https://ampcode.com/threads/T-019d4f6f-01f8-72d4-b474-f75d7909b8b9
7679d09 to
55a828d
Compare
Summary
Fixes #2946 —
bd init --shared-serverwas writingdolt_mode: "embedded"to metadata.json, causing all subsequent commands to use embedded Dolt despitedolt.shared-server: truein config.yaml.Changes
cmd/bd/init.go(2 fixes):--shared-servernow setsinitServerMode = trueso metadata.json getsDoltMode: "server"and init output correctly shows server modeResolveServerModeclassifies shared-server asServerModeExternalwhich suppresses the normal auto-start pathcmd/bd/main.go(1 fix):PersistentPreRunnow checksdoltserver.IsSharedServerMode()as an override when metadata.json says embedded — handles existing installs without requiring re-initcmd/bd/store_factory.go(1 fix):isEmbeddedMode()now checksdoltserver.IsSharedServerMode()as a fallback. Dolt subcommands (status,start,stop) skip DB init inPersistentPreRun, soserverModewas never set from metadata.json for those commandsRoot cause
--shared-serveronly set theBEADS_DOLT_SHARED_SERVERenv var (for directory resolution) but never setinitServerMode, soisEmbeddedMode()returned true and metadata.json was written with"embedded".Test plan
bd init --shared-servershowsMode: serverin output (was:Mode: embedded)dolt_mode: "server"after init with--shared-serverbd dolt startworks (no longer errors with "not supported in embedded mode")dolt.shared-server: truebut stale metadata.json work without re-init (bd dolt statusshows server running)go test ./internal/configfile/ ./internal/doltserver/passes🤖 Generated with Claude Code