Mark transcript_v2 as removed (#55388)

## What changed

Mark the no-op `transcript_v2` feature as removed and drop it from the daemon startup override allowlist. Use `tui.fullscreen_transcript` to control the transcript preference.

## Testing

Update local settings coverage to assert that `features.transcript_v2` does not override the fullscreen transcript preference. Use a generic deprecated option in the deprecation notification test and snapshot.

GitOrigin-RevId: 78f832b9603cedc2a6509404a45509e47e845752
This commit is contained in:
Eric Traut
2026-10-19 21:44:30 +00:00
committed by copyberry
parent fea1d7f7d1
commit 36e5861fd9
6 changed files with 23 additions and 39 deletions
+2 -2
View File
@@ -101,7 +101,7 @@ pub enum Feature {
ApiKeyCyberAccessPrograms,
/// Enable Daybreak controls and automatic access-program selection in CLI clients.
CliDaybreak,
/// Deprecated no-op; use `tui.fullscreen_transcript` instead.
/// Removed no-op; use `tui.fullscreen_transcript` instead.
TranscriptV2,
// Stable.
/// Enable the default shell tool.
@@ -1052,7 +1052,7 @@ pub const FEATURES: &[FeatureSpec] = &[
FeatureSpec {
id: Feature::TranscriptV2,
key: "transcript_v2",
stage: Stage::Deprecated,
stage: Stage::Removed,
default_enabled: false,
},
// Stable features.
@@ -6,7 +6,7 @@ Buffer {
area: Rect { x: 0, y: 0, width: 80, height: 12 },
content: [
"/ T R A N S C R I P T / / / / / / / / / / / / / / / / / / / / / / / / / / / / / ",
"⚠ `transcript_v2` is deprecated. ",
"⚠ `legacy_option` is deprecated. ",
"Remove it from your configuration. ",
" ",
" ",
@@ -47,7 +47,7 @@ async fn deprecation_delivery_deduplicates_retained_transcript() -> Result<()> {
tui.set_owned_screen(/*owned*/ false)?;
let notice = ServerNotification::DeprecationNotice(
codex_app_server_protocol::DeprecationNoticeNotification {
summary: "`transcript_v2` is deprecated.".into(),
summary: "`legacy_option` is deprecated.".into(),
details: Some("Remove it from your configuration.".into()),
},
);
@@ -86,8 +86,8 @@ async fn deprecation_delivery_deduplicates_retained_transcript() -> Result<()> {
insta::assert_snapshot!("deduplicated_deprecation_transcript", format!("{buffer:?}"));
for (summary, details) in [
("`transcript_v2` is deprecated.", None),
("`transcript_v2` is deprecated.", Some("Updated guidance.")),
("`legacy_option` is deprecated.", None),
("`legacy_option` is deprecated.", Some("Updated guidance.")),
("Another deprecated setting.", Some("Updated guidance.")),
] {
app.chat_widget.handle_server_notification(
@@ -109,7 +109,7 @@ async fn deprecation_delivery_deduplicates_retained_transcript() -> Result<()> {
.map(|entry| entry.details)
.collect::<Vec<_>>(),
vec![
"`transcript_v2` is deprecated.\nRemove it from your configuration.\n\n`transcript_v2` is deprecated.\nUpdated guidance.",
"`legacy_option` is deprecated.\nRemove it from your configuration.\n\n`legacy_option` is deprecated.\nUpdated guidance.",
"Another deprecated setting.\nUpdated guidance.",
],
);
+1 -1
View File
@@ -132,7 +132,7 @@ fn allowed_feature(name: &str) -> bool {
matches!(
name,
// Client gates and per-thread settings already forwarded in thread requests.
"daemon_auto_start" | "transcript_v2" | "standalone_web_search"
"daemon_auto_start" | "standalone_web_search"
| "app_server_websocket_compression"
// Shared services and threadless MCP operations need daemon compatibility checks.
| "api_key_model_discovery" | "code_mode_host" | "auth_elicitation"
+1 -4
View File
@@ -8,15 +8,12 @@ use tempfile::TempDir;
#[test]
fn audited_overrides_allow_daemon_without_allowing_arbitrary_config() {
for (raw, eligible) in [
("features.transcript_v2=true", true),
("features.transcript_v2=false", true),
("features.app_server_websocket_compression=true", true),
("features.app_server_websocket_compression=false", true),
("features={transcript_v2=true}", true),
("features.transcript_v2='true'", false),
("features.worktrees=true", true),
("features.worktrees=false", true),
("features={worktrees=true}", true),
("features.worktrees='true'", false),
(
"features={worktrees=true,api_key_model_discovery=false}",
true,
+14 -27
View File
@@ -151,6 +151,16 @@ fast_default_opt_out = true
] {
let home = tempfile::tempdir()?;
std::fs::write(home.path().join("config.toml"), config_text)?;
let cli_overrides = vec![
("tui.disable_paste_burst".into(), true.into()),
("tui.right_click_paste".into(), "on".into()),
("tui.mouse_scroll_speed".into(), 1.5.into()),
// The removed flag must not override the TUI preference.
(
"features.transcript_v2".into(),
config_text.is_empty().into(),
),
];
let config = ConfigBuilder::default()
.codex_home(home.path().to_path_buf())
.strict_config(true)
@@ -158,32 +168,16 @@ fast_default_opt_out = true
ignore_project_config: true,
..LoaderOverrides::without_managed_config_for_tests()
})
.cli_overrides(vec![
("tui.disable_paste_burst".into(), true.into()),
("tui.right_click_paste".into(), "on".into()),
("tui.mouse_scroll_speed".into(), 1.5.into()),
// The deprecated flag must not override or migrate into the TUI preference.
(
"features.transcript_v2".into(),
config_text.is_empty().into(),
),
])
.cli_overrides(cli_overrides.clone())
.build()
.await?;
assert_eq!(config.startup_warnings, Vec::<String>::new());
assert_eq!(config.tui_mouse_scroll_speed, Some(1.5));
assert!(config.tui_fullscreen_transcript);
let bootstrap = crate::legacy_core::config::load_config_toml_with_layer_stack(
home.path(),
/*cwd*/ None,
vec![
("tui.disable_paste_burst".into(), true.into()),
("tui.right_click_paste".into(), "on".into()),
("tui.mouse_scroll_speed".into(), 1.5.into()),
(
"features.transcript_v2".into(),
config_text.is_empty().into(),
),
],
cli_overrides,
codex_config::ConfigLoadOptions {
loader_overrides: LoaderOverrides {
ignore_project_config: true,
@@ -198,14 +192,7 @@ fast_default_opt_out = true
LocalSettings::from_bootstrap(&bootstrap, config.codex_home.clone())?,
LocalSettings::from(&config),
);
assert_eq!(
config
.features
.legacy_feature_usages()
.map(|usage| usage.alias.as_str())
.collect::<Vec<_>>(),
vec!["features.transcript_v2"],
);
assert_eq!(config.features.legacy_feature_usages().count(), 1);
}
Ok(())
}