Skip to content

fix(config): recover Codex MCP after closing marker loss - #2434

Open
astandrik wants to merge 2 commits into
DeusData:mainfrom
astandrik:fix/2228-managed-block-foreign-tables
Open

astandrik wants to merge 2 commits into
DeusData:mainfrom
astandrik:fix/2228-managed-block-foreign-tables

Conversation

@astandrik

@astandrik astandrik commented Sep 29, 2026 •

Copy link
Copy Markdown
Contributor

What does this PR do?

Fixes reinstall after Codex deletes mcp_servers.node_repl and takes the closing MCP marker with it. It keeps #2467's placement of foreign tables after the managed block.

Before legacy migration, install recovers a lone opening marker only when the following CBM table and managed fields are recognizable. It preserves user keys, comments and child tables, restores the closer, and writes once atomically. Ambiguous ownership or a concurrent file change causes refusal without overwriting the file.

Evidence

  • CLI regression: fails on main with reinstall returning -1; passes with the fix.
  • Linux scripts/test.sh: 8468 passed, 0 failed, 9 platform skips; production guards passed.
  • scripts/msan.sh config_toml_edit cli: 409 passed. Config fuzz: 20,000 runs, seed 1.
  • Real Codex 0.149.1 and 0.153.4: 12 lifecycle cases passed, including recovery of the same file after base refused, preservation of user data, byte-idempotent reinstall and uninstall.
  • Full CI lint passed. Raw Clang analysis compared with base: no new diagnostics; 18 existing memory findings unchanged. Raw logs were compared because the existing memory gate misses some diagnostic suffixes.

Native macOS/Windows and full TSan results will come from GitHub CI.

Checklist

  • Every commit is signed off
  • Tests pass (full Linux remote run)
  • CI lint passes
  • New behavior has a failing regression before the fix

Fixes #2228.

Written with OpenAI Codex on behalf of Anton Standrik (@astandrik).

@github-actions

Copy link
Copy Markdown

Thanks for opening this — it has been seen, and it is queued.

This note is automated, but it is not a brush-off: it exists so you know where your PR stands instead of having to guess from silence.

Current review status: working through a backlog. 0.9.1-rc.1 is out, so the release freeze that held reviews is over — but it left a large queue of open pull requests behind it, and we are reading through them oldest-first. The background is in discussion #1144.

What that means for this PR, concretely:

  • It will not be closed for inactivity. No stale bot touches pull requests here.
  • It may still sit a while before a human reads it. That is on us, not on you.
  • Older PRs are read first, so a recent one is not being skipped — it is behind a queue.

Things that will genuinely speed it up whenever review does happen:

  • Keep it rebased on main — the tree is moving quickly right now, and a conflicting branch cannot be reviewed as the diff you intended.
  • Get CI green, or say which failures you believe are pre-existing.
  • Keep the change to one claim. Bundled features and refactors get split before they get merged, which costs you a round trip.
  • Every commit needs a sign-off (git commit -s) — CI enforces DCO.

If this fixes a bug, a reproduction we can run is worth more than a description of the symptom.

Thanks for contributing, and sorry in advance for the wait.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

Array-table ownership and dotted-key conflicts can still produce invalid or incorrectly transformed TOML.

Review effort: Balanced
Findings: 2 High severity

Open (2)
What changed in this PR

Updates managed TOML editing to preserve foreign content and user-defined keys within marker spans.

Changes:

  • Merges or removes only owned TOML tables and descendants.
  • Updates Codex, Grok, and Kimi integrations for table-aware removal.
  • Adds regression, CLI, and fuzz coverage.
File Description
src/​cli/​config_toml_edit.c Implements table-aware span editing.
src/​cli/​config_toml_edit.h Documents and exposes the updated API.
src/​cli/​cli.c Supplies owned headers for client removal.
tests/​test_config_toml_edit.c Adds TOML regression coverage.
tests/​test_cli.c Adds Codex integration coverage.
tests/​fuzz/​cbm_fuzz.c Fuzzes table-headed managed blocks.
tests/​fuzz/​corpus/​config/​toml-foreign-span.seed Adds a foreign-span seed.
scripts/​memory-core-baseline.txt Updates the memory lint baseline.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread src/cli/config_toml_edit.c Outdated
Comment thread src/cli/config_toml_edit.c Outdated
@astandrik
astandrik marked this pull request as draft September 29, 2026 19:14
@astandrik

Copy link
Copy Markdown
Contributor Author

Converted to draft while I run another round of checks on a small cleanup of this change. I'll mark it ready for review once they pass.

astandrik added a commit to astandrik/codebase-memory-mcp that referenced this pull request Sep 30, 2026
Two cases from the DeusData#2434 review, both reproduced before this change:

- Array block (Kimi's [[hooks]]): every later header on the array path
  counted as foreign. A [hooks] table in the span stayed next to the
  [[hooks]] entry upsert wrote, which is invalid TOML, and a [hooks.meta]
  of our entry that sat behind unrelated content survived removal and
  turned hooks into a table. Now only a later [[hooks]] element starts
  foreign content, together with its sub-tables; a same-path [hooks] or
  a sub-table ahead of that element fails closed.
- Dotted keys: command.detail = "x" in our table does not match the
  block's command key, so the merge kept it and appended command, which
  TOML forbids. Upsert now fails closed when a dotted key or a sub-table
  redefines a key the block writes; unrelated dotted keys are kept.

Plus a cleanup with no behaviour change: the block's body spec moves into
the shape struct and the scan state into the span struct instead of extra
parameters and out-parameters, duplicate comments go, and the public
header drops the issue history.

Tests: the fail-closed case adds the three array conflicts (upsert and
removal both refuse, file untouched) and the two key redefinitions; the
merge case keeps an unrelated dotted key; the array case keeps the
sub-table of a foreign element.

Refs DeusData#2228

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Anton Standrik <astandrik@yandex-team.ru>
@astandrik
astandrik marked this pull request as ready for review September 30, 2026 14:06
@DeusData

DeusData commented Oct 4, 2026

Copy link
Copy Markdown
Owner

Thank you so much, @astandrik, for this PR and especially for the careful side-by-side recheck with real Codex app-server writes. That comparison found a real gap. We also owe you an apology for the order of events: #2467, for the same issue, was merged today without your PR and your 10-02 results being weighed against it first. That is on us.

Your finding holds on current main. When Codex removes mcp_servers.node_repl through config/value/write, the closing marker goes with it. The next install then refuses (exit 1, config.toml untouched), exactly as you showed, while #2434 handles that case.

Would you be up for rebasing #2434 onto main as the follow-up for that case? main now keeps foreign tables by moving them below the closing marker (#2467). What is still missing is a safe recovery when the closing marker is gone. Your app-server reproduction (delete node_repl, then reinstall) would make the ideal regression test next to the existing ones in tests/test_cli.c. If you would rather not, just say so and we will take it from here with you credited.

I have reopened #2228 so the remaining case stays tracked. Thanks again for the thorough work!

@astandrik
astandrik force-pushed the fix/2228-managed-block-foreign-tables branch from 0f30825 to ea911e2 Compare October 5, 2026 11:04
@astandrik astandrik changed the title fix(config): keep foreign content inside the managed TOML block (#2228) fix(config): recover Codex MCP after closing marker loss Oct 5, 2026
@astandrik

Copy link
Copy Markdown
Contributor Author

Thank you so much, @astandrik, for this PR and especially for the careful side-by-side recheck with real Codex app-server writes. That comparison found a real gap. We also owe you an apology for the order of events: #2467, for the same issue, was merged today without your PR and your 10-02 results being weighed against it first. That is on us.

Your finding holds on current main. When Codex removes mcp_servers.node_repl through config/value/write, the closing marker goes with it. The next install then refuses (exit 1, config.toml untouched), exactly as you showed, while #2434 handles that case.

Would you be up for rebasing #2434 onto main as the follow-up for that case? main now keeps foreign tables by moving them below the closing marker (#2467). What is still missing is a safe recovery when the closing marker is gone. Your app-server reproduction (delete node_repl, then reinstall) would make the ideal regression test next to the existing ones in tests/test_cli.c. If you would rather not, just say so and we will take it from here with you credited.

I have reopened #2228 so the remaining case stays tracked. Thanks again for the thorough work!

Updated this PR on top of main, keeping #2467’s layout. It now recovers the missing closing marker while preserving user keys and foreign tables.
The regression in tests/test_cli.c fails on base and passes with the fix. With real Codex 0.149.1 and 0.153.4 app-server writes, base refuses after deleting node_repl; the updated installer repairs that same file. Reinstall is byte-idempotent, and uninstall preserves unrelated content.
Full Linux ASan/UBSan, focused MSan, CI lint and 20,000 config-fuzz runs passed. Results are in the PR description.

@astandrik
astandrik requested a balanced review from Copilot October 5, 2026 11:32

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Warning

Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.

Copilot review overview

Review effort: Lite
Findings: 1 High severity · 2 Medium severity

Open (3)
Resolved since last review (2)

Comment thread src/cli/config_toml_edit.c
Comment thread tests/test_cli.c Outdated
Comment thread tests/test_config_toml_edit.c Outdated

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Warning

Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.

Copilot review overview

Review effort: Lite
Findings: 1 High severity · 1 Medium severity

Open (2)
Resolved since last review (3)

Comment thread src/cli/config_toml_edit.c
Comment thread tests/test_cli.c
Signed-off-by: Anton Standrik <astandrik@yandex-team.ru>
@astandrik
astandrik force-pushed the fix/2228-managed-block-foreign-tables branch from b4c735d to c28593e Compare October 6, 2026 12:53
Signed-off-by: Anton Standrik <astandrik@yandex-team.ru>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

install deletes foreign tables placed between the managed MCP markers in ~/.codex/config.toml (0.10.4 → 0.11.0 upgrade)

3 participants