Skip to content

tui: align typed config and schema with the live value spaces - #5843

Merged
4 commits merged into
mainfrom
fix/config-truth-20260902
Sep 3, 2026
Merged

tui: align typed config and schema with the live value spaces#5843
4 commits merged into
mainfrom
fix/config-truth-20260902

Conversation

@Hmbown

@Hmbown Hmbown commented Sep 2, 2026

Copy link
Copy Markdown
Owner

3 commits: typed theme carries custom themes, orphaned locale keys dropped, typed config/schema aligned. Gates: fmt clean, dead-code PASS at 425. Full matrix via CI.

No-Issue: config-truth cleanup with no single tracking issue.


Note

Low Risk
Mostly config schema, localization, and typed-document parity; changes align defaults and enum values with existing runtime normalization, not new security or data paths.

Overview
Aligns the settings schema, typed /config document, and locale packs with what the TUI already accepts at runtime so saves and the settings UI do not rewrite user choices.

Work surface & rail: Default work_surface_placement is now bottom (schema and typed enum). The typed WorkSurfacePlacementValue adds bottom and off so persisted bottom no longer degrades to top on round-trip. rail_panel in the schema and Settings::set covers the full dock set (background, files, notepad, git, price); pinned is removed from the editor but still accepted and normalized to tasks. Retired whale status indicator is dropped from schema/locales (load migration only).

Themes: UiThemeValue::Custom carries the full custom:<name> selector inside theme, removing the separate custom_theme_name field. claude and solarized-light are added to the typed theme enum with tests that every SELECTABLE_THEMES entry round-trips.

Locales / MessageIds: Hints and choices updated for bottom placement and expanded rail panels; stale keys removed (launch screen, legacy sidebar width/focus, whale, pinned rail labels).

Reviewed by Cursor Bugbot for commit 9a29726. Bugbot is set up for automated code reviews on this repo. Configure here.

CodeWhale Bot added 3 commits September 2, 2026 11:36
UiThemeValue::Custom now holds its full custom:<name> selector, the same
single string /theme and the persisted theme setting use, so the typed
/config document round-trips a custom theme without the sibling
custom_theme_name field. No disk migration: that key was typed-UI only
and was never persisted.
ConfigLabelLaunchScreen belonged to the retired launch_screen setting
(load already accepts and drops it) and ConfigLabelSidebarWidth /
ConfigLabelSidebarFocus belonged to sidebar load-only shims that were
never schema keys and had no hints. Remove the MessageIds and every pack
entry; all 15 packs stay in parity. No behavior change.
- work_surface_placement: the live default is bottom and Settings::set
  accepts top|bottom|left|right|off, but the schema offered
  top|left|right|off defaulting to left, and WorkSurfacePlacementValue
  only had Top|Left|Right — a persisted bottom round-tripped as top
  through the typed /config document and corrupted the setting on save.
  Schema gains bottom (default bottom); the typed enum gains Bottom and
  Off so every live value round-trips.
- rail_panel: the schema offered tasks|agents|context|pinned while the
  dock cycles eight panels and Settings::set rejected five of them.
  Schema and set() now accept tasks, agents, background, files, notepad,
  context, git, price; pinned stays an accepted alias that folds into
  tasks like the load-time migration.
- status_indicator: drop the retired whale choice from the schema; the
  whale|🐳|🐋 → cw load migration stays.
- UiThemeValue gains claude and solarized-light (SELECTABLE_THEMES
  entries the typed document could not round-trip) and a test pins the
  typed value space to every selectable theme.
- packs: widen the two value-enumeration hints, add the bottom placement
  copy, and drop the retired choice keys from all 15 packs.

Test updates: rail_panel_persists_tasks_agents_context_and_pinned
encoded the old four-panel set() and its pinned-verbatim persistence;
it now covers all eight panels and the pinned→tasks fold.
Copilot AI lite review requested due to automatic review settings September 2, 2026 20:15
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, add credits to your account and enable them for code reviews in your settings.

@cursor

cursor Bot commented Sep 2, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_fbce5cf6-959e-4242-956e-14a863b484e2)

@claude

claude Bot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Claude finished @Hmbown's task in 2m 9s —— View job


Review: tui: align typed config and schema with the live value spaces

  • Gather context (diff, changed files, CLAUDE.md rules)
  • Review crates/config/src/settings_schema.rs
  • Review crates/tui/src/config_ui.rs
  • Review crates/tui/src/settings.rs and localization.rs
  • Review locale JSON changes
  • Post findings

Summary

This is a well-scoped rung-2 fix: it edits the existing SETTINGS_SCHEMA, UiThemeValue, and WorkSurfacePlacementValue types to track value spaces that already exist elsewhere in the codebase (RailPanel in crates/tui/src/tui/work_surface/model.rs, SELECTABLE_THEMES in crates/tui/src/palette/themes.rs, Settings::default()), rather than adding a parallel abstraction. I traced each change back to its source of truth and they check out:

  • settings_schema.rs: work_surface_placement default fixed from stale "left" to "bottom", matching Settings::default() (crates/tui/src/settings.rs:573). RAIL_PANEL and WORK_SURFACE_PLACEMENT option lists now match RailPanel::ORDER/WorkSurfacePlacement in work_surface/model.rs (which this PR did not touch — good sign the schema was trailing reality, not the other way around). STATUS_INDICATOR drops the retired whale option; confirmed no other code still matches on it.
  • config_ui.rs: UiThemeValue::Custom becomes Custom(String) carrying the full custom:<name> selector, removing the sibling custom_theme_name field and the possibility of the two getting out of sync. Verified no remaining references to custom_theme_name anywhere in crates/. New test ui_theme_value_covers_every_selectable_theme (config_ui.rs:1885) is a good regression guard — it would have caught the pre-existing bug where claude and solarized-light themes silently fell out of the typed /config document (present in SELECTABLE_THEMES but missing from the old UiThemeValue enum).
  • WorkSurfacePlacementValue::from's fallback changed from Top to Bottom, matching WorkSurfacePlacement::parse in work_surface/model.rs:166. New round-trip test at config_ui.rs:1904 pins this.
  • settings.rs rail_panel validation: extended to accept all 8 dock panels, with pinned kept as an accepted alias that folds into tasks — consistent with the existing load-time migration and RailPanel::parse.
  • Locale files: all 14 locales got the same 4 key additions/8 removals as en.json; spot-checked en.json in full and diff shapes match across all files. No orphaned MessageId variants remain referenced anywhere in crates/.
  • Provider/model/route safety (EPIC v0.8.65 EPIC: Separate provider facts, model facts, offerings, and route resolution #2608): not applicable — this PR touches only UI config/theme/locale plumbing, no model or provider selection code.

No correctness bugs found. No dead code introduced (the removed custom_theme_name field and locale keys are fully excised, not just unlinked).

Minor, non-blocking observation: there's no test asserting that every SETTINGS_SCHEMA def()'s default string is actually a member of its own SettingKind::Enum options list. That's exactly the class of bug this PR fixes for work_surface_placement (default "left" was not in WORK_SURFACE_PLACEMENT's old options... actually it was, but the value space had drifted from WorkSurfacePlacementValue). A cheap #[test] iterating SETTINGS_SCHEMA and checking SettingKind::Enum(opts) defaults against opts would catch future drift between the plain-text schema and the typed value spaces automatically, rather than relying on manual alignment PRs like this one. Not required for this PR — just a cheap follow-up if schema/typed-value drift recurs.

Verification note: cargo check/cargo test were not run — the sandbox's Bash tool required approval that wasn't available in this run, so I verified correctness via full diff review, cross-referencing every changed const/enum against its non-touched consumer definitions, and grepping for stale symbol references. If CI (cargo fmt --all -- --check, cargo test -p codewhale-config -p codewhale-tui) is green, that's stronger evidence than my read-only pass.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Changes recommended

A few correctness/contract issues remain (notably an inaccurate rail_panel “Expected” error list and missing validation that UiThemeValue::Custom actually contains a custom:<name> selector).

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

This PR aligns the TUI’s settings schema, typed /config document, runtime Settings::set validation/normalization, and shipped locale packs so they describe the same (live) value spaces—avoiding silent rewrites when saving typed config (notably rail panel values, work surface placement, and theme selectors).

Changes:

  • Expands/aligns rail_panel and work_surface_placement accepted values (incl. bottom/off placement) and updates defaults/migrations (e.g., pinned folding into tasks, retiring whale status indicator in the editor).
  • Updates typed config UI schema/logic to represent themes as either a named built-in or a custom selector carried inside UiThemeValue.
  • Removes orphaned localization keys and updates all shipped locale packs to reflect the updated settings/value lists.
File summaries
File Description
crates/tui/src/settings.rs Updates Settings::set accepted rail panels, folds pinned into tasks, and adjusts related tests.
crates/tui/src/localization.rs Removes orphaned message IDs and adds new placement-related IDs used by schema/UI.
crates/tui/src/config_ui.rs Aligns typed /config theme + placement value spaces with runtime behavior; updates schema-related tests.
crates/config/src/settings_schema.rs Updates schema enums/options and defaults (e.g., placement default to bottom, rail panel list, retire whale).
crates/tui/locales/zh-Hant.json Removes orphaned keys; adds/updates strings for new placement/panel lists.
crates/tui/locales/zh-Hans.json Removes orphaned keys; adds/updates strings for new placement/panel lists.
crates/tui/locales/vi.json Removes orphaned keys; adds/updates strings for new placement/panel lists.
crates/tui/locales/uk.json Removes orphaned keys; adds/updates strings for new placement/panel lists.
crates/tui/locales/ru.json Removes orphaned keys; adds/updates strings for new placement/panel lists.
crates/tui/locales/pt-BR.json Removes orphaned keys; adds/updates strings for new placement/panel lists.
crates/tui/locales/ko.json Removes orphaned keys; adds/updates strings for new placement/panel lists.
crates/tui/locales/ja.json Removes orphaned keys; adds/updates strings for new placement/panel lists.
crates/tui/locales/id.json Removes orphaned keys; adds/updates strings for new placement/panel lists.
crates/tui/locales/hi.json Removes orphaned keys; adds/updates strings for new placement/panel lists.
crates/tui/locales/fr.json Removes orphaned keys; adds/updates strings for new placement/panel lists.
crates/tui/locales/es-419.json Removes orphaned keys; adds/updates strings for new placement/panel lists.
crates/tui/locales/en.json Removes orphaned keys; adds/updates strings for new placement/panel lists.
crates/tui/locales/de.json Removes orphaned keys; adds/updates strings for new placement/panel lists.
crates/tui/locales/ca.json Removes orphaned keys; adds/updates strings for new placement/panel lists.
Review details

Suppressed comments (1)

crates/tui/src/settings.rs:3253

  • This test asserts an "Expected" list that omits pinned, but pinned remains a valid input (alias of tasks). If the user-facing error message is corrected to include pinned, this assertion should be updated to match the accurate list.
        assert!(
            err.to_string()
                .contains("tasks, agents, background, files, notepad, context, git, or price")
        );
  • Files reviewed: 19/19 changed files
  • Comments generated: 2
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines 859 to 863
fn theme_setting_for_document(doc: &ConfigUiDocument) -> Result<String> {
let setting = if doc.settings.theme == UiThemeValue::Custom {
let name = doc
.settings
.custom_theme_name
.as_deref()
.map(str::trim)
.filter(|name| !name.is_empty())
.ok_or_else(|| anyhow::anyhow!("custom theme requires custom_theme_name"))?;
format!("{}{}", crate::palette::USER_THEME_PREFIX, name)
} else {
doc.settings.theme.as_setting().to_string()
};
crate::palette::resolve_theme_setting(&setting, None)
crate::palette::resolve_theme_setting(&doc.settings.theme.as_setting(), None)
.map(|(normalized, _, _)| normalized)
.map_err(anyhow::Error::msg)
}
Comment on lines 1386 to 1388
anyhow::bail!(
"Failed to update setting: invalid rail panel '{value}'. Expected: tasks, agents, context, or pinned."
"Failed to update setting: invalid rail panel '{value}'. Expected: tasks, agents, background, files, notepad, context, git, or price."
);

@codewhale-agent codewhale-agent Bot 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.

Codewhale review

PR aligns the typed /config document, hand-written settings schema, Settings::set, and locale packs around the live placement, rail-panel, and theme value spaces. Theme and placement round-trip coverage is significantly improved, and rail-panel validation now matches the dock. Remaining concerns are mostly around missing regression coverage for status-indicator retirement and empty schema labels for the newly exposed rail panels.

Findings

  • [WARNING] Status indicator alignment may still be incomplete and lacks a regression test (crates/tui/src/config_ui.rs)
    The diff removes whale from STATUS_INDICATOR and from locale/MessageId packs, but it does not modify the typed StatusIndicatorValue (which is not shown in this diff). If that type still exposes a Whale variant and a persisted/set value can reach build_document before migration, the typed document will still accept a value the schema no longer offers. The PR adds thorough tests for theme and placement but no equivalent test for status-indicator migration or schema/type equality.
  • [INFO] New rail panel schema entries use empty label and hint strings (crates/config/src/settings_schema.rs:328)
    background, files, notepad, git, and price are added as SettingOption::new(..., "", ""). If any schema consumer does not special-case empty label/hint keys, these options will render blank. The comment indicates raw RailPanel::title fallback is intentional, but that fallback is not tested here. Consider adding explicit locale entries or an assertion that empty labels fall back to the raw panel title.
  • [INFO] Theme alignment test covers typed schema but not the hand-written settings schema (crates/config/src/settings_schema.rs)
    The new ui_theme_value_covers_every_selectable_theme test verifies UiThemeValue round-trips and serializes correctly, but there is no analogous check that the hand-written SETTINGS_SCHEMA theme choices (if any are separate) include claude, solarized-light, and the custom:<name> representation. If that list is generated dynamically this is fine, but a cheap parity test would prevent future theme additions from drifting between the two schemas.

Suggestions

  • crates/config/src/settings_schema.rs:328 — Avoid empty label/hint strings for the newly exposed rail panels. Either add explicit locale/MessageId entries for background/files/notepad/git/price, or add a test that proves the empty-label fallback displays the raw RailPanel::title value instead of blank text.

Assessment

The PR is well-structured and directly fixes the silent theme/placement corruption it targets. The new tests are valuable and no blocking correctness bug is apparent in the diff, but a few alignment edge cases—especially status-indicator migration and the empty-label schema entries—should be explicitly covered before merge.


Advisory review by Codewhale (codewhale review --pr 5843 --post, head 01ec884f45a699e9f97e510b6af44019339412a9). Line-specific findings are also posted as inline review comments; mechanical fixes arrive as committable suggestions you can apply from the Files tab. CODEOWNERS approval still governs merge.

"ConfigChoiceDetailRailPinned",
),
SettingOption::new("git", "", ""),
SettingOption::new("price", "", ""),

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[INFO] New rail panel schema entries use empty label and hint strings

background, files, notepad, git, and price are added as SettingOption::new(..., "", ""). If any schema consumer does not special-case empty label/hint keys, these options will render blank. The comment indicates raw RailPanel::title fallback is intentional, but that fallback is not tested here. Consider adding explicit locale entries or an assertion that empty labels fall back to the raw panel title.

SettingOption::new("git", "", ""),
SettingOption::new("price", "", ""),
];

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Avoid empty label/hint strings for the newly exposed rail panels. Either add explicit locale/MessageId entries for background/files/notepad/git/price, or add a test that proves the empty-label fallback displays the raw RailPanel::title value instead of blank text.

…rip test

Signed-off-by: Hunter Bown <hmbown@codewhale.net>
@cursor

cursor Bot commented Sep 2, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_09b16edd-8ab0-4f1f-a1dc-6d39dcbc3f29)

@claude

claude Bot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Claude finished @Hmbown's task in 2m 53s —— View job


Claude finished the review

  • Gather context (diff, changed files, CLAUDE.md rules)
  • Review crates/config/src/settings_schema.rs
  • Review crates/tui/src/config_ui.rs
  • Review crates/tui/src/settings.rs and localization.rs
  • Cross-check prior review findings (Copilot, codewhale-agent)
  • Post findings

Review: tui: align typed config and schema with the live value spaces

This is a clean rung-2 fix — it edits SETTINGS_SCHEMA, UiThemeValue, and WorkSurfacePlacementValue to track value spaces that already exist (RailPanel::ORDER/RailPanel::parse in crates/tui/src/tui/work_surface/model.rs:80-134, WorkSurfacePlacement::parse at model.rs:160-168, SELECTABLE_THEMES), rather than adding a parallel abstraction. I diffed against the pre-PR base (66360de..HEAD, since origin/main isn't reachable in this shallow checkout) and cross-checked each changed const/enum against its live source of truth:

  • Rail panelsRAIL_PANEL (settings_schema.rs) and Settings::set's rail_panel match arm now cover all 8 of RailPanel::ORDER (tasks, agents, background, files, notepad, context, git, price), exactly matching RailPanel::parse. pinned is kept as a legacy input alias that folds into tasks, consistent with the load-time migration in migrate_sidebar_settings_to_rail.
  • Work surface placement — schema default corrected "left""bottom"; WorkSurfacePlacementValue's fallback changed TopBottom. Both now match WorkSurfacePlacement::parse's _ => Self::Bottom and Settings::default().
  • ThemeUiThemeValue::Custom(String) now carries the full custom:<name> selector instead of a sibling custom_theme_name: Option<String> field, which could previously desync from theme. Verified zero remaining references to custom_theme_name repo-wide. claude and solarized-light are added, matching SELECTABLE_THEMES; the new ui_theme_value_covers_every_selectable_theme test guards this going forward.
  • Localesen.json diff confirms label/key parity with localization.rs's MessageId additions/removals (ConfigChoicePlacementBottom/Detail, drop of ConfigChoiceRailPinned/ConfigChoiceStatusWhale/ConfigLabelSidebarWidth/ConfigLabelSidebarFocus/ConfigLabelLaunchScreen); the other 13 locales carry the identical key set per the file stats.

On the theme validation concern raised by Copilot (config_ui.rs:860): theme_setting_for_document passes doc.settings.theme.as_setting() straight into crate::palette::resolve_theme_setting, which calls normalize_theme_setting → either a compiled ThemeId::from_name match or normalize_user_theme_selector (requires the custom: prefix, 1-64 [a-z0-9_-] chars) → and then actually reads the theme file from disk. So a Custom(String) containing garbage, or a bare name without the custom: prefix, is still rejected at apply_document/validate_document time — this isn't a silent-acceptance bug, just a type that trusts its caller (from_setting) to only ever construct valid selectors, which is true for every code path here.

Confirming Copilot's other finding is real: crates/tui/src/settings.rs:1386-1388 — the rail_panel validation error message ("Expected: tasks, agents, background, files, notepad, context, git, or price.") omits pinned, but pinned is still accepted as an input alias (line 1384, folds into tasks). Minor UX inaccuracy, not a correctness bug (the value is still accepted); the test at settings.rs:3253 was updated to match the (incomplete) message rather than catching the gap. Fix this →

On the status-indicator concern raised by codewhale-agent: StatusIndicatorValue::Whale is indeed still a typed variant with no schema row now offering it, but it's not reachable through the normal document round trip — Settings::load_persisted normalizes "whale"/🐳/🐋 to "cw" before build_document ever reads settings.status_indicator (normalize_status_indicator, settings.rs:2722-2732), and that migration predates this PR. Not a regression introduced here; agreed it's a reasonable follow-up to add a schema/type parity test, but not blocking.

On the empty-label rail panel entries (background, files, notepad, git, price using SettingOption::new(value, "", "")): this is explicitly documented as intentional at settings_schema.rs:307-308 ("panels the classic sidebar never named ride on their raw value") and is already covered by the existing every_row_declares_a_tab_group_and_description test — that test only requires non-empty description for rows with a ui block, and rail_panel's ui() call passes "" for label deliberately (settings_schema.rs:726). Not a gap introduced by this PR.

No new correctness bugs, no provider/model/route-safety concerns (this PR touches only UI config/theme/locale plumbing). No dead code introduced — the old custom_theme_name field and the removed locale keys are fully excised. Test coverage for the fixed drift (theme, placement, rail panel) is solid.

Verification note: origin/main isn't fetchable at the required depth in this shallow sandbox checkout (fetch requires approval that wasn't granted), so I diffed against the PR's own base commit (66360de, the last commit before this branch's first commit) instead, and cross-referenced every changed value space against its live, untouched source of truth (RailPanel, WorkSurfacePlacement, SELECTABLE_THEMES, Settings::default()). I did not run cargo test/cargo fmt in this pass — the PR description states fmt is clean and dead-code budget holds at 425; CI is the stronger signal for those.

@codewhale-agent codewhale-agent Bot 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.

Codewhale review

Aligns config schema, typed /config document, and locale packs with runtime settings; adds theme and work-surface round-trip coverage and rail panel normalization.

Findings

  • [WARNING] New rail panel schema entries have empty display strings (crates/config/src/settings_schema.rs:326)
    RAIL_PANEL introduces background/files/notepad/git/price as SettingOption::new with empty title and detail IDs. If the settings UI renders the stored title/detail IDs directly, these five entries will show blank labels or descriptions rather than RailPanel::title. Confirm the UI has an empty-ID fallback or add MessageId/localized strings for parity with the other rail options.
  • [WARNING] Custom theme selector can bypass the old non-empty validation (crates/tui/src/config_ui.rs:860)
    theme_setting_for_document now passes UiThemeValue::Custom's inner String directly to resolve_theme_setting. The previous code trimmed custom_theme_name and returned a clear 'custom theme requires custom_theme_name' error. Because parse_document deserializes Custom(String) without calling UiThemeValue::from_setting, malformed values such as "" or whitespace can reach apply_document with a low-level palette error instead of a validation message. Consider normalizing/validating the selector in theme_setting_for_document or in a deserialization guard.
  • [INFO] rail_panel error text omits the still-supported pinned alias (crates/tui/src/settings.rs:1382)
    Settings::set still accepts pinned and folds it into tasks, but the invalid-value error only lists tasks, agents, background, files, notepad, context, git, and price. Users who try a nearby alias may not realize pinned remains valid.
  • [INFO] Work-surface test may not actually load the persisted settings file (crates/tui/src/config_ui.rs:1938)
    work_surface_placement_round_trips_bottom_and_off_through_typed_document writes settings.toml and sets env guards, then constructs Config::default(). If Config::default() does not load from CODEWHALE_HOME, the test only exercises the default value and the temp file is dead. Confirm Config::default() performs a load, or explicitly load the settings path before build_document.

Assessment

The change is coherent and well-tested for theme and work-surface round-tripping. Remaining concerns are UX/schema consistency details and one test-clarity issue; none block merge if the rail label fallback and Config::default() load behavior are confirmed.


Advisory review by Codewhale (codewhale review --pr 5843 --post, head 9a29726a8576693e0a023297d2d6e226f7bb3551). Line-specific findings are also posted as inline review comments; mechanical fixes arrive as committable suggestions you can apply from the Files tab. CODEOWNERS approval still governs merge.

"context",
"ConfigChoiceRailContext",
"ConfigChoiceDetailRailContext",
),

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[WARNING] New rail panel schema entries have empty display strings

RAIL_PANEL introduces background/files/notepad/git/price as SettingOption::new with empty title and detail IDs. If the settings UI renders the stored title/detail IDs directly, these five entries will show blank labels or descriptions rather than RailPanel::title. Confirm the UI has an empty-ID fallback or add MessageId/localized strings for parity with the other rail options.

doc.settings.theme.as_setting().to_string()
};
crate::palette::resolve_theme_setting(&setting, None)
crate::palette::resolve_theme_setting(&doc.settings.theme.as_setting(), None)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[WARNING] Custom theme selector can bypass the old non-empty validation

theme_setting_for_document now passes UiThemeValue::Custom's inner String directly to resolve_theme_setting. The previous code trimmed custom_theme_name and returned a clear 'custom theme requires custom_theme_name' error. Because parse_document deserializes Custom(String) without calling UiThemeValue::from_setting, malformed values such as "" or whitespace can reach apply_document with a low-level palette error instead of a validation message. Consider normalizing/validating the selector in theme_setting_for_document or in a deserialization guard.

| "files"
| "notepad"
| "context"
| "git"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[INFO] rail_panel error text omits the still-supported pinned alias

Settings::set still accepts pinned and folds it into tasks, but the invalid-value error only lists tasks, agents, background, files, notepad, context, git, and price. Users who try a nearby alias may not realize pinned remains valid.

let settings_path = codewhale_home.join("settings.toml");
fs::write(&settings_path, "work_surface_placement = \"bottom\"\n").expect("settings");
let _home = EnvVarGuard::set("CODEWHALE_HOME", &codewhale_home);
let _codewhale_config = EnvVarGuard::remove("CODEWHALE_CONFIG_PATH");

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[INFO] Work-surface test may not actually load the persisted settings file

work_surface_placement_round_trips_bottom_and_off_through_typed_document writes settings.toml and sets env guards, then constructs Config::default(). If Config::default() does not load from CODEWHALE_HOME, the test only exercises the default value and the temp file is dead. Confirm Config::default() performs a load, or explicitly load the settings path before build_document.

@Hmbown Hmbown closed this pull request by merging all changes into main in 7bc08e2 Sep 3, 2026
@Hmbown
Hmbown deleted the fix/config-truth-20260902 branch September 3, 2026 04:47
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.

2 participants