Skip to content

fix(launchd): render every interpreter from the keg, and stop copying the hotlane daemon - #757

Merged
EtanHey merged 2 commits into
mainfrom
wt/hotlane-keg-pin
Sep 4, 2026
Merged

fix(launchd): render every interpreter from the keg, and stop copying the hotlane daemon#757
EtanHey merged 2 commits into
mainfrom
wt/hotlane-keg-pin

Conversation

@EtanHey

@EtanHey EtanHey commented Sep 4, 2026

Copy link
Copy Markdown
Owner

Size: S

What was wrong

Two shapes, one root cause: install.sh resolved what a plist EXECUTES from the authoring environment instead of from the keg.

Measured on the two Macs, via plistlib on ProgramArguments (not a grep, see Scope below):

M4 — 8 of 20 com.brainlayer.* jobs execute the source checkout or the framework Python:

plist executes rendered
decay, health-check, p0-counter, repair-fts ~/Gits/brainlayer/.venv/bin/brainlayer Jun 26 – Jul 1
maintenance-nightly, maintenance-weekly ~/Gits/brainlayer/.venv/bin/python Jun 26
throughput-watchdog /Library/Frameworks/Python.framework/.../python3 Sep 2
hotlane-brainbar framework python + ~/Gits/brainlayer/scripts/hotlane_brainbar_daemon.py Aug 19

No release can move any of those, and no __build_sha__ describes what they run.

M1 — clean on all eight, and stale in a different way. Its hotlane plist correctly names the keg's venv Python, but its script path is ~/.local/lib/brainlayer/hotlane_brainbar_daemon.py, dated Jul 24 and byte-different from the keg's 1.5.12 copy — proven with diff, not inferred. The plist on disk cannot reveal that.

The fix

Interpreters (all renderers). PYTHON_BIN defaulted to command -v python3, BRAINLAYER_BIN to which brainlayer — both answer with whatever the installing shell's PATH fronts. In a keg they now default to the keg's own interpreter, through the stable opt/ symlink. An explicit PYTHON_BIN / BRAINLAYER_BIN / BRAINLAYER_PYTHON still wins, so brainlayer setup and every existing test are unaffected.

Hotlane's script path. install_hotlane_brainbar_daemon() copied the daemon to ~/.local/lib/brainlayer/ and pointed the plist at the copy. brew install never runs that refresh — the copy IS the M1's staleness. The daemon already ships inside the keg (pyproject.toml:139 force-includes it into brainlayer/launchd/), so in a keg the plist now names the packaged file directly and brew upgrade moves it for free. No intermediate copy remains to outrun. Outside a keg the copy survives unchanged, because in a checkout the checkout is the truth.

opt/, never Cellar/<version>/: a versioned path pins a job to a keg the next upgrade deletes. This reuses the existing stable_brainlayer_path (#749) rather than inventing a second convention. The one place the raw versioned root is deliberately kept is the release-signature gate, which verifies the exact keg it was handed.

Scope — stated so it is not re-litigated

WorkingDirectory under a checkout is NOT fixed here, on purpose. It does not decide which code runs. A grep that counts both WorkingDirectory and ProgramArguments gives 12 dirty plists on the M4; the number that matters is 8.

Also not fixed here (named follow-up). Six other files are copied into ~/.local/lib/brainlayer/ and refreshed only by install.sh, never by brew upgrade — the same staleness class as the hotlane copy: brainlayer-env-run.sh (arg0 of nearly every plist), throughput-watchdog.py, tier0-watchdog.sh, fleet-watchdog.sh, and the two templated ones, backup-daily.sh and jsonl-backup.sh. The templated pair cannot be keg-pinned without a substitution redesign. Flagged for the lead to split with orc rather than sprawling this PR.

Tests

test_launchd_installer_renders_every_interpreter_from_the_keg_not_the_authoring_shell renders every service (install.sh all) inside a keg fixture whose PATH deliberately fronts checkout-.venv decoys, then asserts no ProgramArguments entry names the checkout, the framework Python, or a versioned Cellar path — plus a positive half, so it cannot pass by rendering nothing.

test_launchd_installer_pins_hotlane_to_the_keg_copy_with_no_intermediate_copy asserts the packaged daemon path and that ~/.local/lib/.../hotlane_brainbar_daemon.py is not written at all in a keg.

test_launchd_installer_still_copies_the_hotlane_daemon_outside_a_keg pins the dev path so keg-pinning does not take it away.

Both new keg tests fail on HEAD and pass here — verified by restoring git show HEAD:scripts/launchd/install.sh and re-running, not assumed. The third passes on both, as a regression guard should.

Why no existing keg test caught this: every one of them passes PYTHON_BIN/BRAINLAYER_BIN explicitly. The defect lives in what install.sh picks when they are unset — which is exactly how brew install runs it.

tests/test_installable_build.py 95 passed; test_launchd_hygiene, test_fleet_watchdog, test_cli_launchd_mode_a, test_backup_daily, test_enrichment_controller 213 passed. ruff check and ruff format --check clean. Full scoped pre-push gate passed on push.

Known limit — this fix alone does not clean the M4

brew upgrade does not re-render existing plists. The M4's eight stale jobs need one install.sh run from the keg (per-service, not allcom.brainlayer.watch stays => disabled and R3 owns it). After that they follow versions on their own, because the paths are opt/-stable. That deploy ships with 1.5.13 and is proved per-Mac by ps/lsof on the live pid, never by the plist on disk.

🤖 Generated with Claude Code


Note

Medium Risk
Changes which binaries launchd jobs execute on installed Macs; behavior is fail-closed and heavily tested, but mis-detection could block installs or leave stale plists until re-run.

Overview
Fixes launchd plists that were baked with whatever Python/brainlayer the installing shell’s PATH returned (checkout .venv, framework Python) instead of the Homebrew keg, so upgrades could not move those jobs.

install.sh now discovers the keg before defaulting PYTHON_BIN / BRAINLAYER_BIN, resolves them through the stable opt/brainlayer symlink when overrides are unset, and errors if a keg is detected but its interpreter/CLI is missing (no silent PATH fallback). For hotlane on a keg, the plist points at the packaged hotlane_brainbar_daemon.py in the wheel—no copy to ~/.local/lib—and remove only deletes that local copy, not Homebrew-owned files.

Tests add a keg fixture with checkout PATH decoys and assert all ProgramArguments use the keg, hotlane is keg-pinned, dev checkout still copies locally, and remove/reinstall stay safe.

Reviewed by Cursor Bugbot for commit 669fc5f. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Fix launchd installer to render interpreters from keg and stop copying hotlane daemon

  • install.sh now discovers the stable keg before path init and resolves the Python interpreter and brainlayer CLI from inside the keg, preferring them over PATH results. It exits with an error if a keg is present but either binary is missing, unless an explicit override is set.
  • The hotlane daemon destination now points at the packaged daemon inside the keg when present; non-keg installations still copy to the user-local library as before.
  • The remove action now only removes the user-local daemon copy and never unlinks a keg-owned packaged daemon.
  • Adds integration tests in test_installable_build.py covering keg interpreter/CLI rendering, hotlane keg-pinning, non-keg copy behavior, remove safety, and refusal when the keg lacks a usable interpreter.
  • Behavioral Change: keg installations no longer copy the hotlane daemon to the user-local library; launchd jobs reference the keg-packaged daemon directly. A keg missing the packaged daemon causes installation to fail rather than fall back to PATH or a source checkout.

Macroscope summarized 669fc5f.

Summary by CodeRabbit

  • Bug Fixes
    • Improved Homebrew installations to consistently use the packaged Brainlayer environment and command-line tools.
    • Ensured launchd jobs reference the stable Homebrew installation path instead of development or alternate Python environments.
    • Prevented unnecessary local daemon copies when the packaged Homebrew daemon is already available.
    • Preserved local daemon installation behavior for source-based installations.

… the hotlane daemon

The M4 runs eight launchd jobs out of `~/Gits/brainlayer/.venv` or the framework
Python; the M1 runs a hotlane daemon dated Jul 24 while its keg says 1.5.12. Same
root cause, two shapes: `install.sh` resolved what a plist EXECUTES from the
authoring environment instead of from the keg.

**Interpreters.** `PYTHON_BIN` defaulted to `command -v python3` and
`BRAINLAYER_BIN` to `which brainlayer`. Both answer with whatever the installing
shell's PATH happens to front -- on the M4 that is
`/Library/Frameworks/Python.framework/.../python3` and, when installing from the
checkout, `~/Gits/brainlayer/.venv/bin/brainlayer`. Neither is a path any release
can move, and no `__build_sha__` describes what they run. In a keg both now
default to the keg's own interpreter through the stable `opt/` symlink. An
explicit `PYTHON_BIN`/`BRAINLAYER_BIN`/`BRAINLAYER_PYTHON` still wins, so
`brainlayer setup` and every existing test are unaffected.

**Hotlane's script path.** `install_hotlane_brainbar_daemon()` copied the daemon
into `~/.local/lib/brainlayer/` and pointed the plist at the copy. `brew install`
never runs that refresh, so the copy is the thing that went stale on the M1. The
daemon already ships inside the keg (pyproject force-includes it into
`brainlayer/launchd/`), so in a keg the plist now names the packaged file
directly and `brew upgrade` moves it for free -- no intermediate copy to outrun.
Outside a keg the copy survives unchanged, because in a checkout the checkout is
the truth; `test_launchd_installer_still_copies_the_hotlane_daemon_outside_a_keg`
pins that.

`opt/`, never `Cellar/<version>/`: a versioned path pins a job to a keg the next
upgrade deletes. That is what `stable_brainlayer_path` already exists for, so
this reuses it rather than inventing a second convention (#749). The one place
the raw versioned root is kept is the release-signature gate, which verifies the
exact keg it was handed -- a one-shot check where naming the version is right.

Scope, so the next reader does not re-litigate it: `WorkingDirectory` under a
checkout is NOT fixed here. It does not decide which code runs.

Tests. `test_launchd_installer_renders_every_interpreter_from_the_keg_not_the_authoring_shell`
renders every service in a keg fixture whose PATH fronts checkout-`.venv` decoys,
and asserts no `ProgramArguments` entry names the checkout, the framework Python,
or a versioned Cellar path. It fails on HEAD and passes here; so does the hotlane
pin test. The reason no existing keg test caught this is that all of them pass
`PYTHON_BIN`/`BRAINLAYER_BIN` explicitly -- the defect lives in what `install.sh`
picks when they are UNSET, which is how `brew install` runs it.

Known limit, not fixed here: `brew upgrade` still does not RE-RENDER existing
plists, so the M4's eight stale jobs need one `install.sh` run from the keg. After
that they follow versions on their own, because the paths are `opt/`-stable.

Co-Authored-By: brainlayerClaude running claude-opus-5 <noreply@anthropic.com>
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, add credits to your account and enable them for code reviews in your settings.

@cursor

cursor Bot commented Sep 4, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_72162c75-9f2a-44d8-b819-ca2d0e81e9c3)

@github-actions

github-actions Bot commented Sep 4, 2026

Copy link
Copy Markdown

BrainLayer ratchet

Every Value below was measured by this run. A row this machine cannot measure says n/a — <reason> instead of a number; baselines in Notes name their own machine, method and date and were not measured here.

Row Status Value (measured by this run) Method Notes
provenance 🟢 GREEN stamped 2ad510833e60 == HEAD, tree clean wheel stamp · in-process · runner Sha half of #749 keg-mode provenance: a keg built from this wheel can answer __build_sha__. The helper-age and served-process predicates need a running BrainBar and are measured only by scripts/sprint_gate.py on an installed Mac.
mapped bytes ⚪ n/a n/a — no BrainBar daemon at /tmp/brainbar.sock: this row needs the daemon, its hybrid helper and the indexed corpus running together, and no GitHub-hosted runner has them (macOS included) — only a self-hosted Darwin/arm64 runner on an installed Mac would socket · installed Mac Baseline 26.2 GB — installed Mac, socket, 2026-09-03, after R2 drained 15,070 → 0. Up from 16.8 GB because the drain left more vectors mapped under the same cap: the change is the drain, not a leak. Not measured by this run.
search p50/p95 ⚪ n/a n/a — no BrainBar daemon at /tmp/brainbar.sock: this row needs the daemon, its hybrid helper and the indexed corpus running together, and no GitHub-hosted runner has them (macOS included) — only a self-hosted Darwin/arm64 runner on an installed Mac would socket · installed Mac Baseline p50 911.887 ms / p95 3167.985 ms, captured 2026-09-01T08:42:22Z on MacBook-Pro.local under active_sprint_load (tests/fixtures/sprint_gate/corpus.json). Not measured by this run.
idle CPU ⚪ n/a n/a — no BrainBar daemon at /tmp/brainbar.sock: this row needs the daemon, its hybrid helper and the indexed corpus running together, and no GitHub-hosted runner has them (macOS included) — only a self-hosted Darwin/arm64 runner on an installed Mac would ps sampling · installed Mac Budget: average CPU < 30% over a 60 s window (resource_budget in scripts/sprint_gate.py). Needs the BrainBar daemon, helper and watcher actually running. Not measured by this run.
signature_valid ⚪ n/a n/a — the macOS signature-parity job is trigger-gated and did not run on this PR: it touches no release or signing path (pyproject.toml, scripts/release-*, scripts/brainlayer-version-check.sh, publish.yml, ratchet.yml) and carries no ratchet:signatures label — a GitHub macOS runner bills at ~10× Linux minutes and rebuilds the keg venv from source codesign · installed keg scripts/release-verify-signatures.sh <keg> codesign-verifies every *.so/*.dylib under libexec/venv. The macOS parity job installs the published tap formula (etanhey/layers/brainlayer), so this row measures the release path — formula, published sdist and Homebrew's relocation — and not this PR's tree. Release-time baseline for the same keg on a different machine: 442 valid / 0 invalid — installed Mac (M4 Max), brew --prefix brainlayer 1.5.11, 2026-09-03.

🟢 GREEN measured, within budget · 🔴 RED measured, out of budget — a finding to clear before merge · ⚪ n/a not measurable on this machine, never guessed.

No RED rows.

Measured on Linux/x86_64 · checked-out HEAD 2ad510833e60 · run · updated 2026-09-04 11:16:24 UTC

@deepsource-io

deepsource-io Bot commented Sep 4, 2026

Copy link
Copy Markdown

DeepSource Code Review

We reviewed changes in 5bd8d81...669fc5f on this pull request. Below is the summary for the review, and you can see the individual issues we found as inline review comments.

See full review on DeepSource ↗

PR Report Card

Overall Grade   Security  

Reliability  

Complexity  

Hygiene  

Code Review Summary

Analyzer Status Updated (UTC) Details
Python Sep 4, 2026 11:16a.m. Review ↗
Swift Sep 4, 2026 11:16a.m. Review ↗
JavaScript Sep 4, 2026 11:16a.m. Review ↗
Shell Sep 4, 2026 11:16a.m. Review ↗
Secrets Sep 4, 2026 11:16a.m. Review ↗

Important

AI Review is run only on demand for your team. We're only showing results of static analysis review right now. To trigger AI Review, comment @deepsourcebot review on this thread.

@coderabbitai

coderabbitai Bot commented Sep 4, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

Next included review available in 45 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available.

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Learn how review limits work.

Review configuration:

⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Team

Run ID: d2b81f00-0c2e-40f1-897d-3bd07a06453a

📥 Commits

Reviewing files that changed from the base of the PR and between 47d4e82 and 669fc5f.

📒 Files selected for processing (2)
  • scripts/launchd/install.sh
  • tests/test_installable_build.py

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Team

Run ID: 9d33c038-f962-4dfd-b01c-a757f53d3187

📥 Commits

Reviewing files that changed from the base of the PR and between 5bd8d81 and 47d4e82.

📒 Files selected for processing (2)
  • scripts/launchd/install.sh
  • tests/test_installable_build.py

Included review availability: Your plan provides up to 1 included review per hour; 0 remain after this review.

📜 Recent review details
⏰ Context from checks skipped due to timeout. (4)
  • GitHub Check: Macroscope - Correctness Check
  • GitHub Check: test (3.11)
  • GitHub Check: test (3.13)
  • GitHub Check: test (3.12)
🧰 Additional context used
🪛 ast-grep (0.45.2)
tests/test_installable_build.py

[error] 3341-3348: Command coming from incoming request
Context: subprocess.run(
[str(fixture["launchd_dir"] / "install.sh"), action],
env=env,
capture_output=True,
text=True,
timeout=120,
check=False,
)
Note: [CWE-78] Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection').

(subprocess-from-request)


[error] 3450-3470: Command coming from incoming request
Context: subprocess.run(
[str(launchd_dir / "install.sh"), "hotlane"],
env={
**os.environ,
"PATH": f"{fake_bin}:{os.environ['PATH']}",
"HOME": str(home),
"BRAINLAYER_BIN": sys.executable,
"PYTHON_BIN": sys.executable,
"BRAINLAYER_PYTHON": sys.executable,
"BRAINLAYER_ENV_FILE": str(env_file),
"BRAINLAYER_LAUNCHD_UNLOAD_ATTEMPTS": "1",
"BRAINLAYER_LAUNCHD_UNLOAD_INTERVAL": "0",
"BRAINLAYER_LAUNCHD_VERIFY_INTERVAL": "0",
"FAKE_LAUNCHCTL_LOG": str(tmp_path / "launchctl.log"),
"FAKE_PS_COMMAND": f"{sys.executable} {copied} --interval 1.0",
},
capture_output=True,
text=True,
timeout=60,
check=False,
)
Note: [CWE-78] Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection').

(subprocess-from-request)

🔇 Additional comments (2)
scripts/launchd/install.sh (1)

69-127: LGTM!

Also applies to: 138-149, 193-198, 488-498

tests/test_installable_build.py (1)

3240-3312: LGTM!

Also applies to: 3315-3349, 3352-3360, 3363-3399, 3402-3427, 3430-3476


📝 Walkthrough

Walkthrough

The launchd installer now detects Homebrew kegs, prefers keg-local Python and CLI paths, and pins the hotlane daemon to the packaged keg file. Tests cover keg installations with checkout decoys and preserve copying behavior for non-keg installations.

Changes

Homebrew keg-aware launchd installation

Layer / File(s) Summary
Keg interpreter resolution
scripts/launchd/install.sh
The installer detects the keg, resolves its Python and CLI, prefers them over PATH tools, and reuses the detected keg for signature verification.
Hotlane daemon pinning
scripts/launchd/install.sh
Keg installations reference the packaged hotlane daemon and skip the ~/.local/lib copy. Non-keg installations keep the existing copy path.
Keg and checkout validation
tests/test_installable_build.py
Tests create keg fixtures with checkout-venv decoys and validate interpreter selection, hotlane pinning, and non-keg copying.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Merge Risk: ⚪ Minimal · up to 47d4e

Launchd services installed from a Homebrew keg now use stable keg paths for executables and the hotlane daemon, while checkout installations retain their copy behavior. The covered installation paths are ready to merge.

Sequence Diagram(s)

sequenceDiagram
  participant Installer
  participant HomebrewKeg
  participant LaunchdPlist
  participant UserLibrary
  Installer->>HomebrewKeg: Detect keg and resolve Python and CLI
  HomebrewKeg-->>Installer: Return keg-local paths
  Installer->>LaunchdPlist: Render launchd jobs with keg paths
  Installer->>HomebrewKeg: Locate packaged hotlane daemon
  Installer->>LaunchdPlist: Reference packaged daemon
  Installer-->>UserLibrary: Skip copy for keg installation
Loading

Poem

A rabbit checks the keg at dawn,
Keg paths guide the plist on,
Hotlane stays where packages lie,
Decoy shells pass hopping by,
Tests guard each rendered job,
Stable links complete the hop.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 63.64% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 11 functions across 2 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main changes: resolving launchd interpreters from the Homebrew keg and stopping the copied hotlane daemon installation.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch wt/hotlane-keg-pin

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Comment thread scripts/launchd/install.sh Outdated
exit 1
fi
"$BRAINLAYER_RELEASE_VERIFY" "$BRAINLAYER_KEG"
"$BRAINLAYER_RELEASE_VERIFY" "$BRAINLAYER_KEG_RAW"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Medium launchd/install.sh:198

The release-signature tests at tests/test_release_verify_signatures.py:171 and :193 still assert the old "$BRAINLAYER_RELEASE_VERIFY" "$BRAINLAYER_KEG" invocation, so the test suite fails against this script. Update those guards to assert the new BRAINLAYER_KEG_RAW contract.

🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file @scripts/launchd/install.sh around line 198:

The release-signature tests at `tests/test_release_verify_signatures.py:171` and `:193` still assert the old `"$BRAINLAYER_RELEASE_VERIFY" "$BRAINLAYER_KEG"` invocation, so the test suite fails against this script. Update those guards to assert the new `BRAINLAYER_KEG_RAW` contract.

Comment thread scripts/launchd/install.sh
…losed on a keg with no interpreter

Round 2 on #757. Three findings from the Cursor pass, all three real; verified
each in the tree before acting.

**CRITICAL — `install.sh remove` unlinked a Homebrew-owned file.** Keg-pinning
changed what `HOTLANE_BRAINBAR_DST` MEANS -- from a copy this installer made into
`~/.local/lib` to the keg's own shipped file -- while the remove path still ran
`rm -f` on it. On a writable Homebrew prefix that deletes packaged content, and
the next keg-pinned install then fails closed on its own missing-daemon guard
until someone reinstalls the formula. `remove` now names the `~/.local/lib` copy
literally, so a future change to what that variable means cannot silently make
this destructive again. Every other `rm` in that block was already
`$BRAINLAYER_LIB_DIR`-rooted; mine was the only one that had become keg-rooted.

The lesson generalises and is worth writing down: **when you change what a path
MEANS, re-read every site that ACTS on it.** `HOTLANE_BRAINBAR_DST` has 8 hits;
I had checked the ones I edited, not the ones that merely used it.

**MEDIUM — a detected keg with a missing interpreter fell through to PATH.** That
is the same fail-open this whole change exists to close, reintroduced as a
fallback inside the fix for it: a keg is present, so PATH's answer (framework
python, a checkout `.venv`) is wrong by definition. With a keg detected and no
explicit override, a missing keg interpreter is now an error, not a fallback.
An explicit `PYTHON_BIN`/`BRAINLAYER_BIN` is still honoured.

**Naming.** `BRAINLAYER_KEG` is again the keg exactly as found -- what the
release-signature gate verifies, where naming the version is the precise thing to
do -- and the `opt/`-normalised form is `BRAINLAYER_KEG_STABLE`, used for
anything that may reach a plist. My round-1 rename broke
`test_source_checkout_install_sh_skips_gate_without_keg`, which asserts on
install.sh source text; it failed on CI `test (3.12)` and my scoped pre-push did
not cover that file. Restoring the name leaves both existing guards untouched and
still true, which is better evidence than editing them to match my code.

Tests: `..._remove_never_unlinks_the_packaged_daemon_out_of_the_keg` (install,
remove, assert the packaged daemon survives, then assert the keg is still
installable -- the real failure mode is not a missing file but every later
install failing closed) and
`..._refuses_path_fallback_when_a_keg_has_no_usable_interpreter` (both missing
interpreters, asserting the error and that nothing is rendered from a PATH guess
first). **Both verified to FAIL on 47d4e82 and pass here**, restored-tree and
re-run, not assumed.

226 passed across test_release_verify_signatures, test_installable_build,
test_launchd_hygiene, test_fleet_watchdog, test_cli_launchd_mode_a,
test_backup_daily. `ruff check` and `ruff format --check` clean.

Co-Authored-By: brainlayerClaude running claude-opus-5 <noreply@anthropic.com>
@cursor

cursor Bot commented Sep 4, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_06c28af6-4dcc-424e-92b7-e20c50ec2b03)

@EtanHey

EtanHey commented Sep 4, 2026

Copy link
Copy Markdown
Owner Author

Round 2 — three findings, all three real, plus a regression of mine that CI caught

I verified each in my own tree before acting rather than deferring to the review.

🔴 CRITICAL — confirmed, and it was mine

Keg-pinning changed what HOTLANE_BRAINBAR_DST means — from a copy this installer makes in ~/.local/lib to the keg's own shipped file — while :1066's rm -f on it went unchanged. On a writable Homebrew prefix install.sh remove would have unlinked a packaged file, after which every keg-pinned install fails closed on my own :491 guard until someone reinstalls the formula.

Every other rm in that block was already $BRAINLAYER_LIB_DIR-rooted; mine was the only one that had become keg-rooted. Fixed by naming the ~/.local/lib copy literally rather than by guarding on HOTLANE_BRAINBAR_KEG_PINNED, so that a future change to what that variable means cannot make this destructive again.

The generalisable lesson, since this is the third such case this week: when you change what a path means, re-read every site that acts on it. HOTLANE_BRAINBAR_DST has 8 hits. I had checked the ones I edited, not the ones that merely used it.

MEDIUM — confirmed

A detected keg with a missing bin/python / bin/brainlayer fell through to command -v python3 / which brainlayer. That is the same fail-open this change exists to close, reintroduced as a fallback inside the fix for it: if a keg is present, PATH's answer is wrong by definition. With a keg detected and no explicit override, a missing keg interpreter is now an error. An explicit PYTHON_BIN / BRAINLAYER_BIN is still honoured.

HIGH — the tests now catch both

  • test_launchd_remove_never_unlinks_the_packaged_daemon_out_of_the_keg — installs, removes, asserts the packaged daemon survives, then asserts the keg is still installable afterwards, because the real failure mode is not one missing file but every later install failing closed.
  • test_launchd_installer_refuses_path_fallback_when_a_keg_has_no_usable_interpreter — both missing interpreters, asserting the error text and that nothing is rendered from a PATH guess before the refusal.

Both verified to FAIL on 47d4e82 and pass on 669fc5f — restored tree, re-ran, restored. Not assumed.

A regression I caused, and the gate that missed it

My round-1 rename of BRAINLAYER_KEG broke test_release_verify_signatures.py::test_source_checkout_install_sh_skips_gate_without_keg, which asserts on install.sh source text. CI test (3.12) failed on round 1.

Fixed by restoring BRAINLAYER_KEG as the raw keg root the signature gate verifies, and naming the opt/-normalised form BRAINLAYER_KEG_STABLE. That leaves both existing guards untouched and still true, which is better evidence than editing them to match my code.

Worth flagging for the lane: BRAINLAYER_PREPUSH_SCOPE=changed-only did not map scripts/launchd/install.sh to tests/test_release_verify_signatures.py, which is why my pre-push was green on a change CI failed.

Numbers

226 passed across test_release_verify_signatures, test_installable_build, test_launchd_hygiene, test_fleet_watchdog, test_cli_launchd_mode_a, test_backup_daily. ruff check and ruff format --check clean. Round-2 CI green on launchd (macos-15), swift (macos-15), lint, ratchet table, CodeRabbit and all five DeepSource analyzers.

On the deploy, since it follows from a finding in this PR

brew upgrade does not re-render existing plists — the M4's eight are Jun 26 ×4, Jul 1, Aug 19, Sep 2, and 1.5.12 moved none of them. So shipping 1.5.13 fixes the renderer and not the machines. The deploy is two steps per Mac: upgrade the keg, and re-render the seven affected labels from the keg (hotlane, decay, health-check, maintenance, p0-counter, repair-fts, throughput-watchdog — deliberately not all, so nothing dormant is enabled and com.brainlayer.watch stays => disabled), with fleet-watchdog-quiesce before and fleet-watchdog-resume after.

— brainlayerClaude (worker) · claude-code/claude-opus-5

@EtanHey
EtanHey merged commit 64bd6e9 into main Sep 4, 2026
18 checks passed
EtanHey added a commit that referenced this pull request Sep 4, 2026
All six sites: pyproject.toml, src/brainlayer/__init__.py, server.json
(root + packages[0]), brain-bar/bundle/Info.plist (short, bundle, release).
Casks/brainbar.rb stays 1.5.9: no Swift change this release, declared to
scripts/brainlayer-version-check.sh via
BRAINLAYER_VERSION_CHECK_CASK_LAG_REASON="no BrainBar release for 1.5.13".

Why a release. #757 (64bd6e9) changed `scripts/launchd/**`, which pyproject
force-includes into the wheel as `brainlayer/launchd/`. That content is exactly
what the keg ships and exactly what the fix has to reach: the renderer that
decides which interpreter every com.brainlayer.* plist executes, and the
hotlane daemon the plist now names inside the keg instead of copying out of it.
Reusing 1.5.12 would put new packaged content under an identical version number
— the false-green this sprint exists to close. The running binary must answer a
`__build_sha__` descending from 64bd6e9.

What this release does NOT do, stated because the deploy depends on it. Shipping
1.5.13 fixes the RENDERER, not the machines. `brew upgrade` does not re-render
existing plists — measured: the M4's eight stale jobs are dated Jun 26 x4,
Jul 1, Aug 19 and Sep 2, and 1.5.12 moved none of them. Each Mac therefore needs
a second step after the keg upgrade: re-render the affected labels from the keg,
so the new keg-resolving renderer actually rewrites them.

Co-authored-by: brainlayerClaude running claude-opus-5 <noreply@anthropic.com>
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