Skip to content

Restore a deleted worktree, or start a new chat in main - #647

Merged
sambitcreate merged 17 commits into
mainfrom
claude/project-thread-euhzg4-worktrees
Nov 1, 2026
Merged

sambitcreate merged 17 commits into
mainfrom
claude/project-thread-euhzg4-worktrees

Conversation

@sambitcreate

@sambitcreate sambitcreate commented Oct 29, 2026 •

Copy link
Copy Markdown
Owner

Requested by sbt · project thread

Stacked on #643 (deleted workspace folder notice). Item 5, part a (Mac), of the upstream-changes plan. The phone part (New worktree on the new-chat screen) comes in a separate PR.

What changes

When a chat's managed worktree folder is deleted outside Aiden, the chat used to fail every send with "The managed worktree is no longer available to Aiden." Now it is checked like any other workspace folder: the send is refused before it is added (your text stays), and the notice above the composer offers what the owner chose:

  • Restore worktree: checks the same branch out again at the same managed path. Offered only while the branch still exists, no other worktree has it checked out, no Aiden removal of it is pending, and the folder it lived in is still there. Commits survive; uncommitted changes went with the folder.
  • New chat in main checkout: opens a draft in the repository's main workspace in checkout mode with the unsent message. The old chat stays as it is.
  • Check again stays: putting a folder back from the Trash is the only way to keep uncommitted work, and the notice says so.

Phones and paired Macs get a path-free workspace_unavailable refusal: "This chat's worktree folder was deleted on your Mac. Restore it from the chat on your Mac, then send again." No protocol revision (the code and the client handling already exist since #643).

A chat with No workspace (from #667) is left out of the folder check, as on main: its hidden folder is made again when the chat next runs.

How Restore stays safe

restoreDeletedManagedWorktreeCheckout (main/services/git.ts) runs inside the repository's mutation queue and:

  1. verifies the target is inside the managed root and absent;
  2. refuses while a removal journal for this worktree is pending (its files may be in quarantine);
  3. verifies the old ownership token in Git's admin dir (a foreign token refuses);
  4. refuses a moved registration, a branch checked out elsewhere, or a branch that is gone;
  5. clears only Git's stale record, never with git worktree remove: a locked record is refused, otherwise the record's admin directory is moved out of .git/worktrees/ and put back if the new checkout fails or a folder reappears, then deleted once the new checkout exists;
  6. runs worktree add with hooks disabled, verifies it, writes a new ownership token, and saves the workspace record through a callback while the lock is held. If any step after worktree add fails, the save included, the new checkout is taken back out through the same quarantine-and-recheck removal Aiden uses for managed worktrees, so Restore can be retried. If anything was written into it meanwhile, or the removal can't finish, the folder is kept (or put back into its own place) and the error says so.

It never creates, moves or deletes a branch. The application service takes the workspace mutation gate before any await, refuses No Access workspaces, then re-provisions .worktreeinclude files (errors only logged).

Tests

  • managed-worktree-lifecycle.test.ts: restore keeps commits, gets a new identity and leaves no prunable record; a failed save rolls the checkout back with the branch kept, then a retry succeeds; refusals for a present folder, a deleted branch, a branch taken by another worktree, and a foreign token; a failed restore never deletes a file written while it was undoing itself, puts the folder back when a late write stops its removal, and keeps its removal record when something else took the folder's place.
  • workspace-folder-presence.test.ts: managed worktrees checked at the checkout root (no path in the message), the remote refusal, No workspace chats left out and their folder made again, missingWorktreeOptions (restorable, pending removal, missing parent, No Access, no token, main workspace pick including through a symlink, Git error).
  • aiden-remote-chats.test.ts: refusal message passes through.
  • e2e tests/e2e/worktree-folder-deleted.spec.ts: create a New worktree chat, delete its folder, the notice appears with Check again; New chat in main checkout carries the text in checkout mode; Restore brings the folder back on its branch and the send goes through.

Locally: type-check and eslint clean; the suites above pass. Eight managed-worktree tests fail in the cloud container on the base branch too (container-specific, unchanged by this PR).

Flake notes (hosted CI):

Known limits

  • A crash in the few milliseconds between worktree add and the record save still leaves a checkout whose identity Aiden doesn't recognize (rollback covers thrown errors, not a killed process).
  • New chat in main checkout carries the message text, not attachments.

Docs

README workspaces line, docs/plans/managed-worktree-lifecycle-plan.md (new section), docs/plans/README.md row, docs/aiden-on-the-go-remote-access.md troubleshooting, .memory/workspace-folder-presence.md.

https://claude.ai/code/session_018VA6RFZmgu9xAiKJ1wo2w2


Generated by Claude Code

When a chat's managed worktree folder is deleted outside Aiden, the chat
now checks the checkout root like any other workspace folder, refuses a
send before it is added, and offers two actions above the composer:

- Restore worktree checks the same branch out again at the same managed
  path (ownership token verified, stale registration cleared, hooks off,
  .worktreeinclude re-provisioned, new token). The branch is never
  created or deleted, so commits survive.
- New chat in main checkout opens a draft in the repository's main
  workspace in checkout mode with the unsent message.

Phones get a path-free workspace_unavailable refusal that says to
restore it from the chat on the Mac.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018VA6RFZmgu9xAiKJ1wo2w2
@sambitcreate sambitcreate self-assigned this Oct 29, 2026
@very-hermes-bot

very-hermes-bot commented Oct 29, 2026 •

Copy link
Copy Markdown
Collaborator

Hermes Review Bot

Confidence: 4

Engine: opencode/opencode-go/deepseek-v4.1-flash
Review mode: full
Head: c403264963b03fbdb6272d6539445d00f99238dd
Generated: 2026-11-01T13:40:58+00:00
Reviews: 1

Summary

This PR closes the gap where a chat whose Aiden-managed worktree folder was deleted outside Aiden failed every send with the generic managed-worktree admission error. It brings managed worktrees into the existing workspace-folder presence check (checkedWorkspaceFolder points the stat at the checkout root, workspaceFolderCheckApplies no longer excludes them), and extends the missing-folder notice with two actions: Restore worktree (a new workspaces:restoreDeletedWorktree → application service → restoreDeletedManagedWorktreeCheckout path that clears only Git's stale record, re-adds the branch with hooks disabled, verifies and re-tokens the new registration, and rolls the checkout back through the existing quarantine-and-remove machinery on any failure) and New chat in main checkout (a draft in the realpath-matched main workspace, in checkout mode, with the unsent text). Paired devices get a path-free workspace_unavailable refusal via a now message-returning option, so no protocol revision is needed and the existing code-based 409 settlement on iOS/Android still applies.

The restore path is the part to double-check on review: it deliberately never runs git worktree remove, re-checks for a folder put back from the Trash at three separate points, holds a placeholder over the old administrative name so Git picks a fresh one (I verified locally that git worktree add does pick fix1 and that git worktree list tolerates the leftover empty dir), and only deletes the set-aside record after the new checkout exists. The two documented residuals are real: a killed process between worktree add and the record save, and a "kept folder" whose saved identity (worktreeDevice/worktreeInode) no longer matches the workspace record — the latter is a deliberate, message-explained dead end that resolves once the folder is deleted and Restore is run again.

Confidence Score: 4/5

Traced the renderer refusal → IPC → application service → GitService mutation end-to-end, verified every call site of the renamed workspaceFolderMissing option and of the widened workspaceFolderCheckApplies, checked the iOS/Android 409 handling is code-based, and confirmed the Git name-collision mechanism with a local probe; the two suites and the e2e could not be run here, so their green status is unverified.

📁 Important Files Changed
  • main/services/git.ts — the core of the change: restoreDeletedManagedWorktreeCheckout plus helpers (setAsideWorktreeRecord, returnSetAsideRestore, settleKeptRestoreRecord, moveKeptRecordToRecordedName). Deserves the closest read; it is the only place that mutates Git state.
  • main/services/workspace-folder-presence.ts — checkedWorkspaceFolder, worktree-aware workspaceFolderMissingText/workspaceFolderRemoteRefusal, and missingWorktreeOptions (the Restore/main-checkout eligibility the notice renders).
  • renderer/shared/workspace-folder-presence.ts — shared messages plus workspaceFolderCheckApplies no longer excluding managed worktrees; this is the one behavioral change with blast radius into main's generation, scheduled-task and terminal paths.
  • main/services/workspace-worktree-application-service.ts — restoreDeleted: mutation gate, permission refusal, .worktreeinclude re-provisioning after the same capacity check creation uses, and the in-lock workspace save.
  • main/handlers/workspaces.ts — folderPresence now computes worktree options; new workspaces:restoreDeletedWorktree handler mirroring the sibling snapshot-restore handler.
  • renderer/main/chat-pane.tsx, renderer/components/workspace-folder-missing-notice.tsx, renderer/lib/new-chat-actions.tsx, renderer/main/root-view.tsx — the two notice actions, the worktree-specific send refusal, and openNewChatIn's new initialText/gitMode options.
  • main/services/aiden-remote-chats.ts, aiden-remote-service-main.ts — option renamed from a boolean to a message-returning refusal; no protocol change.
  • Tests/docs — managed-worktree-lifecycle.test.ts (11 new restore scenarios), workspace-folder-presence.test.ts, workspace-worktree-application-service.test.ts, tests/e2e/worktree-folder-deleted.spec.ts, plus README/plan/remote-access/project-memory updates that match the implementation.

Findings

No findings.

📊 Sequence Diagram
sequenceDiagram
  participant R as ChatPane (renderer)
  participant H as workspaces handler
  participant A as WorktreeApplicationService
  participant G as GitService
  participant C as configStore

  R->>H: workspaces:folderPresence(workspaceId)
  H->>H: workspaceFolderPresence(checkout root)
  H->>H: missingWorktreeOptions(branch head, worktrees, deletion journal, parent)
  H-->>R: { presence: "missing", worktree: { restorable, mainWorkspaceId } }
  R->>H: workspaces:restoreDeletedWorktree(workspaceId)
  H->>A: restoreDeleted(owner, id)
  A->>A: beginWorkspaceMutation(id) (before any await)
  A->>G: restoreDeletedManagedWorktreeCheckout(...)
  G->>G: enqueueMutation → verify target, token, branch, room
  G->>G: move stale record aside, hold placeholder, git worktree add (hooks off)
  G->>G: verify registration, write new token
  G->>C: commit(restored) — save workspace inside the lock
  G-->>A: restored checkout
  A->>A: checkCreateCapacity, re-provision .worktreeinclude (errors logged)
  A-->>R: saved workspace → invalidate workspaces + presence, toast
Loading

Machine-Readable Findings

[]

Last reviewed commit: c403264963b0
Reviews (1) · Comment /hermes review to trigger a new review · /hermes review full for full re-review

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Important

Two restore-path issues need attention before merging: interrupted identity persistence can strand the chat, and checkout admission is bypassed.

Reviewed changes — Reviewed all 22 changed files in the initial commit, including Git recovery, workspace persistence, desktop draft navigation, and remote refusals.

  • Deleted worktree recovery: Recreates the recorded checkout on its surviving branch, refreshes ownership identity, and provisions included files.
  • Missing-folder handling: Includes managed checkout roots in send checks and returns a path-free refusal to paired clients.
  • Composer actions: Offers Restore or a new chat in the main checkout with the unsent text and explicit checkout mode.
  • Coverage and documentation: Adds lifecycle, presence, and Electron coverage and updates workspace recovery guidance.

Validation: desktop and E2E type checks passed; the new Electron test collects; all 82 remote-chat tests passed. The lifecycle/presence run passed 36 tests, including the new restore cases; five lifecycle tests and three application-service tests failed because build/native/aiden-worktree-file-io is unavailable on Linux. Electron execution requires macOS. Both findings were reproduced with temporary probes using the real Git service.

Pullfrog  | Fix all ➔ | Fix 👍s ➔ | View workflow run | Using gpt-6.1-sol | 𝕏

Comment thread main/services/git.ts Resolved
…n work

Review follow-ups:
- Refuse Restore while an Aiden removal of the worktree is pending, so
  quarantined files are never stranded behind a new checkout.
- Save the workspace record inside Git's lock; if anything after
  `worktree add` fails, remove the new checkout again (the branch stays),
  so a failed Restore can simply be retried.
- Clear the stale registration without --force (falling back only on Git
  versions that need it, and only while the folder is still missing).
- Keep Check again and tell the person to put a trashed folder back to
  keep uncommitted changes.
- Offer Restore only with an ownership marker, folder access, the parent
  folder present and no pending removal; match the main checkout by real
  path; take the workspace gate before any await; leave the worktree's
  path out of the error text.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018VA6RFZmgu9xAiKJ1wo2w2

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

The new rollback can permanently delete externally written edits when workspace persistence fails.

Reviewed changes since the prior review at 807afac09, focusing on the recovery and eligibility changes in f8302cdaf.

  • Moved identity persistence: Saved the restored workspace through a callback inside the Git mutation lock and added rollback for failures after checkout creation.
  • Tightened restore eligibility: Checked pending removal journals, parent-folder availability, ownership fields, and workspace permissions, and acquired the workspace mutation gate before asynchronous work.
  • Changed stale-registration cleanup: Tried plain worktree remove before an absence-checked forced fallback.
  • Improved recovery navigation: Matched main-checkout workspaces through symlinks, retained Check again, and explained Trash recovery for uncommitted changes.
  • Extended tests and guidance: Covered failed-save rollback/retry and the additional eligibility cases, and updated recovery documentation.

Validation passed: desktop and E2E type checks, nine folder-presence tests, two focused real-Git lifecycle tests, and seven workspace environment/mutation tests. Playwright collected the recovery scenario; Electron execution requires macOS and was not run on this Linux runner. A separate real-Git probe reproduced the data loss described inline.

Pullfrog  | Fix all ➔ | Fix 👍s ➔ | View workflow run | Using gpt-6.1-sol | 𝕏

Comment thread main/services/git.ts Resolved
…to claude/project-thread-euhzg4-worktrees

# Conflicts:
#	.memory/workspace-folder-presence.md
#	docs/aiden-on-the-go-remote-access.md
…d folder something wrote into

- Restore checks the branch's current head the way creation does (no
  checkout filters, room on both volumes) before Git's record or any file
  is touched.
- A failed save removes the new checkout only while it is the same folder
  and still clean (no --force); otherwise the folder and what was written
  into it stay, and the branch is never touched.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018VA6RFZmgu9xAiKJ1wo2w2

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

The revised rollback can still delete an ignored file written after its status check. The checkout-admission fix passes its focused test.

Reviewed changes since the prior review at f8302cdaf, covering the new restore safeguards and their integration after the base-branch merge.

  • Added checkout admission: Validated the current branch's checkout transformations and disk capacity before clearing the stale registration.
  • Revised failed-restore cleanup: Checked directory identity and uncommitted, untracked, and ignored content, then used nonforced removal for a clean checkout.
  • Extended lifecycle coverage: Tested preservation of an external write during the save callback and refusal of a branch that acquired checkout filters.
  • Integrated base changes: Retained the chat-visit send guard and updated missing-folder/refusal documentation.

Validation: desktop TypeScript, all four focused deleted-worktree lifecycle tests, and all nine folder-presence tests passed. A separate real-Git probe reproduced the ignored-file loss described inline. Electron execution was not run on Linux.

Pullfrog  | Fix all ➔ | Fix 👍s ➔ | View workflow run | Using gpt-6.1-sol | 𝕏

Comment thread main/services/git.ts Resolved
The rollback of a failed Restore now goes through the same quarantine
removal as managed worktree deletion: the checkout is renamed away first
and checked afterwards, so an ignored file written after the check can no
longer be deleted with it. Anything changed, new or ignored puts the
folder back and keeps it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018VA6RFZmgu9xAiKJ1wo2w2

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Important

The new cleanup preserves late-written content, but can leave it in hidden quarantine with no working Restore/recovery path.

Reviewed changes since the prior review at 11db1df, focusing on df28162.

  • Replaced rollback removal: Routed failed-restore cleanup through the identity-bound quarantine helper with the strict safe deletion policy, preserving the existing branch.
  • Retained unverified checkouts: Kept the folder when its identity changed or the replacement ownership token was not successfully saved.
  • Extended coverage and memory: Added an ignored-file timing test and documented the revised rollback behavior.

Validation: desktop TypeScript, all five focused lifecycle tests, and all nine folder-presence tests passed after building the native remover. A separate real-Git/native-helper probe reproduced the recovery issue inline. Electron execution was not run on Linux.

Pullfrog  | Fix all ➔ | Fix 👍s ➔ | View workflow run | Using gpt-6.1-sol | 𝕏

Comment thread main/services/git.ts Resolved
…ps late

The quarantine removal can refuse after the checkout and its Git record
were already set aside (a write landed through an open handle). The
rollback now moves both back to their places and drops that removal's
journal before saying the folder was kept, so the folder is really
where it was.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018VA6RFZmgu9xAiKJ1wo2w2

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Important

The new put-back helper can discard the recovery journal while the actual checkout remains hidden in quarantine if another process recreates its original pathname.

Reviewed changes since the prior review at df28162, focusing on the recovery changes in 75fdd7e.

  • Added quarantine return: Returned the checkout and Git administrative directory after failed rollback removal, then removed the journal when both were considered restored.
  • Extended lifecycle coverage: Added a successful late-write rejection scenario and documented the put-back behavior.

Validation: desktop TypeScript, all six focused deleted-worktree lifecycle tests, and all nine folder-presence tests passed. A separate real-Git/native-helper probe confirmed that the previously reported uncontended late-write case is fixed and reproduced the pathname-collision issue inline. Electron execution was not run on Linux.

Pullfrog  | Fix all ➔ | Fix 👍s ➔ | View workflow run | Using gpt-6.1-sol | 𝕏

Comment thread main/services/git.ts Resolved
An occupied path no longer counts as the folder being back. Something set
aside returns only to a free path, and with nothing set aside the
checkout path must be the very directory this restore made. Otherwise
the Git record stays set aside with the checkout and the removal journal
is kept, so recovery still knows where they are.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018VA6RFZmgu9xAiKJ1wo2w2

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ No new issues found.

Reviewed changes since the prior review at 75fdd7e, focusing on the recovery safeguards in 6b917d0.

  • Tightened put-back checks: Rejected occupied destinations and ambiguous set-aside paths, and verified checkout identity when nothing remains set aside.
  • Preserved collision recovery state: Left the Git record quarantined and retained the journal when the checkout could not return safely.
  • Extended behavioral coverage: Added a pathname-collision test that verifies preservation of the new occupant, quarantined work, and removal record.

Validation passed: desktop TypeScript, seven focused deleted-worktree lifecycle tests, and nine folder-presence tests. A separate real-Git/native-helper probe confirmed both ordinary late-write recovery and collision preservation, including the quarantined Git record and pending journal. Electron execution was not run on Linux.

Pullfrog  | View workflow run | Using gpt-6.1-sol | 𝕏

Copy link
Copy Markdown
Owner Author

"iOS build and simulator tests" failed on 6b917d0 in one test: AidenMessageVisualSnapshotLayoutTests.testVisualSnapshotKeepsItsHeightAlongsideAnImageDeck ("the snapshot was squeezed", 0 vs 269). In the same run the simulator also failed to launch the app. This is a known flaky test (it hit #636 the same way), and this PR adds no iOS code beyond its base #643, which passed. I'll re-run the failed job once when the rest of the run finishes, and the flake is recorded in the PR description.


Generated by Claude Code

Base automatically changed from claude/project-thread-euhzg4 to main October 30, 2026 14:22
Keeps checking a managed worktree at its checkout root (Restore) and
leaves a No workspace chat's hidden folder out of the check, as main does.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018VA6RFZmgu9xAiKJ1wo2w2

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ No new issues found.

Reviewed changes since the prior review at 6b917d0, focusing on the folder-presence integration in merge commit 537d201.

  • Preserved managed-worktree checks: Kept missing-checkout detection at the checkout root and retained the worktree-specific recovery notice and remote refusal.
  • Integrated No workspace handling: Exempted hidden No workspace folders from missing-folder checks while retaining their recreation before generation; ordinary project folders remain protected from automatic recreation.
  • Reconciled behavioral coverage: Retained tests for both managed-worktree recovery eligibility and No workspace folder exemption/recreation.

Validation passed: desktop TypeScript and all 92 folder-presence/remote-chat tests. All prior Pullfrog threads are already resolved. Electron execution was not run on Linux; hosted CI for this head is still pending.

Pullfrog  | View workflow run | Using gpt-6.1-sol | 𝕏

Copy link
Copy Markdown
Owner Author

Flake in Desktop tests (runtime-subagents) on 537d201: main/services/mcp-failure-diagnostics.test.ts "recorded events never contain URLs, paths, tokens, client secrets or stdio arguments" failed with 8443 leaked. Nothing leaked. The event's serverRef is a hash salted per run, and this time it was c76b4b6844349fbe, which happens to contain the test's port 8443. That's a test bug on main: it substring-checks the port digits against random hex. This PR doesn't touch MCP diagnostics. Run: https://github.com/sambitcreate/aiden-agent/actions/runs/41176004526/job/124463642431. I'll re-run the failed job once when the run finishes. Fixing the oracle (for example, leaving the hash fields out of the check) is a small follow-up outside this PR.


Generated by Claude Code

Keeps main's Headless server README line alongside this branch's
workspaces line.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018VA6RFZmgu9xAiKJ1wo2w2

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ No new issues found.

Reviewed changes since the prior review at 537d201, focusing on the integration with main in merge commit 2adbc33.

  • Preserved refusal ordering: Kept the worktree-specific missing-folder refusal before attachment reservation and message append in the updated remote-turn path.
  • Integrated workspace watching: Retained main's shared Git watcher so workspace handlers and removal services use the same instance.
  • Reconciled composer and documentation changes: Preserved draft-text recovery imports and the worktree recovery guidance alongside main's updated server documentation.

Validation passed: npm run type-check and all 98 remote-chat, folder-presence, and Git watcher tests. All prior Pullfrog threads remain resolved. Electron and native mobile suites were not run on Linux; hosted CI for this exact head is still pending.

Pullfrog  | View workflow run | Using gpt-6.1-sol | 𝕏

@very-hermes-bot very-hermes-bot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Inline review — 2 finding(s) anchored to the diff. See the pinned summary comment for the overview.

Comment thread main/services/git.ts Resolved
…ecord

Restore checked that the folder was gone, then measured the checkout and
the free space, which can take seconds. A folder put back from the Trash
in that window was then deleted by `git worktree remove`, ignored files
included. Restore now looks again right before it touches Git's record
and refuses if the folder is back.

The rollback test for an ignored file written while undoing now writes
into the work tree the status check looked at (the set-aside checkout),
and asserts the file survives instead of skipping the check.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018VA6RFZmgu9xAiKJ1wo2w2

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ No new issues found.

Reviewed changes since the prior Pullfrog review at 2adbc33, focusing on the restore safeguards and behavioral coverage in 6041786.

  • Added a pre-removal folder check: Rechecked the registered and canonical checkout paths after size and capacity admission, refusing to remove a folder returned from the Trash during those checks.
  • Strengthened ignored-file coverage: Wrote the late backup into the actual quarantined checkout and unconditionally verified that its contents survived at the original worktree path.
  • Added Trash-return coverage: Exercised a folder returned during checkout measurement and verified that Restore refused while preserving its ignored .env file.

Validation passed: desktop TypeScript, ESLint on both changed files, all eight focused deleted-worktree lifecycle tests using the compiled native remover, and all ten folder-presence tests. All prior Pullfrog threads are already resolved. Electron execution was not run on Linux; hosted CI for this exact head is still pending.

Pullfrog  | View workflow run | Using gpt-6.1-sol | 𝕏

@very-hermes-bot very-hermes-bot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Inline review — 3 finding(s) anchored to the diff. See the pinned summary comment for the overview.

Comment thread main/services/git.ts Resolved
Comment thread main/services/git.ts Resolved
Comment thread main/services/git.ts Resolved
- Restore clears the stale Git record by moving its admin directory out of
  worktrees/ in one rename, looks for the folder once more and puts the
  record back if it came back, instead of git worktree remove, which deletes
  a clean folder put back from the Trash in that window.
- A failed restore that keeps its folder gives the new record the
  workspace's recorded ownership (or drops it under another name), so
  deleting the folder and choosing Restore again works.
- The .worktreeinclude copies after a restore get the same room check
  creation makes; without room the checkout still comes back.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018VA6RFZmgu9xAiKJ1wo2w2

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ No new issues found.

Reviewed changes since the prior Pullfrog review at 6041786, covering the recovery and provisioning changes in 21a4236.

  • Replaced stale-registration removal: Renamed Git metadata aside without touching the checkout folder, refused locked records, and returned the registration when a folder reappeared from the Trash.
  • Reconciled retained-checkout ownership: Restored the recorded ownership identity after failed recovery so deleting the retained folder and choosing Restore again works.
  • Added provisioning admission and coverage: Checked capacity before optional .worktreeinclude copies, retained successful checkout recovery when copies were skipped, and extended lifecycle tests and recovery documentation.

Validation: desktop TypeScript, ESLint, all nine focused deleted-worktree lifecycle tests, all ten folder-presence tests, and the new capacity-refusal test passed. The full application-service suite passed two tests and hit three existing Linux failures: one macOS-specific capacity expectation and two missing aiden-worktree-file-io helper failures (ENOENT). Electron execution was not run on Linux; hosted CI for this head is still pending.

Pullfrog  | View workflow run | Using gpt-6.1-sol | 𝕏

@very-hermes-bot very-hermes-bot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Inline review — 2 finding(s) anchored to the diff. See the pinned summary comment for the overview.

Comment thread main/services/git.ts Resolved
Comment thread main/services/git.ts Resolved
- The stale record set aside by Restore is deleted only after worktree add
  succeeds, and goes back if add fails, so a folder put back from the Trash
  in that gap stays a checkout.
- Restore refuses a workspace subfolder the branch no longer has, instead
  of saving a record that points at a missing folder.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018VA6RFZmgu9xAiKJ1wo2w2

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Important

A failure deleting the old Git metadata can now strand the restored chat before its ownership is persisted.

Reviewed changes since the prior Pullfrog review at 21a4236, focusing on the recovery changes in 7d49465.

  • Retained the old Git record: Kept the set-aside registration until worktree add succeeds and returned it when checkout creation fails.
  • Rejected missing nested folders: Verified that a nested workspace folder exists before saving the restored workspace, rolling the checkout back when the branch no longer contains it.
  • Extended recovery coverage: Added behavioral tests for a Trash return immediately before checkout creation and a branch that dropped its workspace subfolder, and updated the lifecycle plan.

Validation passed: desktop TypeScript, ESLint on both changed TypeScript files, all 11 focused deleted-worktree lifecycle tests with the compiled native remover, and all ten folder-presence tests. A separate real-Git permission-failure probe reproduced the issue inline. All prior Pullfrog threads remain resolved. Electron execution was not run on Linux; hosted CI for this exact head is still pending.

Pullfrog  | Fix all ➔ | Fix 👍s ➔ | View workflow run | Using gpt-6.1-sol | 𝕏

Comment thread main/services/git.ts Resolved
The set-aside record is already out of Git's list, so failing to delete it
after worktree add only leaves a stray folder; it no longer strands a new
checkout before its ownership is recorded.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018VA6RFZmgu9xAiKJ1wo2w2

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ No new issues found.

Reviewed changes since the prior Pullfrog review at 7d49465, focusing on the cleanup-failure fix in 974fc4a.

  • Made old-record deletion best effort: Allowed restore verification and ownership persistence to continue when deleting the discarded Git metadata fails; that metadata is already outside Git's worktree list.
  • Added cleanup-failure coverage: Injected EACCES after checkout creation and verified that the new identity is recorded and the restored checkout passes managed-worktree admission.

Validation passed: desktop TypeScript, ESLint on both changed files, all 12 focused deleted-worktree lifecycle tests using the compiled native remover, and all ten folder-presence tests. The prior finding is addressed and its thread is already resolved. Electron execution was not run on Linux; hosted CI for this exact head is still pending.

Pullfrog  | View workflow run | Using gpt-6.1-sol | 𝕏

@very-hermes-bot very-hermes-bot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Inline review — 2 finding(s) anchored to the diff. See the pinned summary comment for the overview.

Comment thread renderer/main/chat-pane.tsx Resolved
… restore

A refused or rolled-back restore can leave a folder at the checkout
path, so the notice now re-checks it then instead of still offering
Restore. The can't-restore sentence no longer names a cause Aiden
never checked.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018VA6RFZmgu9xAiKJ1wo2w2

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ No new issues found.

Reviewed changes since the previously reviewed e2603d5 checkpoint, focusing on the failed-Restore notice fix in 8e11731.

  • Refreshed recovery state: Invalidated the affected workspace's folder-presence query after a failed Restore so the notice follows any folder returned or retained on disk.
  • Corrected refusal copy: Removed the unsupported claim that a non-restorable branch must be deleted or checked out elsewhere.
  • Extended recovery coverage: Added an E2E sequence that recreates the folder before Restore, checks that the refusal clears the notice, then deletes it again and completes recovery.

Validation passed: desktop and E2E TypeScript checks, ESLint on all three changed files, all ten folder-presence tests, and collection of the updated E2E scenario. Electron execution requires macOS and was not run on Linux. All prior Pullfrog threads remain resolved; hosted CI for this exact head was still pending when checked.

Pullfrog  | View workflow run | Using gpt-6.1-sol | 𝕏

@very-hermes-bot very-hermes-bot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Inline review — 2 finding(s) anchored to the diff. See the pinned summary comment for the overview.

Comment thread main/services/git.ts Resolved
Comment thread renderer/main/chat-pane.tsx Resolved
A folder moved to the Trash still points at the old Git record's name,
and Restore used to recreate that same name, so Git commands in the
moved copy changed the restored checkout. An empty placeholder now
holds the old name during worktree add, so Git picks a fresh one; a
kept folder's record goes back under its recorded name so Restore can
be retried. The notice, phone refusal and docs now cover a moved
folder, and New chat in main checkout also carries a message waiting
in the paused queue.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018VA6RFZmgu9xAiKJ1wo2w2
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018VA6RFZmgu9xAiKJ1wo2w2

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ No new issues found.

Reviewed changes since the prior Pullfrog review at 8e11731, covering the recovery changes in 897a593 and the memory update in c403264.

  • Reserved the old Git record name: Made successful Restore allocate fresh checkout metadata so an externally moved copy cannot share the replacement's index and HEAD.
  • Preserved retained-folder recovery: Reconciled the fresh administrative name after failed restoration so the existing delete-and-retry recovery path remains available.
  • Recovered queued message text: Used the first queued message when the composer draft is empty before opening a new chat in the main checkout.
  • Clarified moved-folder guidance: Updated desktop and remote copy, recovery documentation, and project memory to cover moved folders as well as deleted ones.

Validation passed: desktop TypeScript, ESLint on all five changed TypeScript files, 13 focused restore lifecycle tests with the compiled native remover, and all 125 folder-presence, remote-chat, and message-queue tests. The chat-transition file passed its 35 assertions but did not terminate within the deadline on its isolated retry, so that suite is not counted as passed. Electron and native mobile execution were not run on Linux; exact-head hosted CI is still pending.

Pullfrog  | View workflow run | Using gpt-6.1-sol | 𝕏

@sambitcreate
sambitcreate merged commit aa37c23 into main Nov 1, 2026
24 checks passed
@sambitcreate
sambitcreate deleted the claude/project-thread-euhzg4-worktrees branch November 1, 2026 21:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants