{"record":{"id":"584db90a459541f0","repo":"paperclipai/paperclip","slug":"paperclip-workspace-restore-preserved-local-work","errorCode":null,"errorMessage":"[paperclip] Workspace restore preserved local working tree changes after clean sandbox restore.","messagePattern":"\\[paperclip\\] Workspace restore preserved local working tree changes after clean sandbox restore\\.","errorType":"console","errorClass":null,"httpStatus":null,"severity":"info","filePath":"packages/adapter-utils/src/git-workspace-sync.ts","lineNumber":638,"sourceCode":"\n  const stagedDiff = await runLocalGit(input.localDir, [\"diff\", \"--cached\", \"--name-status\", \"HEAD\", \"--\"], {\n    timeout: 10_000,\n    maxBuffer: 1024 * 1024,\n  });\n  if (stagedDiff.stdout.trim().length > 0) {\n    throw new Error(\n      `Workspace restore left staged git index changes after reset:\\n${stagedDiff.stdout.trim()}`,\n    );\n  }\n\n  if (!input.checkWorkingTreeClean) return;\n\n  const workingTreeDiff = await runLocalGit(input.localDir, [\"diff\", \"--name-status\", \"HEAD\", \"--\"], {\n    timeout: 10_000,\n    maxBuffer: 1024 * 1024,\n  });\n  if (workingTreeDiff.stdout.trim().length > 0) {\n    console.warn(\n      \"[paperclip] Workspace restore preserved local working tree changes after clean sandbox restore.\",\n    );\n  }\n}\n","sourceCodeStart":620,"sourceCodeEnd":643,"githubUrl":"https://github.com/paperclipai/paperclip/blob/120ae5428fa29bee300bcf806491cd4d965fbb7c/packages/adapter-utils/src/git-workspace-sync.ts#L620-L643","documentation":"resetLocalGitIndexToHead runs `git reset --quiet HEAD -- .` to unstage everything after a sandbox restore, asserts no staged changes remain (throws if staged diff is non-empty), then — only when checkWorkingTreeClean is set — runs `git diff --name-status HEAD`. Non-empty output means the restore left unstaged working-tree modifications, which the helper intentionally does NOT discard; this console.warn says those local changes were preserved through the clean-restore flow.","triggerScenarios":"A workspace that had local uncommitted edits (hotfixes, generated files) goes through a clean sandbox restore; the index resets to HEAD but the modified files remain on disk, so `git diff HEAD` still reports them.","commonSituations":"Agent run restored from a sandbox while a developer had local edits in the same checkout; generated artifacts differing from HEAD; end-of-line or permission-only diffs.","solutions":["Inspect what survived: run `git status --porcelain` and `git diff` in the workspace directory.","If you need a pristine tree, commit or stash the local changes, or explicitly clean them (git checkout -- . / git clean).","Treat the message as expected behavior when local edits existed before the restore — data was deliberately preserved."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"import { execSync } from \"node:child_process\";\nconst dirty = execSync(\"git status --porcelain\", { cwd: workspaceDir, encoding: \"utf8\" });\nif (dirty.trim().length > 0) {\n  // decide before restore: commit, stash, or accept that restore preserves these edits\n}","typeGuard":"const isCleanStatus = (porcelain: string): boolean => porcelain.trim().length === 0;","tryCatchPattern":null,"preventionTips":["Commit or stash local edits before triggering a clean sandbox restore if you want determinism.","Read the warning as informational: restore preserves local work by design.","After restore, run `git status --porcelain` to enumerate exactly what was kept."],"tags":["git","workspace-sync","sandbox-restore","working-tree"],"backgroundTag":"uncommitted-working-tree-changes","analyzedSha":"120ae5428fa29bee300bcf806491cd4d965fbb7c","analyzedAt":"2026-08-18T22:49:45.177Z","contentChangedAt":"2026-08-18T22:49:45.177Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}