Problem
ai/daemons/bridge/daemon.mjs deliverDigest() resolves the target instance pid via getInstancePid / getDefaultInstancePid (which shell out to real ps). test/playwright/unit/ai/daemons/bridge/daemon.spec.mjs does not stub that resolver, so the osascript the daemon builds depends on the host machine's running processes:
- On CI (no
Claude.app running): getDefaultInstancePid({appName:'Claude'}) returns null → the daemon uses the tell application "Claude" to activate path → tests asserting the activate line pass.
- On an agent-harness machine (Claude Desktop running — i.e. every agent's machine, especially with the 2-instance bring-up):
getDefaultInstancePid resolves a real pid → the daemon takes the set frontmost of (first process whose unix id is <pid>) path → there is no activate token → tests like daemon.spec.mjs:704 ("Claude default focus seed …") fail at expect(activateIndex).toBeGreaterThan(-1) (activateIndex = -1).
So these unit tests pass on CI but fail locally on harness machines — a determinism / CI-vs-host-parity hazard (a unit test must not depend on the host's live process list).
Repro
Run with Claude Desktop running on the host:
npm run test-unit -- test/playwright/unit/ai/daemons/bridge/daemon.spec.mjs
→ the default-instance / activate-path tests fail (activateIndex === -1); the rest pass.
Fix
Stub the instance resolver in daemon.spec setup so resolution is deterministic regardless of host state:
- Default-instance / activate-path tests → stub
getDefaultInstancePid (and getInstancePid) to return null.
- Instance-addressed tests → stub to return a fixed pid.
Inject via the existing seam (instanceResolver.mjs exports getInstancePid/getDefaultInstancePid; or thread an injectable exec as the resolver functions already support for testing). Audit all deliverDigest-exercising tests for the same host dependency.
Origin / Scope
- Surfaced while reviewing PR #12424 (#10422 frontmost guard) on a harness machine with live Claude instances.
- The real-
ps dependency in deliverDigest was introduced by #12399 / #12407 (instance-addressable wake routing); the spec was not updated to stub it. Not a #12424 defect — #12424's new guard test merely inherits the same host dependency.
- Test-only change. No runtime behavior change.
Problem
ai/daemons/bridge/daemon.mjsdeliverDigest()resolves the target instance pid viagetInstancePid/getDefaultInstancePid(which shell out to realps).test/playwright/unit/ai/daemons/bridge/daemon.spec.mjsdoes not stub that resolver, so the osascript the daemon builds depends on the host machine's running processes:Claude.apprunning):getDefaultInstancePid({appName:'Claude'})returnsnull→ the daemon uses thetell application "Claude" to activatepath → tests asserting the activate line pass.getDefaultInstancePidresolves a real pid → the daemon takes theset frontmost of (first process whose unix id is <pid>)path → there is noactivatetoken → tests likedaemon.spec.mjs:704("Claude default focus seed …") fail atexpect(activateIndex).toBeGreaterThan(-1)(activateIndex = -1).So these unit tests pass on CI but fail locally on harness machines — a determinism / CI-vs-host-parity hazard (a unit test must not depend on the host's live process list).
Repro
Run with Claude Desktop running on the host:
→ the default-instance / activate-path tests fail (
activateIndex === -1); the rest pass.Fix
Stub the instance resolver in
daemon.specsetup so resolution is deterministic regardless of host state:getDefaultInstancePid(andgetInstancePid) to returnnull.Inject via the existing seam (
instanceResolver.mjsexportsgetInstancePid/getDefaultInstancePid; or thread an injectableexecas the resolver functions already support for testing). Audit alldeliverDigest-exercising tests for the same host dependency.Origin / Scope
psdependency indeliverDigestwas introduced by #12399 / #12407 (instance-addressable wake routing); the spec was not updated to stub it. Not a #12424 defect — #12424's new guard test merely inherits the same host dependency.