Skip to content

fix: keep app-owned notify out of the protected overlay - #3

Merged
StarsailsClover merged 1 commit into
mainfrom
fix/notify-app-owned-churn
Oct 2, 2026
Merged

StarsailsClover merged 1 commit into
mainfrom
fix/notify-app-owned-churn

Conversation

@StarsailsClover

Copy link
Copy Markdown
Member

Problem

notify was treated as user-owned and captured into the protected overlay. The Codex
desktop app rewrites that key with a version-scoped runtime path
(runtimes\cua_node\<hash>\...), so any captured copy goes stale the moment the app
updates.

The explicit repair command runs with manual = true and therefore merges without
requiring a clobber fingerprint (store.rs). So the sequence below silently rewrote the
live config to point at a runtime directory that no longer exists:

status : Change: Edit (score 1, threshold 4) | changed: notify
         -> "protected drift detected; run keepmyconfig repair to restore it"
repair : classification=Edit score=1  ...  overwritten notify
result : notify -> 2134bcb1950af07e   (deleted by the app update)

Effect: the turn-ended Computer Use hook stops firing, and the wrong value persists
because nothing re-reads the deleted directory.

Fix

notify now sits in the default ignored set next to mcp_servers.node_repl, which has
exactly the same lifecycle. ignored means neither protected nor restored — the key is
left to the app that owns it.

This also closes a second, worse path: ccswitch adopt published the overlay into CC
Switch's common_config_codex, so the stale runtime path would have been injected into
every future provider switch.

Evidence

Recorded reproduction against the previous binary (isolated CODEX_HOME):

step value
baseline notify runtime 2134bcb1950af07e
live notify after app update runtime 81ea4d5168ddd0a3
repair overwritten notify
result runtime 2134bcb1950af07e restored (directory no longer exists)

After the fix, the same scenario with the freshly built binary:

Change : NoChange (score 0, threshold 4)
repair : nothing to repair
verdict: SAFE - kept the live value

Tests

  • New: manual_repair_keeps_an_app_updated_notify — fails on the old behaviour.
  • ignored_matches_app_owned_churn — asserts notify is ignored, and that a genuine
    user-owned registration (mcp_servers.prima-mock-api) is still protected.
  • watch_repairs_a_cc_switch_style_clobber / cc_switch_adopt_publishes_common_config_providers_and_mcp
    — updated to assert app-owned churn is left alone and never published.

Verification gates

cargo fmt --all -- --check                        -> pass
cargo clippy --workspace --all-targets -D warnings -> pass
cargo test --workspace                            -> 27 passed / 0 failed
scripts/apply_watermark.ps1                       -> Inserted 0 (already compliant)

Behaviour change to be aware of

After a CC Switch clobber, notify is no longer restored from the overlay; it is absent
until the Codex app rewrites it. The failure mode changes from silently pointing at a
deleted runtime, indefinitely
to briefly missing, self-healed by the owning app. Users
who maintain notify by hand can protect it again by removing it from ignored in
policy.toml.

Version

Crate 0.1.0-alpha.3, release tag v26.0-Alpha.3.

The Codex desktop app rewrites `notify` with a version-scoped runtime path
(`runtimes\cua_node\<hash>\...`), so a copy captured before an app update goes
stale. Because the explicit `repair` command runs with `manual = true` and merges
without requiring a clobber fingerprint, following the `status` hint after an app
update rewrote the live file to point at a runtime directory that no longer
exists, silently breaking the `turn-ended` Computer Use hook.

`notify` now joins `mcp_servers.node_repl` in the default `ignored` set: neither
protected nor restored. That also stops `ccswitch adopt` from publishing the path
into CC Switch's `common_config_codex`, where it would have poisoned every future
provider switch.

Recorded reproduction: baseline notify -> runtime 2134bcb1950af07e, live notify ->
runtime 81ea4d5168ddd0a3 (app update), `repair` -> `overwritten notify`, stale
runtime restored. After the fix the same scenario reports NoChange and `repair`
performs no action.

Regression coverage: `manual_repair_keeps_an_app_updated_notify`;
`ignored_matches_app_owned_churn`; `watch_repairs_a_cc_switch_style_clobber` and
`cc_switch_adopt_publishes_common_config_providers_and_mcp` now assert the
app-owned key is left alone.

Verified: cargo fmt --check, cargo clippy -D warnings, cargo test --workspace
(27 tests).
@StarsailsClover
StarsailsClover merged commit d41e37f into main Oct 2, 2026
2 checks passed
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.

1 participant