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

3.6 KiB
Raw Blame History

DOs

  • Bold the keyword, then colon + concise description.

  • Merge related points when possible; avoid a bullet for every trivial detail.

  • Keep bullets to one line unless breaking for clarity is unavoidable.

  • Bold the keyword, then colon + concise description.

  • Isolate config editing: Move config-toml mutation into a dedicated config_edit.rs module and re-export minimal APIs.

// lib.rs
pub mod config_edit;

// config.rs
pub use crate::config_edit::set_default_model_and_effort_for_profile;
  • Use idiomatic Option chaining: Compute the effective profile with concise, readable combinators.
let effective_profile = profile
    .as_deref()
    .or_else(|| {
        load_config_as_toml(codex_home)
            .ok()
            .and_then(|v| v.get("profile").and_then(|i| i.as_str()))
    })
    .map(ToString::to_string);
  • Edit TOML by segments: Address nested keys via explicit path segments so dots/spaces in names are handled safely.
let segments = ["profiles", "my.team name", "model"];
apply_toml_edit_override_segments(&mut doc, &segments, toml_edit::value("o3"));
  • Preserve formatting/comments: When creating tables, mark them implicit to avoid gratuitous formatting changes.
current[*seg] = toml_edit::Item::Table(toml_edit::Table::new());
if let Some(t) = current[*seg].as_table_mut() {
    t.set_implicit(true);
}
  • Test full file output: Assert against the entire resulting config.toml so table structure and comments are verified.
let contents = std::fs::read_to_string(codex_home.join(CONFIG_TOML_FILE))?;
let expected = r#"profile = "o3"

[profiles.o3]
model = "o3"
model_reasoning_effort = "high"
"#;
assert_eq!(contents, expected);
  • Use string fixtures: Seed input TOML and expected TOML as strings to make intent explicit and reviewable.
let seed = r#"# Global comment
profile = "o3"

[profiles.o3]
existing = "keep"
"#;
std::fs::write(config_path, seed)?;
let expected = r#"# Global comment
profile = "o3"

[profiles.o3]
existing = "keep"
model = "o3"
model_reasoning_effort = "high"
"#;
// ... write via API, then:
assert_eq!(std::fs::read_to_string(config_path)?, expected);
  • Offer focused APIs: Provide both top-level and profile-scoped helpers for clarity and reuse.
set_default_model_and_effort(codex_home, "gpt-5", ReasoningEffort::Minimal)?;
set_default_model_and_effort_for_profile(codex_home, Some("o3"), "o3", ReasoningEffort::High)?;

DONTs

  • Dont bloat config.rs: Avoid embedding large edit routines directly in config.rs; keep it thin.
// Bad (monolithic in config.rs):
fn set_default_model_and_effort(...) {
    // hundreds of lines of edit logic here
}
  • Dont build dotted key strings: Dotted keys break when names contain dots/spaces; use segments instead.
// Bad:
doc["profiles.my.team name"]["model"] = toml_edit::value("o3");
  • Dont drop comments/formatting: Avoid serializing from structs that rewrite the whole file and lose trivia.
// Bad:
let s = toml::to_string(&my_struct)?; // loses comments/order
std::fs::write(config_path, s)?;
  • Dont assert partial changes: Contains/regex checks miss structural and formatting regressions.
// Bad:
assert!(contents.contains("model = \"o3\"")); // ignores tables/comments
  • Dont paper over parse errors: If the TOML cant be parsed, surface the error and dont clobber the file.
// Bad:
let doc = std::fs::read_to_string(config_path)
    .ok()
    .and_then(|s| s.parse::<toml_edit::DocumentMut>().ok())
    .unwrap_or_default(); // silently discards invalid file