Skip to content

install-binary.sh: leave a different app named Plow Latch.app in place - #454

Merged
plonkus merged 4 commits into
mainfrom
keep-other-app
Nov 9, 2026
Merged

plonkus merged 4 commits into
mainfrom
keep-other-app

Conversation

@plonkus

@plonkus plonkus commented Nov 9, 2026 •

Copy link
Copy Markdown
Contributor

On macOS, install-binary.sh chose the app to replace by its path alone: whatever sat at /Applications/Plow Latch.app (or ~/Applications/Plow Latch.app) was quit, moved aside and deleted. An older, different app also named Plow Latch.app was therefore quit and deleted mid-install, cutting off whatever it was doing before the new latch was set up.

What changed

  • The installer reads the bundle id of an app already at either path (plutil -extract CFBundleIdentifier) and compares it with the app it is installing. An app with a different bundle id is never quit, moved or removed.
  • With a different app in /Applications, latch installs to ~/Applications and says:
    install-binary.sh: /Applications/Plow Latch.app is a different app; leaving it in place and installing to ~/Applications, for this user only
  • A different app in the folder the installer would otherwise clean up (this user's copy in the other folder) is left alone.
  • When the only folder latch can use holds a different app, the install stops before stopping a host or touching any app:
    install-binary.sh: ~/Applications/Plow Latch.app is a different app, so nothing was installed; move it out of ~/Applications, then install again
  • Once the user deletes the other app, the next update moves latch to /Applications (when this user can write there) and removes the ~/Applications copy, as it already does.
  • latch/MACOS.md describes this, including that two "Plow Latch" apps can show in Spotlight until the older one is deleted.

What it deliberately doesn't do

  • It doesn't remove, quit or migrate the other app, or read anything from it.
  • It doesn't rename latch's app or change its bundle id, so latch keeps its identity and Full Disk Access.
  • When plutil is missing or an app has no Info.plist, both ids read as empty and the app is treated as latch's, as before. Every supported macOS ships /usr/bin/plutil.

Tests

Two regression tests in scripts/test-install.py (MacAppFolder), with a fake different app (co.plow.domo-desktop) and a window running from it. Both fail on the code before this change (the window is quit and the app replaced) and pass now:

  • test_another_app_named_plow_latch_is_left_running_and_in_place: the other app in /Applications and in ~/Applications; its window keeps running, its files are untouched, latch is in the other folder.
  • test_another_app_in_the_only_folder_latch_can_use_stops_the_install: non-zero exit with the message above, window running, app untouched, no link made.

just test installer on macOS and just test --linux installer both pass. The tests supply a fake plutil, since Linux has none.

🤖 Generated with Claude Code

https://claude.ai/code/session_01RFixJSUTTb3WjpFumMdmNi

plonkus and others added 4 commits November 9, 2026 10:11
The installer picked the app to replace by its path alone, so an older
app also named Plow Latch.app, with another bundle id, was quit and
deleted mid-install. It now compares bundle ids: a different app is never
quit, moved or removed; latch goes in the other folder, and when the only
folder it can use holds one, the install stops before changing anything.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RFixJSUTTb3WjpFumMdmNi
… user can write there

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

srosro commented Nov 9, 2026

Copy link
Copy Markdown
Contributor

📋 First review of this PR — reviewed 25668a8. 🧪 Tests not run. 🔍 Prior-art (KID) unavailable — lookup failed (exit 1). 🔍 8 sibling repos not searched (8 allowlist; names withheld on a public repo). ⚡ Small-diff lane (113 lines): skipped consumers — screened by aggregator. 📐 Complexity budget unchecked — the PR body is missing Goal, Outside users today, Minimal solution for that user count, Complexity added, Size: Expected net LOC; fill in those PR-template fields so the next review can check the budget.

It appears @plonkus is working towards letting macOS users install latch without interrupting or deleting a different app also named “Plow Latch.app” by checking bundle identifiers in latch/install-binary.sh, choosing the other Applications folder when available, and stopping with an explanation when the destination is occupied by a different app — reviewing against that goal.

Overview — The installer distinguishes apps by bundle identifier before selecting a destination, replacing an installed copy, or cleaning up the other Applications folder. For this internal, pre-PMF tool with a handful of hosts, the change stays appropriately small and extends the existing installation path.

Strengths — Clearing other excludes an unrelated app from both window termination and recursive cleanup, reusing the existing downstream behavior. Comparing against the incoming bundle’s identifier handles different apps generally without hard-coding the older app’s identity. The regression cases extend the existing fixture and check observable preservation of files and a running window.

Probes

None.

Security — None.

Test coverage — The added regressions cover collisions in both Applications folders and refusal when the usable destination is occupied, checking that the unrelated app remains intact and running. Staged just test did not run because cargo-nextest is missing (exit 127), an environment prerequisite failure unrelated to this diff; no tests were independently executed during this read-only review.

For AI authors — (Codex, Claude Code, Cursor, etc. reading this PR): The Probes above are load-bearing. Treat each [open] probe as a hard requirement — answer it directly in your reply or revisit the structural decision. Do NOT silently absorb a probe by adding more code; that path inverts the cost stance the probe is encoding. This repo's operating point (see its REVIEW.md) prefers cutting LOC over adding it; an [open] [simplification] probe whose answer is "no, this complexity isn't needed" should land as a deletion in your next push, not a new defensive guard.


How to use: auto-reviews every new PR and re-reviews after a period of inactivity. Trigger an incremental re-review with /srosro-update-review, or a whole-PR re-review with /srosro-review.

For humans only: push-access collaborators can post:

  • /srosro-approve — APPROVE the PR.
  • /srosro-props [from: <specialist>] — give props to a specialist's contribution.
  • /srosro-critique [from: <specialist>] — flag a specialist's contribution as a misread.
  • /srosro-memorize <feedback> — teach a calibration lesson (learn-from-replies updates COMMENT_REVIEW_MISTAKES.md from your body, sentiment-aware via LLM).

Props: /srosro-props [from: shape] caught a real layering bug we'd have shipped.
Critique: /srosro-critique [from: architecture-refined] DRY suggestion misread distinct seams.
Calibration: /srosro-memorize the architecture-refined DRY finding was a misread; those helpers serve different contracts.

AI agents must not use /srosro-memorize, /srosro-props, or /srosro-critique — those signals tune shared global state.

Generated by sam's ai review bot.

@srosro srosro 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.

Approving per automated review above.

@plonkus
plonkus merged commit 383de0a into main Nov 9, 2026
38 of 39 checks passed
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.

2 participants