Skip to content

fix: treat --shared-server as server mode for DoltMode#2947

Merged
maphew merged 4 commits into
gastownhall:mainfrom
maphew:fix/shared-server-mode-2946
Apr 2, 2026
Merged

fix: treat --shared-server as server mode for DoltMode#2947
maphew merged 4 commits into
gastownhall:mainfrom
maphew:fix/shared-server-mode-2946

Conversation

@maphew

@maphew maphew commented Apr 1, 2026

Copy link
Copy Markdown
Collaborator

Summary

Fixes #2946bd init --shared-server was writing dolt_mode: "embedded" to metadata.json, causing all subsequent commands to use embedded Dolt despite dolt.shared-server: true in config.yaml.

Changes

cmd/bd/init.go (2 fixes):

  • --shared-server now sets initServerMode = true so metadata.json gets DoltMode: "server" and init output correctly shows server mode
  • Init auto-starts the shared Dolt server if not already running, since ResolveServerMode classifies shared-server as ServerModeExternal which suppresses the normal auto-start path

cmd/bd/main.go (1 fix):

  • PersistentPreRun now checks doltserver.IsSharedServerMode() as an override when metadata.json says embedded — handles existing installs without requiring re-init

cmd/bd/store_factory.go (1 fix):

  • isEmbeddedMode() now checks doltserver.IsSharedServerMode() as a fallback. Dolt subcommands (status, start, stop) skip DB init in PersistentPreRun, so serverMode was never set from metadata.json for those commands

Root cause

--shared-server only set the BEADS_DOLT_SHARED_SERVER env var (for directory resolution) but never set initServerMode, so isEmbeddedMode() returned true and metadata.json was written with "embedded".

Test plan

  • bd init --shared-server shows Mode: server in output (was: Mode: embedded)
  • metadata.json has dolt_mode: "server" after init with --shared-server
  • bd dolt start works (no longer errors with "not supported in embedded mode")
  • Existing installs with dolt.shared-server: true but stale metadata.json work without re-init (bd dolt status shows server running)
  • go test ./internal/configfile/ ./internal/doltserver/ passes

🤖 Generated with Claude Code

@hilmes hilmes left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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: sharedServer is parsed at line 79, the new block fires before serverMode = initServerMode at line 137, and before the env var propagation at line 145. The ordering is correct — initServerMode is fully resolved before any consumer reads it.

  • Runtime path: The override fires only when cfg.IsDoltServerMode() returned false (stale metadata.json) AND IsSharedServerMode() returns true (config.yaml or env var says shared). Both serverMode and cmdCtx.ServerMode get 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, so cfg.IsDoltServerMode() returns true directly. The !doltCfg.ServerMode guard prevents the redundant IsSharedServerMode() call.

  • IsSharedServerMode() is well-tested. It checks env var ("1" or "true", case-insensitive) then config.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.

@maphew maphew force-pushed the fix/shared-server-mode-2946 branch 2 times, most recently from 2eb9ad6 to 7679d09 Compare April 2, 2026 18:41
maphew and others added 4 commits April 2, 2026 11:42
…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
@maphew maphew force-pushed the fix/shared-server-mode-2946 branch from 7679d09 to 55a828d Compare April 2, 2026 18:43
@maphew maphew merged commit baa9d02 into gastownhall:main Apr 2, 2026
31 checks passed
@maphew maphew deleted the fix/shared-server-mode-2946 branch April 2, 2026 18:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Beads is using embedded Dolt despite shared-server being set

2 participants