Skip to content

fix(catalog): preserve config edits during auto-refresh - #578

Closed
luvs01 wants to merge 7 commits into
devfrom
codex/fix-vulnerability-in-catalog-auto-refresh
Closed

luvs01 wants to merge 7 commits into
devfrom
codex/fix-vulnerability-in-catalog-auto-refresh

Conversation

@luvs01

@luvs01 luvs01 commented Sep 21, 2026

Copy link
Copy Markdown
Owner

Motivation

  • The auto-refresh scheduler loaded a fresh config snapshot and passed it into convergence without arming the per-instance rebase baseline, which allowed an in-flight discovery to overwrite concurrent hand edits to config.json.
  • Arming it with the live-server policy was not enough: saveConfigPreservingClaudeCode excludes hostname/port and disk-only keys from the rebase, so a discovery save still serialized the stale snapshot over those operator edits (Devin Review + Codex P2 on da8f326).
  • A concurrent hand edit to disabledModels also lost to the tick's discovery-appended array as an opaque same-leaf conflict (Devin Review on a7b7adb).

Description

  • Add armDetachedConfigBaseline(config) in src/config/live-reconcile.ts (exported via src/config.ts): arms the same baselines as armClaudeCodeBaseline and additionally marks the instance in a detachedConfigSnapshots WeakSet.
  • In saveConfigPreservingClaudeCode, a detached snapshot reconciles every top-level key against its arming baseline — no hostname/port skip, no disk-only-key exclusion, and configRebaseProvenance merges like a normal key. Deletion intent is read post-merge so an adopted disk-side marker is honored while a stale load-time marker cannot clobber a re-added key. A detached snapshot cannot express a deliberate deletion and owns no live socket, so the fix(config): rebase stale live saves lidge-jun/opencodex#1462 hazards the live-mode skips guard against do not apply; the long-lived server path is unchanged.
  • disabledModels now merges member-wise in reconcileConfigRecord (same pattern as customModels): a slug either side deleted stays deleted, while slugs added on either side — discovery arrivals or hand-hidden rows — are kept. Applies to live saves too, where the same wholesale-loss hazard existed.
  • src/codex/catalog-auto-refresh.ts arms each tick's snapshot via armDetachedConfigBaseline immediately after loadConfig().
  • Tests: extended tests/codex-integration/catalog-auto-refresh-scheduler.test.ts (mid-flight port/hostname/metricsExport hand edits survive a discovery-changing save; existing catalogAutoRefresh edit test retained) and added coverage in tests/config/config-user-edits.test.ts (detached listener + disk-only + claudeCode adoption; disabledModels member-merge for detached and live saves).
  • Update structure/config.md to document the detached-baseline guarantee and the member merge.

Testing

  • bun run typecheck — clean.
  • bun test tests/codex-integration/catalog-auto-refresh-scheduler.test.ts tests/config/config-user-edits.test.ts — 56 passed, 0 failed.
  • bun test tests/codex-integration/model-visibility-management-api.test.ts tests/config/config-save-boundary.test.ts tests/codex-integration/codex-convergence-contract.test.ts tests/codex-integration/codex-config-generation.test.ts — 60 passed, 0 failed.
  • bun run structure:check and bun run privacy:scan — both passed.
  • bun run test:changed — ran 1050 files against the dev merge base; hit the suite's 900s cap mid-run with failures only in unrelated domains (parallel-run spend-ledger owner conflicts, OAuth/Anthropic e2e timeouts) matching the pre-existing suite failures documented previously.

Codex Task

Link to Devin session: https://app.devin.ai/sessions/6fc19413a5a143c0be89e5a9805ba86d
Open in Devin Desktop: https://app.devin.ai/desktop/session/6fc19413a5a143c0be89e5a9805ba86d?variant=devin
Requested by: @luvs01


Devin Review

devin-ai-integration Bot and others added 2 commits September 20, 2026 13:22
…forwarded role (lidge-jun#5334 follow-up)

lidge-jun#5334 made the developer wire role tri-state: an undeclared destination folds
it to system. Two suites asserting role:"developer" on the Chat wire were
missed because they are about tool-result repair ordering and document parts,
not role selection — declare the destination, per the convention the change
established.

Verified: both files fail on dev@600075d2 with system-for-developer wire roles
and pass with the declaration.

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
@coderabbitai

coderabbitai Bot commented Sep 21, 2026

Copy link
Copy Markdown

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration

Configuration used: Repository: luvs01/opencodex/.coderabbit.yaml

Review profile: ASSERTIVE

Plan: Advanced

Run ID: e7fe1ce2-398b-4e33-899f-09fba6b1e8aa


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 21, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-09-21T00:26:38.452468Z da8f326 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@github-actions

Copy link
Copy Markdown

Deterministic PR hygiene checks passed.

@github-actions github-actions Bot added the bug Something isn't working label Sep 21, 2026
devin-ai-integration[bot]

This comment was marked as resolved.

chatgpt-codex-connector[bot]

This comment was marked as resolved.

… save

Devin Review on da8f326: arming the auto-refresh tick's snapshot with the
live-server policy still dropped edits to hostname/port and to keys absent
from the snapshot, because saveConfigPreservingClaudeCode excludes both from
the rebase and the write then serializes the stale snapshot.

Add armDetachedConfigBaseline() so a config nobody holds long-term reconciles
every field against its arming baseline: the listener binding, disk-only
keys, and a disk-side configRebaseProvenance marker all merge in, and
deletion intent is read post-merge so an adopted marker is honored while a
stale load-time marker cannot clobber a key disk re-gained.

Co-Authored-By: Epinephrine <luvs01@hanmail.net>
devin-ai-integration[bot]

This comment was marked as resolved.

devin-ai-integration Bot and others added 2 commits September 21, 2026 05:57
…y-in-catalog-auto-refresh

Co-Authored-By: Epinephrine <luvs01@hanmail.net>

# Conflicts:
#	tests/adapters/openai/openai-chat-dangling-toolcalls.test.ts
#	tests/responses/chat-inline-document-bytes.test.ts
Devin Review on a7b7adb: a hand edit to disabledModels mid-refresh
conflicted with the tick's discovery-appended array as an opaque leaf, so
the save published the stale snapshot's list and dropped the operator's
visibility change.

Give the field the customModels treatment: reconcile it member-wise so a
slug either side deleted stays deleted while slugs added on either side —
discovery arrivals or hand-hidden rows — are all kept. Applies to live
saves as well, where the same wholesale-loss hazard existed.

Co-Authored-By: Epinephrine <luvs01@hanmail.net>
devin-ai-integration[bot]

This comment was marked as resolved.

devin-ai-integration Bot and others added 2 commits September 21, 2026 06:04
src/config.ts sits exactly at the file-size ratchet baseline; pair the two
arming exports on one line so the new armDetachedConfigBaseline export does
not grow the file.

Co-Authored-By: Epinephrine <luvs01@hanmail.net>
…egraded runner

The 30s timeout on 'usage byte-prefix truncation and entry-count truncation
report independent metadata' (tests/usage/usage-log.test.ts) is environmental:
the same test ran in 3.96s on dev's macos 2/2 leg on the identical runner image
two hours earlier, the branch does not touch src/usage/, and the read path's
~500 cooperative setTimeout(0) yields make it uniquely sensitive to event-loop
starvation on a saturated runner (suite overall ran 1.2x slower).

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
@luvs01

luvs01 commented Sep 21, 2026

Copy link
Copy Markdown
Owner Author

Closing: superseded by combined PR #612, which carries this PR's auto-refresh edit preservation (�rmDetachedConfigBaseline) together with the desktop-apply guard rebase and async policy probe on current dev. Combined tests: 91 pass (4 baseline-identical timeouts).

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

Labels

aardvark bug Something isn't working codex

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant