Builds on aedbf8a, which fixed the discard-everything-after-the-block bug.
Two related faults remained, both reproducible on a config that has drifted:
1. The block's interior was still dropped. Where an older kit let the end
marker drift below content Codex had written, real [plugins.*] and
[projects.*] sections ended up *inside* the block, so discarding it
deleted them. This was the live state on the macOS machine: the markers
spanned lines 15-88 with plugins, marketplaces, projects and
mcp_servers.graphiti between them. The interior is now filtered like the
rest, which also heals the layout in a single run.
2. Bare root keys were still landing under a table. With the block emitted
after `before`, and `before` ending in [sandbox_workspace_write], TOML
bound model/web_search/project_doc_max_bytes to that table rather than to
the document root. Output is now ordered: root keys, managed block, then
tables.
Against a fixture with a plugin inside the block and an mcp_server after it,
aedbf8a yields:
swallowed plugin kept: False
sandbox keys: [network_access, model, model_reasoning_effort,
project_doc_max_bytes, web_search]
root keys: [approval_policy]
and this commit yields:
swallowed plugin kept: True
after-block mcp kept: True
sandbox keys: [network_access]
root keys: [approval_policy, model, model_reasoning_effort,
project_doc_max_bytes, web_search]
BOM handling, profile file layout and model choices from aedbf8a are
unchanged. Verified on macOS: repeated runs are byte-identical, all 13
plugins / 3 projects / 6 mcp_servers survive, and `codex exec --profile deep`
works.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>