◐ Off-By-One · answer catalog

go-config-startup-validation

2 answer(s)godockergodocker

go-config-startup-validation

📦 Source in repository (JSON)

Answer 1

The project was reconstructed at ~/guard (Go 1.26, no pre-existing repo in the environment). The fix addresses C-GAP-001..003 in three parts.

1. internal/config/config.go — new ApplyStartupValidations() (fixes C-GAP-002 compression on DeepSeek, C-GAP-003 missing API key):

// ApplyStartupValidations inspects the configuration for known
// misconfigurations, corrects the ones it can (mutating c), and returns
// human-readable warnings for the caller to surface via slog.Warn.
func (c *Config) ApplyStartupValidations() []string {
    var warnings []string

    // C-GAP-002: DeepSeek has no embeddings endpoint. If compression is
    // enabled with the default text-embedding-3-small model on that
    // backend, disable it and explain why.
    if c.CompressionEnabled &&
        strings.EqualFold(c.LLMBackend, BackendDeepSeek) &&
        c.EmbeddingsModel == EmbeddingModelTextEmbedding3Small {
        c.CompressionEnabled = false
        warnings = append(warnings, fmt.Sprintf(
            "compression disabled: backend %q has no embeddings endpoint for model %q; "+
                "set --compression=false / compression.enabled=false, switch to a backend "+
                "that exposes embeddings, or configure an embeddings-capable model",
            c.LLMBackend, c.EmbeddingsModel))
    }

    // C-GAP-003: surface a missing LLM API key at startup.
    if strings.TrimSpace(c.LLMAPIKey) == "" {
        warnings = append(warnings,
            "LLM API key is not set: LLM requests will fail at runtime "+
                "(set LLM_API_KEY or pass --llm-api-key)")
    }
    return warnings
}

2. internal/server/server.go — RunServer logs warnings via slog.Warn and gates the compression worker:

func RunServer(cfg *config.Config, logger *slog.Logger) error {
    warnings := cfg.ApplyStartupValidations()
    for _, w := range warnings {
        logger.Warn("startup validation", "detail", w)
    }
    if cfg.CompressionEnabled {
        startCompressionWorker(logger)
    } else {
        logger.Info("compression worker not started (compression disabled)")
    }
    return nil
}

3. Makefile — dev targets use --db-url (C-GAP-001; the CLI in cmd/server/main.go registers --db-url, never --db):

dev: build
    $(BIN) --db-url "$(DB_URL)"

dev-openai: build
    $(BIN) --db-url "$(DB_URL)" --llm-backend openai --llm-api-key sk-test-1234

Evidence & signatures

**Unit tests — 9/9 pass** (`go test -count=1 ./...`), covering:

| Test | Covers |
|---|---|
| `TestApplyStartupValidations_DisablesCompressionOnDeepSeek` | C-GAP-002 correction: compression off + warning explaining missing embeddings endpoint |
| `TestApplyStartupValidations_KeepsCompressionOnEmbeddingBackend` | OpenAI backend → compression stays on, no compression warning (no false positive) |
| `TestApplyStartupValidations_RespectsExplicitDisable` | User-disabled compression is never re-enabled / re-warned |
| `TestApplyStartupValidations_DeepSeekNonDefaultEmbeddingModelKeepsCompression` | Non-default model is not touched (only the exact default triggers correction) |
| `TestApplyStartupValidations_WarnsOnMissingAPIKey` | C-GAP-003: warn when key empty; no warning when set |
| `TestRunServer_LogsWarningsViaSlogWarn` | Both warnings emitted at `level=WARN` |
| `TestRunServer_DoesNotStartCompressionWorkerWhenDisabled` | Worker stub not invoked after correction; config mutated |
| `TestRunServer_StartsCompressionWorkerWhenSupported` | Worker starts on embeddings-capable backend |
| `TestCLIFlagIsDbUrl` | C-GAP-001: `--db-url` registered and parses; legacy `--db` absent |

**Live `make dev` run** (default DeepSeek config, `LLM_API_KEY` unset) — WARNs printed, compression worker NOT started, exit 0:

```
level=WARN msg="startup validation" detail="compression disabled: backend \"deepseek\" has no embeddings endpoint for model \"text-embedding-3-small\"; ..."
level=WARN msg="startup validation" detail="LLM API key is not set: LLM requests will fail at runtime (set LLM_API_KEY or pass --llm-api-key)"
level=INFO msg="compression worker not started (compression disabled)"
```

Edge cases exercised in live runs:
- **Env key present** (this machine has `LLM_API_KEY` set): only the compression WARN prints — the missing-key warning is correctly suppressed, proving no false positives.
- **`make dev-openai`**: no compression WARN, `compression worker started` — compression only disabled where it would actually fail.

**Guard script — `guard PASS 5/5`** (`make guard`, exit 0): (1) Makefile recipes use `$(BIN) --db-url`, no `$(BIN) --db `; (2) `config.ApplyStartupValidations` exported; (3)–(5) behavioral checks via the unit tests above. One interim guard failure was a regex artifact (it matched the comment "CLI has no --db flag"); fixed by scoping check #1 to recipe lines with `grep -F` on `$(BIN)`.
{"model": "deepseek-v4-flash", "problem_class": "go-config-startup-validation", "result": "passed", "tests": 9}

Answer 2

The project was reconstructed at ~/guard (Go 1.26, no pre-existing repo in the environment). The fix addresses C-GAP-001..003 in three parts.

1. internal/config/config.go — new ApplyStartupValidations() (fixes C-GAP-002 compression on DeepSeek, C-GAP-003 missing API key):

// ApplyStartupValidations inspects the configuration for known
// misconfigurations, corrects the ones it can (mutating c), and returns
// human-readable warnings for the caller to surface via slog.Warn.
func (c *Config) ApplyStartupValidations() []string {
    var warnings []string

    // C-GAP-002: DeepSeek has no embeddings endpoint. If compression is
    // enabled with the default text-embedding-3-small model on that
    // backend, disable it and explain why.
    if c.CompressionEnabled &&
        strings.EqualFold(c.LLMBackend, BackendDeepSeek) &&
        c.EmbeddingsModel == EmbeddingModelTextEmbedding3Small {
        c.CompressionEnabled = false
        warnings = append(warnings, fmt.Sprintf(
            "compression disabled: backend %q has no embeddings endpoint for model %q; "+
                "set --compression=false / compression.enabled=false, switch to a backend "+
                "that exposes embeddings, or configure an embeddings-capable model",
            c.LLMBackend, c.EmbeddingsModel))
    }

    // C-GAP-003: surface a missing LLM API key at startup.
    if strings.TrimSpace(c.LLMAPIKey) == "" {
        warnings = append(warnings,
            "LLM API key is not set: LLM requests will fail at runtime "+
                "(set LLM_API_KEY or pass --llm-api-key)")
    }
    return warnings
}

2. internal/server/server.go — RunServer logs warnings via slog.Warn and gates the compression worker:

func RunServer(cfg *config.Config, logger *slog.Logger) error {
    warnings := cfg.ApplyStartupValidations()
    for _, w := range warnings {
        logger.Warn("startup validation", "detail", w)
    }
    if cfg.CompressionEnabled {
        startCompressionWorker(logger)
    } else {
        logger.Info("compression worker not started (compression disabled)")
    }
    return nil
}

3. Makefile — dev targets use --db-url (C-GAP-001; the CLI in cmd/server/main.go registers --db-url, never --db):

dev: build
    $(BIN) --db-url "$(DB_URL)"

dev-openai: build
    $(BIN) --db-url "$(DB_URL)" --llm-backend openai --llm-api-key sk-test-1234

Evidence & signatures

**Unit tests — 9/9 pass** (`go test -count=1 ./...`), covering:

| Test | Covers |
|---|---|
| `TestApplyStartupValidations_DisablesCompressionOnDeepSeek` | C-GAP-002 correction: compression off + warning explaining missing embeddings endpoint |
| `TestApplyStartupValidations_KeepsCompressionOnEmbeddingBackend` | OpenAI backend → compression stays on, no compression warning (no false positive) |
| `TestApplyStartupValidations_RespectsExplicitDisable` | User-disabled compression is never re-enabled / re-warned |
| `TestApplyStartupValidations_DeepSeekNonDefaultEmbeddingModelKeepsCompression` | Non-default model is not touched (only the exact default triggers correction) |
| `TestApplyStartupValidations_WarnsOnMissingAPIKey` | C-GAP-003: warn when key empty; no warning when set |
| `TestRunServer_LogsWarningsViaSlogWarn` | Both warnings emitted at `level=WARN` |
| `TestRunServer_DoesNotStartCompressionWorkerWhenDisabled` | Worker stub not invoked after correction; config mutated |
| `TestRunServer_StartsCompressionWorkerWhenSupported` | Worker starts on embeddings-capable backend |
| `TestCLIFlagIsDbUrl` | C-GAP-001: `--db-url` registered and parses; legacy `--db` absent |

**Live `make dev` run** (default DeepSeek config, `LLM_API_KEY` unset) — WARNs printed, compression worker NOT started, exit 0:

```
level=WARN msg="startup validation" detail="compression disabled: backend \"deepseek\" has no embeddings endpoint for model \"text-embedding-3-small\"; ..."
level=WARN msg="startup validation" detail="LLM API key is not set: LLM requests will fail at runtime (set LLM_API_KEY or pass --llm-api-key)"
level=INFO msg="compression worker not started (compression disabled)"
```

Edge cases exercised in live runs:
- **Env key present** (this machine has `LLM_API_KEY` set): only the compression WARN prints — the missing-key warning is correctly suppressed, proving no false positives.
- **`make dev-openai`**: no compression WARN, `compression worker started` — compression only disabled where it would actually fail.

**Guard script — `guard PASS 5/5`** (`make guard`, exit 0): (1) Makefile recipes use `$(BIN) --db-url`, no `$(BIN) --db `; (2) `config.ApplyStartupValidations` exported; (3)–(5) behavioral checks via the unit tests above. One interim guard failure was a regex artifact (it matched the comment "CLI has no --db flag"); fixed by scoping check #1 to recipe lines with `grep -F` on `$(BIN)`.
{"model": "deepseek-v4-flash", "problem_class": "go-config-startup-validation", "result": "passed", "tests": 9}
Generated from the verified corpus · MIT licensedBack to the catalog