Land PR #41's content into main (was stranded), fix repeated deprecation warning - #44
frostebite wants to merge 2 commits into
Conversation
* Default localCacheMode to move-directory; add EXDEV copy fallback Switches the default local cache mode from tar (archive+extract, copies bytes twice) to move-directory (O(1) atomic rename), matching child-workspace-service's already-proven pattern. tar remains available as an explicit opt-in, e.g. for distributing cache entries via the existing rclone/S3 built-in container hooks. Adds a renameOrCopy fallback in both local-cache-service.ts and child-workspace-service.ts: a cross-volume rename (EXDEV) or permissions failure (EPERM) now degrades to a copy + source cleanup instead of throwing and losing the cache entirely. Previously this was an unhandled failure mode in both services. Updates two existing tests that implicitly relied on tar being the default to explicitly request tar mode, and adds new coverage for the new default and the EXDEV fallback on both restore and save paths. Part of the game-ci/roadmap#11 caching workstream, following on from #40 (canonical-overlay removal). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Rename localCacheMode input to cacheMode "local" no longer accurately describes this input now that distributed caching via the rclone/S3 built-in container hooks is a supported (if not-yet-unified, see #42) path. localCacheMode keeps working as a deprecated alias — existing workflows aren't broken, but get a one-time deprecation warning pointing at cacheMode. Internal call sites now read config.cacheMode. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
PR #41 was stacked on #40's branch and merged into that branch instead of main — #40's branch got squash-merged into main first, so #41's actual payload (move-directory default, EXDEV/EPERM copy fallback, cacheMode rename) never made it to main at all. Cherry-picked the squash commit (fc7b901) onto current main to land it properly. Also fixes a real bug found in review: config.cacheMode's deprecation warning fired on every read (not once as documented) since there was no site tracking it. Two live call sites, so it fired at least twice per action run when only the deprecated `localCacheMode` input was set. Memoized with a module-level flag.
📝 WalkthroughWalkthroughThe PR adds canonical ChangesCache mode and filesystem fallback
Estimated code review effort: 3 (Moderate) | ~20 minutes Mergeability Score: 🟠 High · up to The cache fallback can leave incomplete data in place after a copy failure, potentially causing later restores to use corrupted or partial workspace data. The PR is not merge-ready until the destination replacement and failure cleanup are made safe. Sequence Diagram(s)sequenceDiagram
participant PluginLifecycle
participant LocalCacheService
participant FileSystem
PluginLifecycle->>LocalCacheService: pass resolved cacheMode
LocalCacheService->>FileSystem: restore or save directory
FileSystem-->>LocalCacheService: rename succeeds or returns EXDEV/EPERM
LocalCacheService->>FileSystem: copy recursively and remove source
Possibly related PRs
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 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 |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
src/model/orchestrator/services/cache/local-cache-service.test.ts (1)
218-240: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winAdd
EPERMfallback test cases.
renameOrCopyhandles bothEXDEVandEPERM. The tests only forceEXDEV. AddEPERMcases so the permission-error fallback remains covered.
src/model/orchestrator/services/cache/local-cache-service.test.ts#L218-L240: Add anEPERMrestore fallback case that verifies copy and source cleanup.src/model/orchestrator/services/cache/local-cache-service.test.ts#L297-L320: Add anEPERMsave fallback case that verifies copy and source cleanup.🤖 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/model/orchestrator/services/cache/local-cache-service.test.ts` around lines 218 - 240, Add EPERM fallback coverage in local-cache-service.test.ts at lines 218-240 and 297-320: add restore and save cases that make renameSync throw an error with code EPERM, then verify the operation succeeds via cpSync and removes the source with rmSync, matching the existing EXDEV assertions and setup.
🤖 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.
Inline comments:
In `@src/model/orchestrator/services/cache/child-workspace-service.ts`:
- Line 86: Update ChildWorkspaceService.renameOrCopy and all affected
save/restore call sites to stage copies in a unique sibling temporary path,
rename the completed temporary path to destination only after fs.cpSync
succeeds, and remove the temporary path on failure. Delete source only after
destination replacement completes, preserving destination integrity across EXDEV
and EPERM fallback paths; add failure tests covering both fallbacks.
---
Nitpick comments:
In `@src/model/orchestrator/services/cache/local-cache-service.test.ts`:
- Around line 218-240: Add EPERM fallback coverage in
local-cache-service.test.ts at lines 218-240 and 297-320: add restore and save
cases that make renameSync throw an error with code EPERM, then verify the
operation succeeds via cpSync and removes the source with rmSync, matching the
existing EXDEV assertions and setup.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: ea71151d-c071-4d1d-8b6f-801663dcb25e
📒 Files selected for processing (5)
action.ymlsrc/model/orchestrator/services/cache/child-workspace-service.tssrc/model/orchestrator/services/cache/local-cache-service.test.tssrc/model/orchestrator/services/cache/local-cache-service.tssrc/plugin-lifecycle.ts
| `[ChildWorkspace] Restoring workspace: ${cachedWorkspacePath} -> ${projectPath}`, | ||
| ); | ||
| fs.renameSync(cachedWorkspacePath, projectPath); | ||
| ChildWorkspaceService.renameOrCopy(cachedWorkspacePath, projectPath); |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win
Stage the copy before replacing the destination.
If fs.cpSync fails after it writes target entries, Line 433 throws without removing the partial destination. The save paths have already removed the prior cache. A later restore accepts the nonempty partial cache and can use incomplete workspace or library data.
Copy to a unique sibling temporary path. Rename that path to destination only after the copy succeeds. Remove the temporary path if the copy fails. Delete source only after the destination is complete. Add failure tests for both EXDEV and EPERM fallback paths.
Also applies to: 154-154, 197-197, 249-249, 421-435
🤖 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/model/orchestrator/services/cache/child-workspace-service.ts` at line 86,
Update ChildWorkspaceService.renameOrCopy and all affected save/restore call
sites to stage copies in a unique sibling temporary path, rename the completed
temporary path to destination only after fs.cpSync succeeds, and remove the
temporary path on failure. Delete source only after destination replacement
completes, preserving destination integrity across EXDEV and EPERM fallback
paths; add failure tests covering both fallbacks.
Supersedes #41. Found during a full review pass of this session's PRs: #41 was stacked on #40's branch (
remove-canonical-overlay-cache) and merged into that branch — but #40's branch was squash-merged intomainfirst (22:49:59), 12 seconds before #41 merged into it (22:50:12). So #41's actual payload (defaultcacheMode→move-directory,EXDEV/EPERMcopy fallback,localCacheMode→cacheModerename) never reachedmainat all — it landed on a branch that immediately became orphaned relative tomain.This PR cherry-picks #41's squash commit onto current
mainso the content actually lands, plus one more fix found in the same review pass:config.cacheMode'score.warning(...)call had no memoization and is read from 2+ live call sites (restoreMode,saveMode) — so a workflow using only the deprecatedlocalCacheModeinput got the warning logged at least twice per run, contradicting the intended "warn once" behavior. Fixed with a module-level flag.Verified:
tsc --noEmitclean, full test suite passes (915/916, 1 pre-existing skip) excluding 3 flaky subprocess-spawn CLI-integration tests that time out in this sandbox regardless of this change (confirmed independently reproducible on a clean run with no diff).Closes #41 (superseded — its content is fully included here, plus the warning fix).
Summary by CodeRabbit
New Features
cacheModeconfiguration option for selecting distributed cache behavior.Bug Fixes
Deprecation
localCacheModeis retained as a deprecated alias forcacheMode, with a one-time warning.canonical-overlaymode.