Conversation
Co-authored-by: Codex <noreply@openai.com>
📝 WalkthroughWalkthroughreplaces a complex multi-file codex cli reconciliation system with a streamlined local-index normalization approach. the sync function is no longer declared async but still returns a promise. new internal normalizeIndexCandidate and normalizeStoredFamilyIndexes helpers treat codex cli data as non-authoritative, favoring existing local indexes instead. Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Suggested labels
review notesflagging three explicit concerns:
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches
🧪 Generate unit tests (beta)
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. Comment |
| const candidate = | ||
| typeof raw === "number" | ||
| ? normalizeIndexCandidate(raw, storage.activeIndex) | ||
| : normalizeIndexCandidate(storage.activeIndex, 0); | ||
| return Math.max(0, Math.min(candidate, count - 1)); |
There was a problem hiding this comment.
Critical bug: when raw is a non-finite number (NaN/Infinity) AND storage.activeIndex is also non-finite, the function returns NaN instead of a valid index.
What breaks:
// Example scenario:
storage = {
activeIndex: NaN,
activeIndexByFamily: { codex: NaN },
accounts: [/* some accounts */]
};
getActiveSelectionForFamily(storage, 'codex');
// Returns NaN because:
// - raw = NaN (typeof NaN === 'number' is true)
// - normalizeIndexCandidate(NaN, NaN) returns NaN
// - Math.max(0, Math.min(NaN, count-1)) = NaNFix:
Ensure storage.activeIndex is normalized before using it as a fallback:
const normalizedActiveIndex = normalizeIndexCandidate(storage.activeIndex, 0);
const candidate =
typeof raw === "number"
? normalizeIndexCandidate(raw, normalizedActiveIndex)
: normalizedActiveIndex;| const candidate = | |
| typeof raw === "number" | |
| ? normalizeIndexCandidate(raw, storage.activeIndex) | |
| : normalizeIndexCandidate(storage.activeIndex, 0); | |
| return Math.max(0, Math.min(candidate, count - 1)); | |
| const normalizedActiveIndex = normalizeIndexCandidate(storage.activeIndex, 0); | |
| const candidate = | |
| typeof raw === "number" | |
| ? normalizeIndexCandidate(raw, normalizedActiveIndex) | |
| : normalizedActiveIndex; | |
| return Math.max(0, Math.min(candidate, count - 1)); | |
Spotted by Graphite
Is this helpful? React 👍 or 👎 to let us know.
Co-authored-by: Codex <noreply@openai.com>
Co-authored-by: Codex <noreply@openai.com>
|
@cubic pls review |
@ndycode I have started the AI code review. It will take a few minutes to complete. |
🧩 Analysis chain🏁 Script executed: Length of output: 46 🏁 Script executed: Length of output: 10704 🏁 Script executed: Length of output: 10442 🏁 Script executed: Length of output: 4993 🏁 Script executed: Length of output: 0 🏁 Script executed: Length of output: 0 🏁 Script executed: Length of output: 4631 🏁 Script executed: Length of output: 4460 🏁 Script executed: Length of output: 3388 🏁 Script executed: Length of output: 0 🏁 Script executed: Length of output: 7680
|
| severity | location | issue |
|---|---|---|
| medium | lib/codex-cli/sync.ts:10 |
shallow account clone — maintenance risk for future normalization passes |
| low | lib/codex-cli/sync.ts:69 |
reconcileAttempts metric fires on null no-op path |
| low | lib/codex-cli/sync.ts:84 |
JSON.stringify change detection assumes stable key order — add comment |
| low | test/codex-cli-sync.test.ts |
missing syncAccountStorageFromCodexCli test for fractional/non-finite activeIndex |
| info | test/codex-cli-sync.test.ts:removeWithRetry |
Windows retry window may be too short on slow CI |
logic for mirror-only enforcement, index clamping, skip condition, and concurrency serialization all look correct. 👍
✅ Actions performed
Review triggered.
Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.
Co-authored-by: Codex <noreply@openai.com>
Summary
Why
This is the mirror-sync replacement for the mixed-scope sync slice in
#51.Supersedes #51.
Verification
npm exec vitest run test/codex-cli-sync.test.tsnpm run typechecknpm run lintnpm testnpm run buildNotes
#51Summary by cubic
Keep Codex CLI state mirror-only. Sync stops reading Codex files or seeding canonical storage, and only normalizes local selection indexes (including NaN and fractional values) while avoiding spurious writes.
syncAccountStorageFromCodexClino longer reads Codex files; no-ops when canonical storage is missing, clones current storage, normalizes/clamps indexes, and skips writing missing family keys that resolve to the active index to prevent false “changed” signals.normalizeIndexCandidatetruncates bothvalueandfallback; used bynormalizeStoredFamilyIndexesandgetActiveSelectionForFamilyto handle NaN/fractional cases (including 3+ accounts).loadCodexCliStatecalls), add a NaNactiveIndexclamp test, retain fractional cases, use Windows-safe cleanup viaremoveWithRetrywithETIMEDOUTretries, and keep concurrent writer serialization coverage.Written for commit 310772e. Summary will update on new commits.
note: greptile review for oc-chatgpt-multi-auth. cite files like
lib/foo.ts:123. confirm regression tests + windows concurrency/token redaction coverage.Greptile Summary
this pr correctly narrows
syncAccountStorageFromCodexClito a pure mirror-only operation: it no longer reads codex cli files, seeds canonical storage, or imports account data — it only clamps/truncates local selection indexes and no-ops when canonical storage is missing. two previously flagged correctness bugs are both properly resolved:normalizeIndexCandidatenow truncates the fallback path (preventing fractional indexes from escaping theMath.max/Math.minclamp in 3+ account scenarios), and thenormalizeStoredFamilyIndexesskip logic prevents the falsechanged: truesignal whenactiveIndexByFamilyis empty but all families would resolve to the existing active index.key changes:
normalizeIndexCandidate(value, fallback)now callsMath.trunc(fallback)— not justMath.trunc(value)— closing the float-escape path on the NaN branchnormalizeStoredFamilyIndexesuses!hasFamilyIndex && familyIndex === storage.activeIndexguard to skip redundant family key writes, eliminating spuriousatomicWriteJsoncalls on windows (where extra opens carryEPERM/EBUSYrisk during antivirus scans)syncAccountStorageFromCodexCliis now a pure synchronous computation wrapped inPromise.resolve— zero file i/o, zero token reads, no windows filesystem windowsETIMEDOUTadded toRETRYABLE_REMOVE_CODESin test cleanup — correct for windows temp-dir teardown under heavy ioloadCodexCliStatespy, NaNactiveIndexclamp, fractional 3-account path ingetActiveSelectionForFamily, and theactiveIndexByFamily: {}no-op guardConfidence Score: 4/5
activeIndexByFamilystays sparse after normalization, so a future regression that accidentally re-populates all family keys would not be caught by those testsactiveIndexByFamilyremains emptyImportant Files Changed
normalizeIndexCandidatenow truncates bothvalueandfallback(fixing the float-escape regression);normalizeStoredFamilyIndexesskips writing missing family keys that resolve toactiveIndex(fixing spurious changed signal); no file i/o, no token reads — clean from a windows concurrency and token-leakage perspectiveETIMEDOUTcorrectly added to retryable set; one gap: NaN / OOB tests don't assert activeIndexByFamily remains sparse after normalizationFlowchart
%%{init: {'theme': 'neutral'}}%% flowchart TD A[syncAccountStorageFromCodexCli] --> B{current is null?} B -- yes --> C[reconcileNoops\nreturn storage null, changed false] B -- no --> D[cloneStorage\nnext = copy of current] D --> E[snapshot previousActive\nand previousFamilies JSON] E --> F[normalizeStoredFamilyIndexes next] F --> F1[clamp activeIndex via\nnormalizeIndexCandidate + Math.max/min] F1 --> F2{for each MODEL_FAMILY} F2 --> F3{missing key AND\nresolves to activeIndex?} F3 -- skip write --> F2 F3 -- write value --> F4[set activeIndexByFamily family = familyIndex] F4 --> F2 F2 -- done --> G{previousActive changed\nOR families JSON changed?} G -- changed true --> H[reconcileChanges metric\nreturn storage next, changed true] G -- no change --> I[reconcileNoops metric\nreturn storage current, changed false]Last reviewed commit: 310772e