fix(codex): preserve per-app approval reviewer policy#97327
Conversation
|
Codex review: needs real behavior proof before merge. Reviewed June 29, 2026, 5:29 AM ET / 09:29 UTC. Summary PR surface: Source +59, Tests +165. Total +224 across 8 files. Reproducibility: yes. at source level: current main lacks app-level reviewer assignment and resume replay for persisted plugin app config, while PR-head source and tests cover the expected behavior. I did not run a live current-main repro in this read-only review. Review metrics: 2 noteworthy metrics.
Stored data model Merge readiness Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch. Rank-up moves:
Proof guidance:
Mantis proof suggestion Risk before merge
Maintainer options:
Next step before merge
Security Review detailsBest possible solution: Land this direction only after maintainers accept exact-head proof for read/no-elicitation, destructive approval or rejection without side effects, and resume/recovery policy replay. Do we have a high-confidence way to reproduce the issue? Yes at source level: current main lacks app-level reviewer assignment and resume replay for persisted plugin app config, while PR-head source and tests cover the expected behavior. I did not run a live current-main repro in this read-only review. Is this the best way to solve the issue? Yes for the code direction: OpenClaw owns the plugin app config patch and binding replay, and upstream Codex supports app-level reviewer selection. It is not merge-ready until current-head real behavior proof covers the user-visible plugin app path. AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning high; reviewed against ff1e7e1305cc. Label changesLabel justifications:
Evidence reviewedPR surface: Source +59, Tests +165. Total +224 across 8 files. View PR surface stats
What I checked:
Likely related people:
What the crustacean ranks mean
Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics. How this review workflow works
|
|
@clawsweeper re-review The PR body now includes redacted executable output from the production cache-key implementation, captured and replay-verified in an isolated OpenClaw integration workspace. It shows the serialized key contains both build versions and changes when either version changes independently. No gateway, deployment, devbox, or external service was started. |
|
🦞🧹 I asked ClawSweeper to review this item again. |
|
Small proof/lifecycle note before the re-review: the updated PR body proves the lower-level In the PR head,
So I’d be careful about treating the new proof as evidence that a still-running OpenClaw process observes an installed Codex plugin version change. It demonstrates the serializer/key shape, not the runtime wrapper observing changed package metadata after startup. If the intended contract is “distinct cache scope after process/plugin module reload,” this patch shape looks consistent; if the target is same-process upgrade invalidation, the version read probably needs to happen at the reload/install boundary or per key-build instead of as a module-level constant. |
|
Good distinction. The intended contract here is a distinct cache key for runtime/plugin module instances loaded with different build identities, not same-process observation of package metadata changing after module evaluation. I updated the PR body to state that lifecycle boundary explicitly and to list same-process hot package updates under “What was not tested.” The code still reads |
|
Merged via squash.
|
What Problem This Solves
Fixes an issue where enabling Codex plugins could overwrite a thread's approval reviewer globally, causing non-destructive app reads to inherit user review and making resumed or recovered threads diverge from the original per-app policy. It also fixes stale Codex app inventories after plugin upgrades.
Why This Change Was Made
Plugin configuration now leaves the top-level reviewer untouched and assigns
approvals_reviewer: "user"only to concrete enabled apps whose resolved destructive-action mode isalways. The same resolved policy is persisted and replayed for resume and recovery, while the inventory cache key includes the app/plugin version so upgraded inventories refresh.The patch relies on Codex's native app tool approval-mode semantics instead of doing pre-start MCP tool discovery, so configured apps are not hidden before their thread-effective config exists. Existing app enablement, destructive/open-world flags, tool approval modes, activation validation, and fail-closed defaults remain intact.
AI-assisted: yes. Codex implemented the changes and completed a clean repository autoreview.
User Impact
Calendar and other read-only app actions can continue without an unnecessary user-review override. Apps with an effective
allow_destructive_actions = "always"still route destructive approvals to the user at the app boundary, whileauto,allow, anddenyinherit the thread's configured reviewer. The behavior remains consistent after thread resume, recovery, and replay.Evidence
0ab4bbd175: Google Calendar read returnedCALENDAR_READ_OK 7without elicitation. A Calendar write reachedcreate_event, was rejected by the configured auto reviewer, emitted no Slack elicitation, and an exact-title search confirmed that no event was created.Commands:
Real behavior proof
_defaultreviewer; only concrete enabled apps with effective destructive modealwaysreceive the user reviewer. App inventory must refresh after plugin version changes and persisted policy must replay identically.openclaw-debug:per-app-reviewer-final-0ab4bbd175-20260629t082935z(linux/amd64, local image IDsha256:3a1999f55f14…) built from a clean detached worktree at exact PR head0ab4bbd175, with a healthy gateway at127.0.0.1:18789. It was exercised through thekevinlinSlack/OpenClaw integration profile with the required five-plugin policy (google-calendar=auto,linear=always). The remoteopenclaw-gateway-kevinlinStatefulSet remained at zero replicas and its pod was absent.dist/thread-lifecycle-*reviewer branches, replaced the isolated local gateway container, verified health and plugin policy, then sent the canonical Google Calendar read and write/read-back requests through Slack. After the rejected write, searched Calendar for the exact unique title in the bounded test window.CALENDAR_READ_OK 7with no elicitation. The write request reachedcodex_apps.google_calendar.create_eventtwice; both tool results wereuser rejected MCP tool call, the Slack thread reported that no event was created, and a direct exact-title search returned zero events. Final focused tests passed 202/202, the filtered run-attempt test passed, exact-head CI passed, oxlint passed, and autoreview was clean._default, disabled patches, and all non-alwayseffective modes, plus per-app user review for inherited or explicitalwaysacross initial and reconstructed patches.google-calendar=auto, and its auto reviewer rejected the destructive call without emitting a Slack approval card. The live probe therefore proves final-head read behavior and the write rejection/no-side-effect path, while per-appalways → userrouting and resume/recovery replay remain covered by focused tests rather than a livealwaysCalendar profile. The fullrun-attempt.test.tsfile was not green locally: three environment-dependent tool-policy tests saw the local computer-use/MCP delegation configuration; the directly affected resume-policy case passed. Localpnpm check:changedwas blocked before checks by a registry403fetchingacpx.