refactor: abort unreadable config saves with a typed StorageError - #587
Conversation
|
Codex usage limits have been reached for code reviews. Please check with the admins of this repo to increase the limits by adding credits. |
|
Warning Review limit reached
More reviews will be available in 13 minutes and 53 seconds. Learn how PR review limits work. Your organization has run out of usage credits. Purchase more credits in the billing tab to continue. ⌛ How to resolve this issue?After more reviews become available, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available. Please see our Fair Usage Limits Policy for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (3)
✨ Finishing Touches🧪 Generate unit tests (beta)
✨ Simplify code
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 |
Second §4.3 slice (M11), unblocked by #585's merge: the three 'Aborting config save because <path> is unreadable.' throws in savePluginConfig now go through one unreadableConfigSaveError helper returning StorageError with the config path, an UNREADABLE code, an actionable hint, and the classifier's message as the cause. Messages are byte-identical, so existing rejects.toThrow("unreadable") assertions and CLI output are unchanged. New test pins the class, path, code, and exact message through the real savePluginConfig env path. https://claude.ai/code/session_01XNtnkLbBiXZxfQQYLMpucB
54da0c0 to
7544582
Compare
Summary
Aborting config save because <path> is unreadable.throws insavePluginConfignow produce a typedStorageErrorinstead of a bareError. With refactor: throw CodexValidationError from rotation-proxy startup guards #586 (merged) and this PR, the three files §4.3 names carry no bare throws — M11 is fully executed.What Changed
lib/config.ts— one newunreadableConfigSaveError(configPath, errorMessage)helper replaces the three inline throws (env-path branch inside the ESTALE CAS, unified path, legacy path). It returns aStorageErrorcarrying:rejects.toThrow("unreadable")assertions and CLI output are unchanged),code: "UNREADABLE"(following the existing non-errno precedent of"UNKNOWN"in the storage layer),path= the offending config file,causefor debuggability.The typed throw still propagates immediately through the ESTALE
withRetry(its code is notESTALE→ non-retryable), exactly as before.docs/reference/error-contracts.md— adds thesavePluginConfigguarantee to the "Typed Error Classes" section that #586 introduced (branch rebased onto post-#586mainso the section exists here).test/config-save.test.ts— new test pinning the class,path,code, and exact message through the realsavePluginConfigenv path, alongside the three existing unreadable tests which pass unchanged.Validation
npm run typecheck(also in the pre-commit hook)npx eslint lib/config.ts test/config-save.test.ts --max-warnings=0npm test -- test/config-save.test.ts— 21/21 (the three pre-existing unreadable-abort tests pass without modification, proving message compatibility)maincompleted just before this branch: exactly the 58-name environment baseline, zero new namesnpm run builddeferred to CIDocs and Governance Checklist
docs/reference/error-contracts.mdupdated in the same PR as the behavior it documentsStorageError extends CodexError extends Error, so allinstanceof Errorhandling is unaffectedRisk and Rollback
https://claude.ai/code/session_01XNtnkLbBiXZxfQQYLMpucB
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
replaces three inline
new Error(...)throws insavePluginConfigwith a typedStorageErrorvia a newunreadableConfigSaveErrorfactory, satisfying audit §4.3. the"UNREADABLE"code is not in the ESTALEwithRetry'sretryableCodeslist, so retry behavior is unchanged; message text is byte-identical, preserving existing test assertions.lib/config.ts: adds theunreadableConfigSaveErrorfactory returning aStorageErrorwithcode,path,hint, andcause; all three unreadable-abort throw sites updated.test/config-save.test.ts: new test verifiesinstanceof StorageError,path,code, and message through the env-path branch with anEBUSYread spy.docs/reference/error-contracts.md: one-line contract guarantee added forsavePluginConfig's new typed error.Confidence Score: 4/5
safe to merge; the only observable change is richer metadata on the thrown error object — message text, throw conditions, and retry behavior are all identical to before
the three throw sites are straightforward substitutions, the ESTALE retry loop correctly non-retries the new StorageError (code "UNREADABLE" is absent from retryableCodes: ["ESTALE"]), and the new test covers the core contract. the savePluginConfig JSDoc block is left orphaned above the helper, which is a cosmetic gap but doesn't affect runtime behavior.
lib/config.ts — the original savePluginConfig JSDoc block is now detached from the function; worth fixing before merging to keep IDE hover docs accurate
Important Files Changed
Sequence Diagram
sequenceDiagram participant C as Caller participant S as savePluginConfig participant R as readConfigRecordForSave participant F as unreadableConfigSaveError participant W as withRetry (ESTALE) C->>S: savePluginConfig(patch) S->>W: withRetry([ESTALE], op) W->>R: readConfigRecordForSave(path) alt "status === "unreadable"" R-->>W: "{ status: "unreadable", errorMessage }" W->>F: unreadableConfigSaveError(path, msg) F-->>W: "StorageError(code="UNREADABLE")" note over W: "UNREADABLE" not in ["ESTALE"] → rethrow immediately W-->>S: throws StorageError S-->>C: throws StorageError else "status === "ok" or "missing"" R-->>W: config record W->>W: merge + write W-->>S: void S-->>C: void endPrompt To Fix All With AI
Reviews (1): Last reviewed commit: "docs: record the savePluginConfig typed-..." | Re-trigger Greptile