Skip to content

fix: CLI doctor reports engines bundled in an installed app (#209) - #217

Merged
drawmeanelephant merged 2 commits into
drawmeanelephant:mainfrom
BeauBoorman:fix/209-installed-app-engines
Aug 26, 2026
Merged

drawmeanelephant merged 2 commits into
drawmeanelephant:mainfrom
BeauBoorman:fix/209-installed-app-engines

Conversation

@BeauBoorman

Copy link
Copy Markdown
Collaborator

Follow-up to the bundled helpers (#209 / #211).

Problem

banal doctor on a consumer machine — no boris/oliver on PATH, none configured — warns not found — builtin HTML will be used even when an installed BANAL.app carries both engines in Contents/Helpers. The CLI is a bare executable: its Bundle.main has no Helpers, so the locator chain (configured → this-bundle → env → PATH → sibling checkout) comes up empty, and doctor under-reports what the machine can actually do.

Approach

One new tier, doctor-only, after the existing chain: BundledHelper.installedAppHelperURLs(named:) probes ~/Applications/BANAL.app/Contents/Helpers/<name> then /Applications/..., and doctor's engine checks consult it when the locator returns nil.

Two deliberate boundaries, both adversarially reviewed:

  • Probes stay outside executables(). They are machine-global (any installed app), so the locator's default-injection tests (testLocatorReturnsNilWhenIsolated & co.) must not see them. Verified: full suite green with a staged installed app present on the host, and green without one.
  • Publish keeps the plain chain. banal publish delegates engine choice to the publisher's own locators — a bare-CLI publish matches the app's engine rules rather than silently borrowing a GUI app's bundled copies. Doctor reports machine capability; publish does the app's work. (Same-machine divergence — doctor ok while publish says builtin — is the honest outcome of that split; noted in the CHANGELOG.)

Sibling-checkout precedence over the installed app is unchanged and verified live: a dev hacking on boris keeps winning.

Verification (DEVELOPER_DIR=Xcode-beta)

  • Full suite: five xctest bundles, all green — with and without a staged ~/Applications/BANAL.app (the isolation proof).
  • swift build -Xswiftc -warnings-as-errors — clean.
  • Consumer end-to-end, env -i PATH=/usr/bin:/bin, bare vault:
    • no app anywhere → boris/oliver warn, exit 64
    • staged app → boris/oliver ok with the Helpers paths, contract ok, exit 0; --json reports "ok": true
  • New test testInstalledAppHelperProbesAreMachineGlobalNotBundled pins the probe shape (two candidates, user-local first) and their absence from the bundle-local list.

Adversarial gate held the branch until its findings were folded: the first version's test was dead (file-scope, never discovered — now inside the class and strengthened), the doc comment promised a publish path that didn't exist (now doctor-only and true), and the commit subject now matches the house convention.

BeauBoorman and others added 2 commits August 26, 2026 13:08
…elephant#209)

A bare-machine CLI has no bundle of its own, so doctor warned 'not
found — builtin' even when an installed BANAL.app carried boris and
oliver in Contents/Helpers. The CLI speaks for the machine: after the
locator chain comes up empty, doctor consults ~/Applications/BANAL.app
then /Applications/BANAL.app.

The probes stay out of the locator's injectable auxiliary list — they
are machine-global, and default-injection tests must stay isolated from
whatever is installed on the host. Doctor-only by design: publish keeps
the plain locator chain, so a bare-CLI publish matches the app's own
engine choice rather than borrowing an installed app's bundle.
@drawmeanelephant
drawmeanelephant merged commit 6010e75 into drawmeanelephant:main Aug 26, 2026
3 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