Skip to content

[Bug] ocx sync overwrites hand-edited config.json from stale server memory (GLM-5.3 tune lost); 2.21.0 save path fixed it but sync path question remains #1802

Description

@DaveW001

Summary

A hand-edited config.json (adding glm-5.3 to the zai provider) was silently reverted by an ocx sync while the long-lived proxy server was running. The running server held the pre-edit config in memory; the sync-triggered service-time save serialized the stale copy over the disk file. This is the bug class from #488 (closed). In 2.21.0 the normal save path was fixed to re-read disk first (verified: a later service-time write preserved the hand-edit), but we have not confirmed whether the ocx sync write path was part of that fix or still uses the stale in-memory config.

Environment

  • opencodex 2.21.0 (npm @bitkyc08/opencodex), Windows, service mode via scheduled task (opencodex-service.cmd wrapper, bun runtime, start --port 10101)
  • Config at %USERPROFILE%.opencodex\config.json

Timeline (2026-08-15, America/New_York, EDT)

Time Event
14:02:56 Hand-edit applied to disk: glm-5.3 added to all six zai provider spots (models, modelContextWindows, modelReasoningEfforts, noVisionModels, preserveReasoningContentModels, modelReasoningEffortMap)
14:03:05 ocx sync run against long-lived server (old PID 45428, started 8/13)
14:04:46 config.json rewritten: tune gone; opencode-go/glm-5.3 auto-added to disabledModels
14:21:56 / 14:22:08 Second re-apply, clobbered again by second ocx sync
14:50:48 / 14:51:11 npm install -g @bitkyc08/opencodex@latest -> 2.21.0; startup migration rewrites config (qwen rename only; never touches zai)
14:53:06 Service restart; new server (PID 55940) loads the already-reverted file (so the upgrade gets blamed for a loss that happened 46 minutes earlier)
15:06:28 / 15:06:37 Third re-apply + ocx sync - this one survived, consistent with 2.21.0 save path re-reading disk before writing
15:18:44 Another service-time write; tune still intact

Evidence

  • Backup diffs: pre-tune vs post-clobber differ ONLY by the disabledModels line; the tune appears in none of the backups because each backup was taken from already-clobbered or pre-tune state.
  • config-mutation.sqlite records the writes (RCA copy retained).
  • npm debug log confirms the 2.21.0 install completed at 14:51, after the first clobber at 14:04:46.

Ask

  1. Does the ocx sync path (and any other management/GUI write path) in current code re-read config from disk before saving, or can it still serialize a stale in-memory copy over a hand-edit?
  2. If the sync path still saves from memory, can it adopt the same disk-rebase approach as the fixed save path?

Impact / prevention on our side

Documented runbook guard: hand-edit -> restart proxy before any ocx sync/GUI toggle; snapshot -> validate -> diff after every upgrade/sync; config.json now git-tracked locally for one-command rollback.

Activity

  1. coderabbitai commented on Aug 16, 2026

    @coderabbitai
    Contributor
    🔗 Related PRs

    #518 - fix(codex): warn or restart stale app-server after sync [open]
    #576 - fix(codex): warn about stale Codex app-servers after a catalog write [merged]
    #889 - fix(providers): Copilot mixed-wire routing, DeepSeek service_tier + reasoning replay, Claude 4.6/4.7 1M windows [open]
    #892 - fix: bound the six remaining retained-state leaks (#820 wave 2) [merged]
    #1331 - fix(catalog): keep failover combos when live discovery omits members [merged]


    📝 Issue Planner

    Check the box below or use the @coderabbitai plan command to generate an implementation plan and prompts that you can use with your favorite coding assistant.

    • Create Plan

    🧪 Issue enrichment is currently in open beta.

    To disable automatic issue enrichment, add the following to your .coderabbit.yaml:

    issue_enrichment:
      auto_enrich:
        enabled: false

    💬 Have feedback or questions? Drop into our discord!

  2. github-actions commented on Aug 16, 2026

    @github-actions
    Contributor

    Maintainer decision respected

    A maintainer has reopened this issue. The automated closure has been deactivated.

  3. reopened this on Aug 16, 2026
  4. lidge-jun commented on Aug 16, 2026

    @lidge-jun
    Owner

    Fixed on dev by #1848 (merged as 73440d4bb) — though the code path was already correct; what was missing was proof.

    POST /api/sync calls loadConfig() at its own route boundary (src/server/management/config-routes.ts:383), and syncModelsToCodex writes Codex artifacts rather than OpenCodex config.json. Combined with the 2.21.0 save-path fix, the reported clobber is no longer reachable.

    The regression added here starts a server, hand-edits config.json out of band so disk is strictly newer than the server's snapshot, then calls /api/sync and asserts against the FILE — because the failure being prevented is the route persisting a caller-held snapshot back over it. It was driven red first by making the route save its held config: the hand-edited provider disappears and the test fails.

    Closing as completed. The change is on dev and ships with the next release; it is not in a published version yet.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingcliCLI, config inject, packaging flags

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions