Skip to content

feat(toggles): Codex restore truth, Claude Desktop switch, composed acceptance (WP13 resume) - #1106

Merged
lidge-jun merged 52 commits into
devfrom
codex/260806-wp13-toggles
Aug 6, 2026
Merged

lidge-jun merged 52 commits into
devfrom
codex/260806-wp13-toggles

Conversation

@lidge-jun

@lidge-jun lidge-jun commented Aug 6, 2026

Copy link
Copy Markdown
Owner

Summary

Resumes the paused WP13/WP14 tail of the Codex write-substrate campaign: the Codex CLI toggle gets artifact-level restore truth, Claude Desktop gets a real ON/OFF toggle with a documented standard-mode pivot, and a composed acceptance suite proves the production entry points reach the substrate instead of writing around it.

  • Codex toggle completion (devlog/_plan/260803_codex_desktop_toggle/040 as amended by 260806_wp13_toggles_resume/010): ocx restore/eject persist desired OFF before mutating (crash-durable), restore back/eject back persist ON; restoreNativeCodexAsync returns a per-artifact {config, catalog, history} envelope where history failure carries a busy | permission discriminator instead of being folded into success; every syncModelsToCodex caller (startup, ensure, sync, restore dispatch, models, provider, POST /api/sync, toggle enable) branches on a discriminated applied/skipped/refused status; desired state is re-read inside each artifact serializer (write lock, history serialization, catalog commit, cache reacquisition) so a lost race becomes a typed skip, never a stale write.
  • Claude Desktop toggle (050 as amended by 020): claude-desktop joins clientIntegrations and the native route union; a read-only inspector classifies not_installed/standard/gateway_ours/gateway_drifted/foreign/no_owned_state/broken/unsafe with an ownership boundary (owned-but-drifted refuses as unsafe; reads never create files); OFF pivots to a credential-free {} standard profile before removing the opencodex profile, its backup, and its metadata row; all four writer paths (auto-apply, native enable, POST /apply, no-daemon CLI apply) re-read persisted intent after their awaits; desiredEnabled is required on post-commit refusals for every client; GUI switch with six-locale copy.
  • Composed acceptance (issue WP13: composed acceptance at the production boundary #1048, reduced workstation scope per 030): tests/codex-composed-acceptance.test.ts runs six scenarios through real spawned CLI children and a real HTTP server on temp homes — entry-to-funnel manifests, lost transition via HTTP, foreign-home zero-artifact refusal, same-user cross-home single lock, Grok OFF surviving a real restart, and restore truth via the new ocx restore --json. Building it exposed four real production holes (OFF paths creating artifacts in CODEX_HOME, POST /api/sync trusting the server-captured config, foreign homes accepted over HTTP, opaque busy results), all fixed here. The disposable-host service class (P09/P10/P18/P34-P36) and remaining census rows stay deferred; WP13: composed acceptance at the production boundary #1048 remains open (referenced, not closed).

Verification

  • bun x tsc --noEmit — clean at every commit.
  • bun scripts/test.ts (full suite) — 9242 pass / 8 skip / 1 fail; the single failure (issue-quality workflow rejects workflow_dispatch pull request numbers before mutation in tests/ci-workflows.test.ts) is pre-existing on origin/dev (reproduced on a clean detached worktree at e496e9bfe) and untouched by this branch (git diff origin/dev...HEAD touches no workflow files).
  • bun run lint:gui, bun run privacy:scan, bun run build:gui — green.
  • Composed suite stable across 3 consecutive runs; six per-scenario broken-change proofs executed (mutate mechanism → red, restore → green, clean diff).
  • Live temp-home proof: PUT /api/native-integrations/claude-desktop OFF on a not_installed home returns an idempotent no-op with zero filesystem footprint and persisted clientIntegrations["claude-desktop"]: false; GET lists all four clients.
  • Independent review: every work-phase was audited by a reviewer subagent that did not write the code; all blockers across seven review rounds were fixed or rebutted with evidence before close.

GUI change screenshot (Integrations overview with the Claude Desktop switch and the four native rows):

integrations overview

Related: #1048 (stays open — workstation subset landed here, service-class scenarios still deferred).

Checklist

  • Scope stays focused and avoids unrelated cleanup.
  • Docs or release notes were updated when needed (devlog unit 260806_wp13_toggles_resume/ documents the roadmap, amendments, and deferred rows).
  • Security-sensitive changes were reviewed for secrets, auth, and unsafe defaults (credential-bearing Desktop profiles are removed on disable and never echoed into envelopes, logs, or tests; lock ids disclose only path hashes).

Summary by CodeRabbit

  • New Features

    • Added Claude Desktop integration toggling, status reporting, enable/apply actions, and localized messages.
    • Added persistent desired-state controls for Codex, Claude Desktop, and Grok.
    • Added clearer synchronization and restore outcomes, including skipped, refused, failed, and incomplete states.
    • Added safeguards for foreign configurations, unsafe metadata, cleanup residue, and concurrent changes.
  • Bug Fixes

    • Prevented disabled integrations from writing configuration or cache updates.
    • Improved restore reporting while preserving externally managed profiles.
    • Added warnings when applied settings cannot be fully persisted.
  • Tests

    • Expanded coverage for toggles, races, cleanup, restoration, isolation, and CLI behavior.

…tating today, full sync-caller gating, workstation-only 030 leaves #1048 open)
The commit-path OFF check runs under the first catalog permit; the
models_cache rewrite reacquires K after release, so a disable landing in
the gap could still publish a routed cache. Re-read intent under the
second permit too.
…status

The inspector now carries ownedProfileActive (ID-match tri-state, null when
metadata or appliedId is absent/unreadable) so the status route stops
flattening undeterminable into false.
The toggle field names the API wire id (claude-desktop) which is not an
OverviewClientId; widen the union explicitly. The status parser narrowed on
fields absent from its readOptional shape.
…sts:write

Pre-existing red on origin/dev (run 31078958589 and a clean dev worktree
both fail it); the permissions gate now matches the migrated workflow.

@Ingwannu Ingwannu left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

This campaign is high-value, but the current head must be rebased before I can approve it.

The important boundaries are in the right place: OFF intent is persisted before mutation; config/history/catalog/cache writers re-read intent inside their serialization boundary; restore returns artifact-level truth instead of folding history failure into success; Claude Desktop removal pivots to a credential-free standard profile and refuses owned-but-drifted state; and the composed suite drives real CLI/HTTP entry points rather than only helpers. Those are meaningful correctness improvements, not cosmetic toggle work.

Current blocker: head 39f452ac is 8 commits behind dev and GitHub reports it conflicting. I reproduced the merge against a5b37827; the only conflict is tests/ci-workflows.test.ts. Current dev intentionally accepts either copilot-requests: write or the migration-era models: read, while this branch re-tightens the assertion to Copilot only. Please rebase onto current dev and keep the current dev assertion unless the workflow itself is being changed in this PR. The source/runtime changes merge without conflict.

Local current-dev merge validation after resolving that test conflict with the dev version:

  • 12 focused Codex/Claude Desktop toggle, restore, sync, lock, and composed suites: 100 passed; one native-codex-toggle case exceeded its 5 s timeout under the concurrent CPU-limited run and caused 3 cascading failures
  • isolated rerun of tests/native-codex-toggle.test.ts: 6 passed, 0 failed (the timed case completed in 180 ms)
  • bun run typecheck: passed

Because this touches credential-bearing Desktop profiles, persistent desired state, cross-process locks, management writers, and GUI controls, the rebased exact head needs the full required CI and GUI gates before approval. Please rebase rather than merge dev into the branch again, rerun the suite, and request review on the new SHA.

The route persisted desired ON, then saved the whole long-lived server
snapshot -- whose clientIntegrations still said OFF -- back over it, so its
post-await guard refused the apply it had just been asked to perform.
Persist only the desktopProfile field under the config-mutation lock, and
route the writer through the deps seam its sibling path already uses.
setIntegrationEnabled writes disk only, and the server reuses one config
object per request, so the native GET reported OFF right after a successful
apply and the profile PUT wrote that stale OFF back. Mirror the transition
onto the snapshot, and surface an unavailable profile mutation instead of
dropping it.
…ccess

The route already reported saved:false with a warning when the applied
marker failed to persist, but both front ends discarded it and announced a
clean save+apply. GUI shows a warn-tone notice (six locales), CLI prints the
warning after a successful apply.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/server/management/agent-settings-routes.ts (1)

177-208: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Use field-scoped persistence for auto-apply bookkeeping.

saveConfigPreservingClaudeCode(current) writes the complete current snapshot after the Desktop artifact write. A concurrent process can change clientIntegrations or another config field after Line 189. This save can restore the stale value.

Use persistDesktopProfileField to store only claudeCode.desktopProfile with the new fingerprint and timestamp. That helper rebases against current disk state under the config mutation lock.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/server/management/agent-settings-routes.ts` around lines 177 - 208,
Replace the full-snapshot saveConfigPreservingClaudeCode call in the
result.written && result.fingerprint block with persistDesktopProfileField,
passing the updated claudeCode.desktopProfile fingerprint and timestamp.
Preserve the existing bookkeeping values while ensuring persistence is scoped
only to claudeCode.desktopProfile.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@src/server/management/agent-settings-routes.ts`:
- Around line 177-208: Replace the full-snapshot saveConfigPreservingClaudeCode
call in the result.written && result.fingerprint block with
persistDesktopProfileField, passing the updated claudeCode.desktopProfile
fingerprint and timestamp. Preserve the existing bookkeeping values while
ensuring persistence is scoped only to claudeCode.desktopProfile.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 766ba33f-3b44-4830-b844-084abb919520

📥 Commits

Reviewing files that changed from the base of the PR and between 39f452a and 38d3834.

📒 Files selected for processing (15)
  • gui/src/i18n/de.ts
  • gui/src/i18n/en.ts
  • gui/src/i18n/ja.ts
  • gui/src/i18n/ko.ts
  • gui/src/i18n/ru.ts
  • gui/src/i18n/zh.ts
  • gui/src/pages/ClaudeDesktop.tsx
  • gui/src/ui.tsx
  • src/cli/claude-desktop.ts
  • src/config.ts
  • src/server/management/agent-settings-routes.ts
  • src/types.ts
  • tests/ci-workflows.test.ts
  • tests/claude-messages-endpoint.test.ts
  • tests/native-claude-desktop-toggle.test.ts

@lidge-jun
lidge-jun merged commit 43a1fdc into dev Aug 6, 2026
30 checks passed
lidge-jun added a commit that referenced this pull request Aug 6, 2026
…-margin

Restores dev to green after #1106: the contended-restore case needed a watchdog wide enough for production's own retry budget. Test-only.
@lidge-jun
lidge-jun deleted the codex/260806-wp13-toggles branch August 8, 2026 00:49
agentHits pushed a commit to agentHits/opencodex that referenced this pull request Sep 17, 2026
…ggles

Merging the WP13/WP14 toggle resume after an independent completeness audit (4 rounds) closed three real defects: the self-cancelling /apply enable, in-process snapshot incoherence, and an unconsumed partial-success envelope. Issue lidge-jun#1048 stays open for the deferred disposable-host census rows.
agentHits pushed a commit to agentHits/opencodex that referenced this pull request Sep 17, 2026
…-watchdog-margin

Restores dev to green after lidge-jun#1106: the contended-restore case needed a watchdog wide enough for production's own retry budget. Test-only.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants