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

161 lines
5.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
**DOs**
- Bold: Atomic config writes: write `config.toml` via a temp file in `codex_home`, then atomically persist.
```rust
use tempfile::NamedTempFile;
use toml_edit::{DocumentMut, value};
const CONFIG_TOML_FILE: &str = "config.toml";
fn write_config_atomically(codex_home: &Path, doc: &DocumentMut) -> anyhow::Result<()> {
let config_path = codex_home.join(CONFIG_TOML_FILE);
std::fs::create_dir_all(codex_home)?;
let tmp = NamedTempFile::new_in(codex_home)?;
std::fs::write(tmp.path(), doc.to_string())?;
tmp.persist(config_path)?;
Ok(())
}
```
- Bold: Autovivify with toml_edit: rely on table creation-on-demand when setting nested keys (no panics).
```rust
use toml_edit::{DocumentMut, value};
fn trust_project(doc: &mut DocumentMut, project: &Path) {
let key = project.to_string_lossy();
doc["projects"][key.as_ref()]["trust_level"] = value("trusted");
}
```
- Bold: Single source of cwd: canonicalize once, store in `Config`, and use `config.cwd` everywhere.
```rust
// During CLI parsing
let cwd = cli.cwd.clone().map(|p| p.canonicalize().unwrap_or(p));
let overrides = ConfigOverrides { cwd, /* ... */ };
// Later, prefer config.cwd over a separate arg
fn needs_trust_screen(config: &Config) -> bool {
let resolved = &config.cwd;
/* use resolved as the canonical cwd */
/* ... */
false
}
```
- Bold: Respect overrides and profiles: only show the trust screen when no explicit policy is set via CLI flags, `-c` overrides, profile, or `config.toml`.
```rust
fn determine_repo_trust_state(
config: &mut Config,
config_toml: &ConfigToml,
approval_override: Option<AskForApproval>,
sandbox_override: Option<SandboxMode>,
profile_override: Option<String>,
) -> std::io::Result<bool> {
let profile = config_toml.get_config_profile(profile_override)?;
if approval_override.is_some() || sandbox_override.is_some() { return Ok(false); }
if profile.approval_policy.is_some() { return Ok(false); }
if config_toml.approval_policy.is_some() || config_toml.sandbox_mode.is_some() { return Ok(false); }
if config_toml.is_cwd_trusted(&config.cwd) {
config.approval_policy = AskForApproval::OnRequest;
config.sandbox_policy = SandboxPolicy::new_workspace_write_policy();
return Ok(false);
}
Ok(true)
}
```
- Bold: Apply `-c` overrides to `config.toml` for decisions: merge CLI key/value overrides before trust checks.
```rust
let cli_kv = cli.config_overrides.parse_overrides()?;
let codex_home = find_codex_home()?;
let config_toml = load_config_as_toml_with_cli_overrides(&codex_home, cli_kv)?;
```
- Bold: Keep “trust” UX in TUI: mutate session config in the trust step, not in `core`.
```rust
// In the TrustDirectory widget
if let Ok(mut args) = self.chat_widget_args.lock() {
args.config.approval_policy = AskForApproval::OnRequest;
args.config.sandbox_policy = SandboxPolicy::new_workspace_write_policy();
}
set_project_trusted(&self.codex_home, &self.cwd)?;
```
- Bold: Share mutable state only when needed: use `Arc<Mutex<...>>` to pass `ChatWidgetArgs` across steps that mutate it.
```rust
let shared = Arc::new(Mutex::new(chat_widget_args));
steps.push(Step::TrustDirectory(TrustDirectoryWidget { chat_widget_args: shared.clone(), /*...*/ }));
steps.push(Step::ContinueToChat(ContinueToChatWidget { chat_widget_args: shared }));
```
- Bold: Update docs when defaults change: if the default `AskForApproval` variant changes, annotate and update prose.
```rust
#[derive(Default, strum::Display, Clone, Copy, Debug, PartialEq, Eq)]
pub enum AskForApproval {
OnFailure,
#[default] // now the default
OnRequest,
UnlessTrusted,
}
/// Default ask-for-approval policy is OnRequest.
```
**DONTs**
- Bold: Non-atomic writes: dont write `config.toml` directly or compute arbitrary parents; always write temp-then-persist in `codex_home`.
```rust
// ❌ Dont
std::fs::write(codex_home.join("config.toml"), doc.to_string())?;
```
- Bold: Implicit trust from flags: dont mark a project trusted just because user passed `--sandbox` or `--approval-policy`, and dont persist that.
```rust
// ❌ Dont persist trust due to transient flags
if approval_override.is_some() || sandbox_override.is_some() {
// do not write projects[resolved_cwd].trust_level = "trusted"
}
```
- Bold: UI logic in core: dont make `core` assume TUI onboarding; keep policy selection and trust prompts in TUI.
```rust
// ❌ Dont in core
if cfg.projects.get(&cwd_str).map(|p| p.trusted == Some(true)).unwrap_or(false) {
// core deciding UI flow — avoid
}
```
- Bold: Hardcoded paths: dont sprinkle `"config.toml"` everywhere; use a constant.
```rust
// ✅ Do
const CONFIG_TOML_FILE: &str = "config.toml";
let p = codex_home.join(CONFIG_TOML_FILE);
```
- Bold: Ignoring profiles/overrides: dont trigger trust onboarding if a profile or any override already sets policy/sandbox.
```rust
// ❌ Dont
let show_trust = true; // ignoring profile/overrides present in config_toml or CLI
```
- Bold: Redundant cwd plumbing: dont pass `cwd` separately when `config.cwd` is already resolved.
```rust
// ❌ Dont
fn should_show_trust_screen(_config: &Config, cwd: Option<PathBuf>) -> bool { /* ... */ }
```
- Bold: Conflate Git with trust: dont treat “inside a Git repo” as the trust signal or exit condition; use explicit trust state.
```rust
// ❌ Dont
if !is_inside_git_repo(&config.cwd) { eprintln!("Exiting..."); std::process::exit(1); }
```
- Bold: Unnecessary locking: dont wrap data in `Arc<Mutex<_>>` unless a later step will mutate it.
```rust
// ❌ Dont
let args = Arc::new(Mutex::new(ChatWidgetArgs { /* ... */ })); // if never mutated, pass by value
```
- Bold: Vague errors: dont lose detail; include variables directly in messages with captured `format!`.
```rust
// ✅ Do
return Err(std::io::Error::new(std::io::ErrorKind::NotFound, format!("config profile `{key}` not found")));
```