Files
codex/prs/bolinfest/study/PR-1675-study.md
2025-09-02 15:17:45 -07:00

2.7 KiB
Raw Blame History

DOs

  • Align UI text with config: Use a single source of truth by deriving Display and Serialize/Deserialize on the enum with kebab-case.
use serde::{Deserialize, Serialize};
use strum_macros::Display;

#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash, Serialize, Deserialize, Display)]
#[serde(rename_all = "kebab-case")]
#[strum(serialize_all = "kebab-case")]
pub enum AskForApproval {
    #[default]
    #[serde(rename = "untrusted")]
    #[strum(serialize = "untrusted")]
    UnlessTrusted,
    OnFailure,
    Never,
}
  • Render policies via Display: Show the kebab-case value with to_string() (or format!("{}", ...)) in summaries and TUI.
("approval", config.approval_policy.to_string())
// or
("approval", format!("{}", config.approval_policy))
  • Override per-variant when needed: Explicitly rename variants whose desired label isnt the kebab-case of the Rust identifier.
#[serde(rename = "untrusted")]
#[strum(serialize = "untrusted")]
UnlessTrusted,
  • Keep changes centralized: Put naming logic on the enum, not scattered across UI layers.
// Good: UI just uses Display everywhere
let approval = config.approval_policy.to_string();
  • Verify and update snapshots when UI text changes: Regenerate and accept TUI snapshots that include the new strings.
cargo test -p codex-tui
cargo insta pending-snapshots -p codex-tui
cargo insta accept -p codex-tui

DON'Ts

  • Dont use Debug for user-facing strings: {:?} exposes Rust variant names that dont match config values.
// Bad: prints "UnlessTrusted"
("approval", format!("{:?}", config.approval_policy))
  • Dont use serde_json::to_string for display: It adds quotes/JSON formatting and increases complexity.
// Bad: results in "\"untrusted\""
("approval", serde_json::to_string(&config.approval_policy).unwrap())
  • Dont duplicate mapping in the UI: Avoid hand-written matches or ad-hoc conversions in multiple files.
// Bad: scattered, easy to drift
let label = match config.approval_policy {
    AskForApproval::UnlessTrusted => "untrusted",
    AskForApproval::OnFailure => "on-failure",
    AskForApproval::Never => "never",
};
  • Dont rely on implicit case conversion to match external spec: Handle exceptions like UnlessTrusteduntrusted explicitly.
// Bad: assumes kebab-case of identifier is correct
#[strum(serialize_all = "kebab-case")] // without per-variant override
// "UnlessTrusted" would become "unless-trusted" (wrong)
  • Dont leak internal names into UX: Users should see config-aligned values, not Rust identifiers.
// Bad UX: shows "OnFailure" instead of "on-failure"
format!("{:?}", AskForApproval::OnFailure);