"Identity, not timestamps. The mtime would have looked newer on the wrong binary."
The Database Behind Every Launch
LaunchServices is the macOS database that answers questions like "which app is com.example.spark", "which app handles spark://" and "what opens a .md file". A double-click in Finder, open -a, open -b, a URL clicked in a browser and NSWorkspace.openApplication all go through it. That is why every family build script ends by registering the installed bundle with lsregister -f (the tool lives in LaunchServices.framework/Support, not on PATH), so the database sees the new build immediately, and why the previous track insisted on launching with open: an app started through LaunchServices is its own responsible process, receives its open events, and activates like an app, while the executable run straight from a shell is just a child of that shell.
Two open details bite once each. open --env sets environment variables only when it starts a process, so against an app that is already running it refuses with "already running and so the additional environment variables could not be set". Add -n for a new instance, or quit the old one first. And the process is named after CFBundleExecutable, not the bundle. A smoke script that ran pkill -x with the bundle name matched nothing, because the executable inside was called something else. Read the name from Info.plist.
/Applications Is One Global Slot
On a Mac with several checkouts of one repository and several sessions working in them, /Applications/Spark.app is a single slot that all of them write. An installed-app gate for a family client failed three times in a row against a binary that did not contain the code under test. Another session had run build and install from a different checkout in the middle of the run. Every existing guard passed: bundle identifier, product version, signature, designated requirement, even CFBundleVersion. All of those are true of any build of that app. A long detour through environment delivery and argument expansion ended with strings on the installed binary: the new marker string was simply not there.
The fix is to check identity where identity lives. When the checkout holds a build product, the installed executable's SHA-256 must equal it. The same check catches the ordinary version of the mistake, which is rebuilding and forgetting to install. Timestamps prove nothing here, because the wrong binary was the newer file.
A Diagnosis Order That Works
When an installed app behaves as if your edit is not there: first strings -a the installed binary for a literal you just added (an interpolated Swift string appears as its literal pieces, so search for a prefix). Then hash the installed executable against every build product on the machine to learn which tree it came from. Only then look at the environment the running process received, with ps eww on its pid.