Skip to content

config: route the builtin through the registry and repair the designed subsystem syncs#358

Merged
berrym merged 5 commits into
masterfrom
config/central-config-correctness
Jun 25, 2026
Merged

config: route the builtin through the registry and repair the designed subsystem syncs#358
berrym merged 5 commits into
masterfrom
config/central-config-correctness

Conversation

@berrym

@berrym berrym commented Jun 25, 2026

Copy link
Copy Markdown
Owner

Summary

First, non-destructive phase of the CREG/config correctness overhaul (from a 64-agent audit). The central unified configuration system is a deliberate lush design pillar -- a single, discoverable source of truth that every surface (the config builtin, display lle …, setopt, TOML) is meant to synchronize with. Several of those syncs were silently broken because keys were never registered. This makes them work; it removes nothing.

Five commits, each verified:

  1. config: resolve dotted registry keys from the config builtinconfig get/set iterated only the legacy config_options[] array and never consulted the registry, so registry-only keys (completion.menu_shadow_ghost, chain_directories) reported "Unknown configuration key". Adds a registry fallback after the legacy lookup; purely additive.

  2. config: register the display hot-reload and pager keysdisplay lle hot-reload / display lle pager write display.theme_hot_reload and display.lle.pager.* to the registry, and the sync hooks already mirror them, but the keys were unregistered so every write/sync was a CREG_ERROR_NOT_FOUND no-op. Registering them makes the display↔config sync work both directions.

  3. config: apply per-mode defaults to the runtime on init and mode changeapply_mode_defaults seeded the registry but nothing synced it into the runtime struct on fresh install or on a mode switch, so mode-aware options didn't follow the active mode. Adds the missing sync_to_runtime.

  4. config: register completion.match_mode and threshold — these lived only in the legacy table, so the set_mode_default("completion.match_mode", …) calls failed silently and lush's curated fuzzy default never applied. Registers them with string↔enum sync; with commit 3, lush now resolves to fuzzy and posix/bash/zsh to prefix.

  5. config: add an lle registry section for history deduplicationdisplay lle history writes lle.enable_deduplication, lle.dedup_* to a section CREG didn't have. Adds the lle section so those settings persist and round-trip.

Verification

  • meson test: 156/156, zero warnings (werror).
  • Manual: config get/set round-trips registry-only keys; display lle hot-reload off / pager min-lines 12 / history dedup off persist to config save and reload from TOML; completion.match_mode = fuzzy in lush and prefix in posix/bash/zsh, observable via config get and $COMPLETION_MATCH_MODE.

Not in this PR

The destructive/migration phases (remove 51 confirmed-dead/aspirational keys, migrate the remaining wired legacy-only keys into CREG, regenerate the embedded TOML, retire the legacy array) come next, with the aspirational-key removal list reviewed before anything is deleted.

🤖 Generated with Claude Code

berrym added 5 commits June 25, 2026 12:01
config get/set iterated only the legacy config_options[] array and never
consulted the CREG registry, so registry-only keys -- completion.chain_directories,
completion.menu_shadow_ghost, and every future CREG-only key -- reported "Unknown
configuration key". The central configuration system is meant to be the single,
discoverable source of truth every surface shares; the builtin bypassing it broke
that contract.

Add a registry fallback to config_get_value and config_set_value: after the legacy
table misses, consult config_registry_get/set. get prints by value type; set probes
the declared type, parses the text against it (boolean widened to true/1/on/yes and
false/0/off/no, integers via strtoll with overflow and trailing-garbage checks),
writes through the registry (firing its change notification), then mirrors into the
runtime struct and applies. Every previously working key resolves exactly as before;
the fallback runs only when the legacy table misses, so this is purely additive and
makes the CREG-only keys reachable without changing existing behavior.

First step toward a single config table: the legacy array shrinks as its keys
migrate into the registry, after which this fallback becomes the primary path.
display lle hot-reload and display lle pager write their state to both the runtime
struct and the config registry, and display_sync_to/from_runtime already mirror
display.theme_hot_reload and display.lle.pager.{enabled,min_lines,wrap_search}
between the registry and the struct. But those four keys were never registered in
the display section, so every registry write and every sync returned
CREG_ERROR_NOT_FOUND and silently did nothing: the builtins updated the struct
while the registry stayed empty, the settings never persisted to lushrc.toml, and
TOML values for them were dropped on load.

Register the four keys in display_options[] with defaults matching
config_set_defaults. The existing sync hooks become live, so the designed
display-builtin to central-config synchronization works end to end both ways: a
display lle change persists through config save, and a lushrc.toml value reaches
the runtime and shows in display lle status.
config_registry_apply_mode_defaults seeds the registry with the active mode's
curated defaults, but nothing pushed them into the runtime struct the engine
reads. On a fresh install with no lushrc the user-config load path -- the only
caller of config_registry_sync_to_runtime in that flow -- never runs, so the
struct kept the generic config_set_defaults values; and apply_mode_preset
re-seeded the registry on a mode switch without syncing, stranding the previous
mode's value in the struct. Mode-aware options (history.search_mode, the Ctrl-R
finder settings, and -- once registered -- completion.match_mode) silently did
not follow the active mode.

Call config_registry_sync_to_runtime() right after apply_mode_defaults in
config_init (before the user-config existence checks), and add
sync_to_runtime + config_apply_settings after the re-seed in apply_mode_preset.
The active mode's defaults now reach the struct on startup and change with the
mode mid-session; user config still layers on top via the later load-path sync.
The completion match predicate and fuzzy-accept threshold lived only in the
legacy config_options[] array and the runtime struct, never in the CREG section.
So the four config_registry_set_mode_default("completion.match_mode", ...) calls
silently failed against an unregistered key, and lush's curated fuzzy default
never applied -- the struct kept the generic prefix default in every mode. A
stale completion_sync_to_runtime comment claimed the key's "registry storage
points directly at config.completion_match_mode", describing a registration and
a storage-pointer model that do not exist.

Register completion.match_mode (string: prefix/substring/fuzzy) and
completion.threshold (integer) in completion_options[], and add real
string<->enum sync in completion_sync_to/from_runtime using the existing
completion_match_mode_mappings table. With the registry sync from the companion
change, lush now resolves to fuzzy and posix/bash/zsh to prefix, both at startup
and across mode switches, observable via config get and the COMPLETION_MATCH_MODE
script variable.
display lle history writes lle.enable_deduplication, lle.dedup_scope,
lle.dedup_strategy, lle.dedup_navigation, and lle.dedup_navigation_unique to the
registry, but no "lle" section was ever registered, so every config_registry_set
returned CREG_ERROR_NOT_FOUND: the builtin updated the struct while the registry
stayed empty and the settings never persisted to lushrc.toml.

Register an lle section with the six dedup keys (defaults matching
config_set_defaults), carrying the two enums (scope, strategy) as strings and
translating them onto the engine enums in lle_sync_to/from_runtime via the
shared lle_dedup_scope_mappings / lle_dedup_strategy_mappings tables. The
display lle history settings now persist through config save and load from
lushrc.toml.
@codecov

codecov Bot commented Jun 25, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 27.90698% with 93 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
src/config.c 26.77% 93 Missing ⚠️

📢 Thoughts on this report? Let us know!

@berrym berrym merged commit 058bd3e into master Jun 25, 2026
5 checks passed
@berrym berrym deleted the config/central-config-correctness branch June 25, 2026 16:40
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.

1 participant