Documentation
¶
Overview ¶
Package configdiff compares the canonical .cloop/config.yaml against the SQLite-mirrored copy stored by Save() (see pkg/config). The two stores diverge whenever:
- The user runs `cloop config set` against a binary that mirrors, then restores the YAML from a backup that predates the SQLite mirror.
- A different cloop binary (one without the mirror code) writes config.yaml, leaving the SQLite copy stale.
- Direct SQL edits or migrations mutate the metadata blob without touching the YAML.
- The YAML is hand-edited but cloop hasn't run Save() yet.
Silent drift between the two leads to "why did my config change not take effect" bug reports — Load() prefers YAML when present, but tools that query the SQLite mirror (analytics, the doctor command, third-party inspection scripts) see the stale copy. This package exposes the drift explicitly so users can resolve it deliberately.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func IsSensitive ¶
IsSensitive returns true when the given dotted config path likely names a secret. Used by Render() to mask values before printing the diff.
func MaskSecret ¶
MaskSecret returns a redacted form of a secret value suitable for human display. Mirrors the masking convention of cmd/config_cmd.go's maskSecret — keep the first/last 4 chars when long enough, otherwise return ****.
func Render ¶
Render formats a Report as a multi-line, human-readable string. Secret values (api keys, tokens) are masked. Returns an empty string when no drift is present (callers usually short-circuit before calling Render).
func Sync ¶
Sync resolves drift in the chosen direction. Returns an error when the chosen source is not available (e.g. FromDB with no mirror, FromYAML with no YAML file). The opposite store is overwritten atomically — for FromYAML via config.Save (which already mirrors); for FromDB via writing the blob out and calling config.Save to round-trip via the validated, atomic path.
We deliberately go through config.Save rather than writing raw bytes so:
- The validateAndClamp pass runs on the rehydrated config — operators can't accidentally restore a stale-and-invalid blob.
- 0o600 perms and atomic rename behaviour are inherited.
- The reverse mirror is also refreshed (FromDB writes YAML + re-mirrors, so any missing fields in the blob are normalised on the way through).
Types ¶
type DiffKind ¶
type DiffKind string
DiffKind describes how a key differs between the two stores.
const ( // Added means the key exists in the right side (DB) but not the left (YAML). Added DiffKind = "added" // Removed means the key exists in the left side (YAML) but not the right (DB). Removed DiffKind = "removed" // Changed means the key exists in both with different values. Changed DiffKind = "changed" )
type Direction ¶
type Direction string
Direction selects which source wins during Sync.
const ( // FromYAML overwrites the SQLite mirror with the YAML contents (default). // This is the natural recovery path because YAML is the canonical // human-edited source — Load() already prefers it. FromYAML Direction = "from-yaml" // FromDB overwrites the YAML with the SQLite mirror. Used to recover // when the YAML has been corrupted or accidentally truncated and the // SQLite blob has the last good copy. FromDB Direction = "from-db" )
type Entry ¶
Entry is a single keyed difference between YAML and DB.
Path is a dotted key path into the YAML structure (e.g. "anthropic.api_key", "rate_limit.burst"). YAMLValue and DBValue are the human-readable string forms of each side; either may be empty when the kind is Added/Removed.
type Report ¶
type Report struct {
// YAMLPresent is true when .cloop/config.yaml exists on disk.
YAMLPresent bool
// DBPresent is true when .cloop/state.db exists AND has a non-empty config blob.
DBPresent bool
// Entries lists every keyed difference, ordered by Path.
Entries []Entry
}
Report is the result of comparing the two stores.
func Compute ¶
Compute compares the two stores and returns a structured Report. Returns an error only on unexpected I/O or parse failures; "absent" is normal state and reflected via the booleans on Report.