Skip to content

chore(e2e): stop and reap leaked isolated Obsidian E2E instances#197

Merged
chhoumann merged 2 commits into
masterfrom
chhoumann/devx-e2e-vault-teardown
Jun 16, 2026
Merged

chore(e2e): stop and reap leaked isolated Obsidian E2E instances#197
chhoumann merged 2 commits into
masterfrom
chhoumann/devx-e2e-vault-teardown

Conversation

@chhoumann

Copy link
Copy Markdown
Owner

Summary

The per-worktree Obsidian E2E isolation wrapper (PR #188) starts a private-HOME Obsidian instance per worktree (profile dir under /private/tmp/podnotes-obsidian-e2e/<vault>-<hash>/) but nothing stopped it. When a worktree was removed on merge, every completed worker leaked an Obsidian process tree and a /private/tmp vault dir. This adds a reliable teardown.

This is DevX tooling only — no plugin runtime / user-facing behavior changes.

What's added

  • scripts/stop-obsidian-e2e-instance.mjs + npm run stop:e2e-obsidian — identifies this worktree's instance by its private --user-data-dir=<instance>/ token (handles the macOS /tmp/private/tmp firmlink so the whole Electron tree is matched), terminates that process tree (SIGTERM, then SIGKILL for stragglers), and removes its profile dir behind a safe-path + profile-root containment guard. Supports --dry-run, --json, --prune.
  • Orca archive hook (orca.yaml)scripts.archive runs the teardown on orca worktree rm --run-hooks (cwd = worktree, $ORCA_WORKTREE_PATH), guarded with command -v node. A failed hook is logged by Orca but never blocks removal.
  • Reap-on-start safety netstart:e2e-obsidian and obsidian:e2e reap orphaned instances (those whose worktree is gone, recorded via a new podnotes-e2e-instance.json marker) before launching, so leaks are cleaned even when a worktree is removed without --run-hooks. An idle instance for a worktree that still exists is left alone so concurrent workers reuse it.
  • Docs — AGENTS.md "Stopping an isolated instance" subsection.
  • Testsscripts/stop-obsidian-e2e-instance.test.ts (23 cases): process-tree matching across /tmp vs /private/tmp, flag-scoped seeding, descendant walk, SIGTERM→SIGKILL, safe-path/containment guards, marker-based orphan detection, and reap isolation.

Safety invariants (held)

The teardown only ever targets the current worktree's instance. The shared dev vault (real $HOME, no /tmp token), other worktrees (distinct per-worktree hash), and all quickadd instances (/tmp/quickadd-obsidian-e2e/...) are never touched.

Runtime verification (real Obsidian, this worktree)

  • Started an isolated instance → verifiedPodNotes: true; the marker recorded the worktree path.
  • stop --dry-run listed exactly the instance's 4 pids and removed nothing.
  • stop terminated exactly those pids and removed the profile dir, while a live sibling worktree instance, 3 quickadd instances, and the shared dev vault all stayed alive and the sibling's dir was intact.
  • Synthetic worktree-gone orphan → reaped; live sibling spared.

Review

Ran a 3-reviewer pass (1 comprehensive + 2 adversarial), each finding independently verified against the code: 13 raised, 10 confirmed, 0 must-fix. Addressed the high-value confirmed items in the second commit (flag-scoped matcher, worktree-marker orphan signal, EPERM tolerance, per-orphan isolation, containment guard, hook node guard).

Commands run (Node 22)

npm run lint · npm run format:check · npm run typecheck · npm run build · npm run test (453 passing). docs:build skipped (no docs/ changes; mkdocs not installed locally).

Release / migration impact

None. Tooling/scripts only; no plugin code, settings, storage, API, or URI behavior changes.

Note on hook activation

Orca reads orca.yaml from the registered repo root (/Users/christian/Developer/PodNotes), so the archive hook becomes active for future worktree removals once this merges to master. The stop:e2e-obsidian script and reap-on-start net work immediately regardless.

The per-worktree isolation wrapper starts a private-HOME Obsidian instance
per worktree but nothing stopped it, so a removed/merged worktree leaked an
Obsidian process tree and a /private/tmp/podnotes-obsidian-e2e/<vault> dir.

Add scripts/stop-obsidian-e2e-instance.mjs + a stop:e2e-obsidian npm script
that identify this worktree's instance by its private --user-data-dir token,
terminate that process tree (SIGTERM then SIGKILL), and remove its profile
dir. It never touches the shared dev vault, other worktrees, or quickadd
instances. Two layers prevent leaks:

- orca.yaml scripts.archive hook runs the teardown on
  `orca worktree rm --run-hooks`.
- start:e2e-obsidian and obsidian:e2e reap orphaned instances (backing vault
  gone) on next start, so leaks are cleaned even without the hook.

Document the workflow in AGENTS.md and cover the engine (process-tree
matching across /tmp vs /private/tmp, safe-path guard, orphan detection,
reaping) with unit tests.
Review-driven hardening of the E2E instance teardown:

- Seed the kill set only on the Obsidian `--user-data-dir=<instance>/` flag
  instead of a bare path substring, so an unrelated process that merely
  mentions the instance path (a log tail, an editor) is never reaped.
- Detect orphans by "the worktree is gone" via a per-instance marker
  (podnotes-e2e-instance.json) instead of "the vault leaf is missing", so a
  momentarily-unmounted vault no longer triggers a destructive reap; fall back
  to the vault-path check for pre-marker instances.
- Tolerate EPERM/ENOENT (not just ESRCH) when signalling, so a recycled
  foreign pid never aborts teardown before the profile dir is removed.
- Isolate each orphan teardown in reap so one failure does not abort the scan.
- Add a profile-root containment guard before removing a dir.
- Guard the orca archive hook with `command -v node` and document the custom
  --vault / --profile-root limitations.

Extends the unit tests to cover each case.
@cloudflare-workers-and-pages

Copy link
Copy Markdown

Deploying podnotes with  Cloudflare Pages  Cloudflare Pages

Latest commit: 62e8852
Status: ✅  Deploy successful!
Preview URL: https://12fee50f.podnotes.pages.dev
Branch Preview URL: https://chhoumann-devx-e2e-vault-tea.podnotes.pages.dev

View logs

@chhoumann chhoumann merged commit 13ab5eb into master Jun 16, 2026
2 checks passed
@chhoumann chhoumann deleted the chhoumann/devx-e2e-vault-teardown branch June 16, 2026 08:10
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.

1 participant