Skip to content

feat(checkpoints): shadow restoreFile service for per-file rollback (B3c v2-10, epic #1375) - #53

Open
easonLiangWorldedtech wants to merge 1 commit into
feat/fws-v2-9-settings-uifrom
feat/fws-v2-10-shadow-restore-service
Open

feat(checkpoints): shadow restoreFile service for per-file rollback (B3c v2-10, epic #1375)#53
easonLiangWorldedtech wants to merge 1 commit into
feat/fws-v2-9-settings-uifrom
feat/fws-v2-10-shadow-restore-service

Conversation

@easonLiangWorldedtech

Copy link
Copy Markdown
Owner

What this PR does

The service half of the per-file/per-step rollback feature (B3c, epic Zoo-Code-Org#1375), stacked on #52 (v2-9):

  • ShadowCheckpointService.restoreFile(commitHash, filePath): restores a single file to its state at commitHash without moving the branch or truncating the checkpoint list (unlike restoreCheckpoint). A file that did not exist at the checkpoint is removed from the working tree instead — rolling a file back to before it was created. Defensive behavior: lexical path-containment guard (plus a realpath re-check on the destructive branch to see through symlinked ancestors), Windows backslash normalization for git pathspecs, and an evidence-based commit-object check before the delete branch can run.
  • fileExistsInCommit (private): verifies the commit object with rev-parse --verify first (simple-git's cat-file -e rejects silently on a bad hash, which the delete branch would misread as "file absent"), then probes the tree with cat-file -e <sha>:<path>.
  • ShadowCheckpointService.spec: a restoreFile describe covering the happy path, file-absent-at-checkpoint delete, Windows separator normalization, path-escape rejection (..), symlink-escape rejection, invalid-hash rejection, and the uninitialized-shadow-git error path.

Line count / split rationale

264 changed lines (264+/0-) across 2 files — pure additions, below the 400 soft design target.

Plan note: the approved v2 plan placed the rollback core at #v2-10 and this service at #v2-11 (rows B12/B13). The rollback core (rollback.ts) calls service.restoreFile(...) at compile time, so the service PR must land first; the two PRs' content is therefore swapped relative to the plan rows, with the slugs renamed to match. The plan's Stryker invariant — every killing test for a PR's diff lines stays in the same PR — is preserved: this PR's diff is exactly the service lines and the killing restoreFile describe, and #v2-11 carries the rollback core with its full spec.

Provenance

Not included here (later v2 PRs)

  • Rollback core (rollback.ts + full rollback.spec.ts + changeJournal ENOENT-only journal delta) — v2-11.
  • Rollback UI + remaining epic work — v2-12..v2-15.

Local gates

  • tsc --noEmit (src): clean.
  • Vitest (services/checkpoints + core/checkpoints): 7 files, 108 tests passed.
  • ESLint --prune-suppressions --max-warnings=0 on the 2 touched files: clean; src/eslint-suppressions.json counts unchanged.
  • Prettier: both files content-clean under the repo config (LF-normalized API audit).
  • Stryker diff gate (base 7ae24aff5 = feat(settings): change card detail control in CheckpointSettings + webview default (B3a v2-9, epic #1375) #52 head; the branch was re-based onto the re-baselined v2-9 chain before push): 54 changed-code mutants, 54 Killed, 0 Survived, 0 NoCoverage (41 changed executable lines).

@easonLiangWorldedtech easonLiangWorldedtech added coderabbit-review-active Required CI passed; CodeRabbit review is active awaiting-coderabbit Waiting for CodeRabbit to approve the latest commit labels Sep 6, 2026
@github-actions

github-actions Bot commented Sep 6, 2026

Copy link
Copy Markdown

Review status

Thanks for contributing. This comment tracks the review sequence and the next action.

Current step: Required CI passed. Waiting for automated review of the latest commit.

If automated review does not start, a maintainer must restart it.

Review-state labels are managed by this workflow; do not edit them manually.

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

Labels

awaiting-coderabbit Waiting for CodeRabbit to approve the latest commit coderabbit-review-active Required CI passed; CodeRabbit review is active

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants