Skip to content

test(write-queue): take the wall clock out of the brain_store retry test, and pin the budget that governs (XS) - #773

Merged
EtanHey merged 2 commits into
mainfrom
fix/store-busy-budget-injectable
Sep 5, 2026
Merged

test(write-queue): take the wall clock out of the brain_store retry test, and pin the budget that governs (XS)#773
EtanHey merged 2 commits into
mainfrom
fix/store-busy-budget-injectable

Conversation

@EtanHey

@EtanHey EtanHey commented Sep 5, 2026

Copy link
Copy Markdown
Owner

What forced this PR

tests/test_write_queue.py::TestStoreRetryOnLock::test_store_retries_busy_error_before_queueing
failed on #762 attempt 1 (ubuntu, py3.13): assert 1 == 3, 1 failed / 4524 passed — with
nothing in that PR reachable from the failure (0 src lines changed).

Mechanism

The test patches _retry_delay to 0.001 but has no control over the wall clock. _store
sets a deadline of now + BRAINLAYER_STORE_BUSY_BUDGET_MS (400ms default,
src/brainlayer/mcp/store_handler.py:32). On a loaded runner that budget expired after attempt 1,
so the handler deferred instead of retrying three times:

brain_store BusyError exceeded 400ms busy budget after attempt 1/4; deferring

assert attempts == 3 then reads a slow machine as a broken retry loop.

The change (tests only)

  1. The retry test pins the budget: BRAINLAYER_STORE_BUSY_BUDGET_MS=60000. That test is about
    the retry loop, so the clock comes out of it — 60s cannot expire across three mocked attempts
    on any runner.
  2. A new sibling asserts the other half:
    test_store_busy_budget_governs_and_is_injectable — budget 100ms with _retry_delay 0.3s, so
    the remaining budget cannot cover the next backoff and attempt 1 defers
    (status: DEFERRED, reason: DB_BUSY, one queue file). The deferral stops being the flake and
    becomes the asserted behaviour.

No src change, no behaviour change. The brief asked to "make the budget injectable"; it already
is — _store_busy_budget_ms() reads the env var on every call, so nothing was cached and
nothing needed rewiring. The test simply never used the knob. Production defaults untouched.

Evidence — mutation, not assertion

Check Result
New test with its setenv removed (400ms default, same 0.3s delay) assert 2 == 1 — it retries; the knob is what makes the deferral deterministic
Retry test with its pin removed, under BRAINLAYER_STORE_BUSY_BUDGET_MS=1 assert 0 == 3 — the reported flake, forced
Retry test with the pin, under that same hostile =1 env 5 passed
TestStoreRetryOnLock, 30 consecutive runs, random order on 30/30 green (0.56–0.63s)
tests/test_write_queue.py 76 passed
ruff check + ruff format --check clean
Scoped pre-push gate on this branch green — "BrainLayer test gate passed."

One detail of the brief disproved

The brief suggested forcing the budget to 1ms. That is too small: at 1ms the deadline is
already spent inside _remaining_store_busy_budget_ms at store_handler.py:1030, before
store_memory is ever called — attempts == 0, and the test would pass for the wrong reason
(that is exactly what the =1 mutation row above shows). 100ms is the smallest value that
still reaches attempt 1.

Size

XS — 1 test file: 1 pinned env var, 1 new test.

@coderabbitai review


Opened by brainlayerClaude-19a28f09 running claude-opus-5.


Note

Low Risk
Only test changes in tests/test_write_queue.py; production store handler logic and defaults are untouched.

Overview
Fixes flaky TestStoreRetryOnLock coverage where _store’s default 400ms BRAINLAYER_STORE_BUSY_BUDGET_MS wall-clock deadline could expire on slow CI before mocked retries finished, so the handler deferred instead of retrying three times.

The existing busy-retry test now sets BRAINLAYER_STORE_BUSY_BUDGET_MS=60000 so the case targets the retry loop, not runner timing. A new test test_store_busy_budget_governs_and_is_injectable asserts the opposite path: with a 100ms budget and 0.3s retry delay, one BusyError leads to DEFERRED / DB_BUSY and a single JSONL queue file. A _frozen_monotonic helper pins store_handler.time.monotonic so budget math is deterministic without freezing asyncio’s clock.

Tests only — no production behavior or default budget changes.

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

Note

Freeze monotonic() clock and pin busy budget in brain_store retry tests

  • Adds a _frozen_monotonic test helper that returns a fixed value from monotonic() while delegating all other time functions to the real module
  • Pins BRAINLAYER_STORE_BUSY_BUDGET_MS to 60s in test_store_queues_on_busy_error so the three mocked retry attempts complete without early deferral
  • Adds test_store_busy_budget_governs_and_is_injectable, which injects a 100ms budget, 300ms retry delay, and frozen clock to verify that a single busy attempt defers and queues a JSONL entry deterministically

Macroscope summarized fff2a8f.

…est, and pin the budget that governs

`TestStoreRetryOnLock::test_store_retries_busy_error_before_queueing` failed on #762 attempt 1
(ubuntu, py3.13): `assert 1 == 3`, 1 failed / 4524 passed, with nothing from that PR reachable in
0 src lines. The test patched `_retry_delay` to 0.001 but had no control over the WALL-CLOCK
deadline: `_store` sets one at now + BRAINLAYER_STORE_BUSY_BUDGET_MS (400ms default). On a loaded
runner the budget expired after attempt 1 and the handler deferred instead of retrying three times
-- "brain_store BusyError exceeded 400ms busy budget after attempt 1/4; deferring".

The retry test now pins BRAINLAYER_STORE_BUSY_BUDGET_MS=60000: 60s cannot expire across three
mocked attempts on any runner. It asserts the retry loop, so the clock is out of it.

A new sibling asserts the other half -- that the budget, not the retry count, is what decides to
defer, and that it is reachable from a test: budget 100ms with `_retry_delay` 0.3s, so the
remaining budget cannot cover the next backoff and attempt 1 defers with status DEFERRED and one
queue file.

No src change: the env reader `_store_busy_budget_ms()` already reads
BRAINLAYER_STORE_BUSY_BUDGET_MS on every call, so the budget was already injectable -- the test
just never used it. Production defaults untouched.

Evidence (mutation, not assertion):
- New test with its `setenv` removed (400ms default, same 0.3s delay): `assert 2 == 1` -- it
  retries. The knob is what makes the deferral deterministic.
- Retry test with its pin removed under BRAINLAYER_STORE_BUSY_BUDGET_MS=1: `assert 0 == 3` --
  the reported flake, forced. With the pin, green under that same hostile env.
- TestStoreRetryOnLock 30/30 green in random order; tests/test_write_queue.py 76 passed.
- ruff check + ruff format --check clean.

The brief suggested forcing the budget to 1ms; that is too small. At 1ms the deadline is already
spent at `_remaining_store_busy_budget_ms` before `store_memory` is ever called (attempts == 0),
so the test would pass for the wrong reason. 100ms is the smallest value that still reaches
attempt 1.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@EtanHey EtanHey added the XS Extra-small change (400 lines or fewer) label Sep 5, 2026
@cursor

cursor Bot commented Sep 5, 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_2f9faddf-4f38-43b6-9b69-0b64194e3032)

@coderabbitai

coderabbitai Bot commented Sep 5, 2026

Copy link
Copy Markdown

Warning

Review limit reached

Next included review available in 14 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: acbc9e95-f8a1-455c-921a-28a3bbd526d1

📥 Commits

Reviewing files that changed from the base of the PR and between 7272db4 and fff2a8f.

📒 Files selected for processing (1)
  • tests/test_write_queue.py

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.

@deepsource-io

deepsource-io Bot commented Sep 5, 2026

Copy link
Copy Markdown

DeepSource Code Review

We reviewed changes in 7272db4...fff2a8f 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 5, 2026 3:21p.m. Review ↗
Swift Sep 5, 2026 3:21p.m. Review ↗
JavaScript Sep 5, 2026 3:21p.m. Review ↗
Shell Sep 5, 2026 3:21p.m. Review ↗
Secrets Sep 5, 2026 3:21p.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.

@github-actions

github-actions Bot commented Sep 5, 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
commit provenance 🔴 RED checkout 706583bc85af is neither fff2a8f0ddc3 nor a merge of it — this run was triggered for a commit it does not have checked out commit graph + live PR head · in-process · runner Which commit this whole table is about. On a pull_request event the checkout is GitHub's synthetic merge ref, whose sha is not on the PR — #759's table printed 13fa724278bf while that PR's head was 4632f979 — so this row names the PR-head parent instead, the sha a reviewer can actually see. The comparison sha is read live from repos/{owner}/{repo}/pulls/{n} when the table is collected, not taken from the event payload, because the payload cannot know the run has been overtaken. Residual window, stated rather than papered over: a push landing between that read and the comment being posted is not caught here — the run for that push refreshes the table.
baseline attestation 🟢 GREEN baseline f421d1a7c5e6 matches the main attestation (run 33979237066 · main 2264b19ea0aa · 2026-09-05T16:53:22Z) main attestation artifact via Actions API · in-process · runner What every comparison is measured AGAINST, and who says so. The baseline fields of tests/fixtures/sprint_gate/corpus.json (queries, latency_baseline_ms, thresholds) are compared to the ratchet-attestation artifact of the latest successful push or (no-input) workflow_dispatch run of ratchet-attest.yml on main, fetched through the Actions API — a PR run cannot write to another run's artifacts. A field that differs is RED unless that main run measured the new value; today no runner-side collector measures any baseline field, so today the baseline cannot move by PR at all, and this row says so instead of a hand edit passing. Boundary: the comparator is this PR's checkout of ci_ratchet_table.py, diff-reviewable, not tamper-proof.
provenance 🟢 GREEN stamped 706583bc85af == 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. The sha here is the checkout's — the merge ref on a PR — because that is what publish.yml stamps at release time; the PR-head sha this table describes is the one in commit provenance above.
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 Margin p50: margin unmeasured — 0 of the 5 attested green main runs it needs; no verdict is rendered from fewer. Margin p95: margin unmeasured — 0 of the 5 attested green main runs it needs; no verdict is rendered from fewer. Calibrated on MacBook-Pro.local at 2026-09-01T08:42:22Z 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 Ceiling: average CPU < 30% over a 60 s window (resource_budget in scripts/sprint_gate.py), ratified and kept as a hard budget. Margin daemon: margin unmeasured — 0 of the 5 attested green main runs it needs; no verdict is rendered from fewer. Margin helper: margin unmeasured — 0 of the 5 attested green main runs it needs; no verdict is rendered from fewer. Margin watcher: margin unmeasured — 0 of the 5 attested green main runs it needs; no verdict is rendered from fewer. 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.

1 RED row(s) to clear: commit provenance.

Measured on Linux/x86_64 · measured fff2a8f0ddc3 · PR head fff2a8f0ddc3 · checkout 706583bc85af · run · updated 2026-09-05 17:03:26 UTC

…it spends no wall clock at all

Round-1 review low on #773 (ACCEPT + optional) — taken, because the PR's whole thesis is taking the
wall clock out of this test, and leaving ~100ms of it in the replacement is the same class of
defect one size down.

With a real clock, a pathological stall between the deadline stamp and the first budget read
(store_handler.py:1029-1030) spends the entire 100ms budget there,
`_remaining_store_busy_budget_ms` raises before `store_memory` is ever called, and the store defers
with attempts == 0 -- a pass for the wrong reason. `_frozen_monotonic` hands store_handler the real
`time` module with `monotonic()` pinned to one value, so elapsed time cannot shrink the budget:
every read answers 100ms and machine load is irrelevant. Everything else (`time.time`,
`time.sleep`) delegates, so asyncio's own clock is untouched -- patching global `time.monotonic`
would have frozen that too.

Claim kept narrow, because I measured it: the freeze removes the CLOCK dependence, not the
arithmetic. The remaining budget is `int((deadline - now) * 1000)`, and at a 1ms budget that float
lands on 0 even frozen (int((p+0.001-p)*1000) == 0; at 400ms it is 399). So 100ms remains the
floor, and the comment says so rather than implying the freeze licenses a smaller one.

Evidence:
- Still discriminates: with the budget knob removed (default 400) and the clock frozen, the test
  fails `assert 2 == 1` -- it retries. The knob is what makes the deferral the asserted behaviour.
- TestStoreRetryOnLock 10/10 in random order, 0.60-0.80s; tests/test_write_queue.py 76 passed.
- ruff check + ruff format clean. Full CI matrix was green on the previous head (3.11/3.12/3.13).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@cursor

cursor Bot commented Sep 5, 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_3d83a177-b6d9-4f7a-9024-165acbd643df)

@EtanHey

EtanHey commented Sep 5, 2026

Copy link
Copy Markdown
Owner Author

Round 1 — the low is taken, with the claim kept narrower than "clock-free"

Fixed in fff2a8f0. You marked it optional; I took it because the PR's whole thesis is taking
the wall clock out of this test, and leaving ~100ms of it in the replacement is the same class of
defect one size down.

Your read of the mechanism is right: with a real clock, a stall between the deadline stamp and the
first budget read (store_handler.py:1029-1030) spends the entire 100ms there,
_remaining_store_busy_budget_ms raises before store_memory is ever called, and the store defers
with attempts == 0 — a pass for the wrong reason.

_frozen_monotonic hands store_handler the real time module with monotonic() pinned to one
value. Elapsed time can no longer shrink the budget: every read answers 100ms, so machine load is
irrelevant and the branch under test is the delay-vs-remaining one by construction
(int(0.3 * 1000) >= 100). Everything else (time.time, time.sleep) delegates — patching global
time.monotonic would have frozen asyncio's clock too.

One correction to my own framing, because I measured it rather than assuming it. The freeze
removes the clock dependence, not the arithmetic. Remaining budget is
int((deadline - now) * 1000), and at a 1ms budget that float lands on 0 even frozen
(int((p+0.001-p)*1000) == 0; at 400ms it is 399). So 100ms stays the floor, freeze or no freeze —
I would have overclaimed "fully clock-free at any budget". The comment in the test says this
explicitly so nobody reads the freeze as a licence to shrink the budget.

Still discriminates: with the budget knob removed (default 400) and the clock frozen, the test
fails assert 2 == 1 — it retries. The knob remains what makes the deferral the asserted behaviour.

TestStoreRetryOnLock 10/10 in random order (0.60–0.80s); tests/test_write_queue.py 76
passed
; ruff clean. The previous head was green on 3.11/3.12/3.13.


brainlayerClaude-19a28f09 running claude-opus-5.

@EtanHey
EtanHey merged commit 706583b into main Sep 5, 2026
18 checks passed
EtanHey added a commit that referenced this pull request Sep 5, 2026
…he PYL-W0404 reimports

The DeepSource red on this PR was MINE, and my earlier comment on it was wrong. I inferred the
blocking issues were a pre-existing "method doesn't use self" baseline; the run report says
otherwise. The three blocking issues are:

  PYL-W0404 "Reimport 'watcher' (imported line 23)" -- tests/test_jsonl_watcher.py:85, 363, 521

Line 23 was the `import brainlayer.watcher` I added at module scope for the AST pins. Three
pre-existing tests already reach the module the way this file has always done it --
`from brainlayer import watcher as watcher_module`, function-local -- and my top-level import turned
all three into reimports. Cause: my change. Not a baseline.

Both modules the pins parse are now imported inside the test that needs them, matching the file's
own convention, and the module-level `import brainlayer.cli` / `import brainlayer.watcher` are gone.
`from brainlayer.watcher import (...)` at module scope stays: it does not collide, which is why
those three local imports were clean before this PR.

What disproved my earlier reasoning: tests/test_write_queue.py carries 56 methods that never use
`self` and #773 passed DeepSource Python, so that rule was never the blocker. I should have measured
that before posting the inference rather than after.

Evidence: tests/test_jsonl_watcher.py 112 passed; the 3 liveness pins green; ruff check + format
clean. The three named lines are unchanged by this commit -- only the import that collided with them
moved.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
EtanHey added a commit that referenced this pull request Sep 5, 2026
…, and pin the stdout/stderr split (XS) (#776)

* docs(watcher): name the health file as the canonical liveness surface, and pin the stdout/stderr split

The watcher seat's sampler read an empty throughput column because it grepped watch.out.log for
"Watcher alive" and got nothing. #759 added logging.basicConfig(stream=sys.stderr), so the
heartbeat rides stderr while the startup banner rides rich's stdout.

The brief offered two fixes: duplicate the heartbeat onto stdout, or document the split and make
the health file canonical. Taking the second. Duplicating it would put two writers on one signal
and make the noisier copy the one people grep -- and a prose log line is the wrong liveness surface
anyway. watcher-health.json already carries poll_count and updated_at, is JSON, and both fields
advance on every poll, which is exactly what a sampler needs.

AGENTS.md "Real-time JSONL Watcher" now states three things: read watcher-health.json for
liveness (with its BRAINLAYER_WATCHER_HEALTH_PATH override), which stream carries what and why,
and that grepping watch.out.log for "Watcher alive" returning nothing IS the split rather than a
dead watcher.

tests/test_jsonl_watcher.py::TestWatcherLivenessSurface pins both halves so the next reader does
not re-derive this from a grep:
- the health file advances poll_count 1 -> 2 and moves updated_at (tz-aware) across two polls
- the heartbeat's single emit site is `logger.info`, and the watch command's basicConfig names
  sys.stderr explicitly rather than inheriting a default (AST, not text matching)

Evidence:
- tests/test_jsonl_watcher.py: 111 passed.
- Mutation, both directions: turning the heartbeat's `logger.info` into `print` fails the pin;
  removing `stream=sys.stderr` alone fails it with "the watcher's log stream must be explicit, not
  inherited". Sources restored, `git diff src/` empty.
- The documented path and fields check out against the real artifact on this machine:
  ~/.local/share/brainlayer/watcher-health.json, poll_count=2, updated_at 2026-09-05T14:48:53Z.

Scope note: com.brainlayer.watch is disabled by Etan's ruling and this lane does not touch it, so
there is no live-daemon verification here -- no watcher code changed, only docs and tests. The
second test asserts on cli/__init__.py from the watcher's suite, so a changed-only push touching
only the CLI will not run it; that mapping is a separate concern, called out in the docstring.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* docs(watcher): the health path is database-relative, the clamp is on both streams, and the pins tighten

Round-1 bot + review round on #776. All five taken; the two doc findings were real defects in what
I wrote.

Macroscope medium (AGENTS.md) — CONFIRMED. The documented liveness path was wrong whenever
BRAINLAYER_DB is set: `watch` resolves health_path as `watcher-health.json` beside the RESOLVED db
(`cli/__init__.py`, `paths.get_db_path()` honours BRAINLAYER_DB), so following the hardcoded
`~/.local/share/brainlayer/...` reads a stale or absent file. Now documented as database-relative,
with that path named as the canonical-DB DEFAULT, the startup banner as where the real path is
printed, and BRAINLAYER_WATCHER_HEALTH_PATH as the outright override.

Review low (AGENTS.md) — CONFIRMED. The clamp was attributed to stdout only. It is on BOTH streams:
`enforce_min_poll_interval()` logs it at WARNING to stderr (`watcher.py:86`) and the command also
rprints it. Operators find it in watch.err.log, which the old wording hid.

Review low — `assert second["updated_at"] >= first["updated_at"]` passed on an UNCHANGED timestamp,
so only poll_count was really pinned and a sampler reading updated_at alone was unlocked. Now
strict `>`, compared as parsed datetimes.

Review low — the heartbeat pin filtered `ast.Constant` first args only, so a duplicate spelled
`rprint(f"Watcher alive: …")` (an `ast.JoinedStr`) would not have been counted and
`len(...) == 1` would still pass. `_leading_string_literal` now reads the leading literal out of
either shape. Verified by mutation: adding exactly that f-string print next to the logger call
fails the pin with `assert 2 == 1`. Restored; `git diff src/` empty.

DeepSource Python (blocking, 4 findings) — all four addressed by splitting the one AST test in two:
- cyclomatic complexity 16 "high" -> two focused tests plus three module-level helpers;
- two methods not using their instance -> `@staticmethod`;
- bare `next()` -> a list comprehension with `assert len(...) == 1`, which also names what was
  expected when it fails.

Evidence: tests/test_jsonl_watcher.py 112 passed (111 before; the split adds one). ruff check +
ruff format --check clean. No src change — docs and tests only. Full CI matrix was green on the
previous head (3.11/3.12/3.13).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* test(watcher): import the parsed modules function-locally, clearing the PYL-W0404 reimports

The DeepSource red on this PR was MINE, and my earlier comment on it was wrong. I inferred the
blocking issues were a pre-existing "method doesn't use self" baseline; the run report says
otherwise. The three blocking issues are:

  PYL-W0404 "Reimport 'watcher' (imported line 23)" -- tests/test_jsonl_watcher.py:85, 363, 521

Line 23 was the `import brainlayer.watcher` I added at module scope for the AST pins. Three
pre-existing tests already reach the module the way this file has always done it --
`from brainlayer import watcher as watcher_module`, function-local -- and my top-level import turned
all three into reimports. Cause: my change. Not a baseline.

Both modules the pins parse are now imported inside the test that needs them, matching the file's
own convention, and the module-level `import brainlayer.cli` / `import brainlayer.watcher` are gone.
`from brainlayer.watcher import (...)` at module scope stays: it does not collide, which is why
those three local imports were clean before this PR.

What disproved my earlier reasoning: tests/test_write_queue.py carries 56 methods that never use
`self` and #773 passed DeepSource Python, so that rule was never the blocker. I should have measured
that before posting the inference rather than after.

Evidence: tests/test_jsonl_watcher.py 112 passed; the 3 liveness pins green; ruff check + format
clean. The three named lines are unchanged by this commit -- only the import that collided with them
moved.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
@EtanHey
EtanHey deleted the fix/store-busy-budget-injectable branch September 5, 2026 16:23
@EtanHey EtanHey added the size:S Tight-loop PR size: 21-100 hand-written lines changed label Sep 5, 2026
EtanHey added a commit that referenced this pull request Sep 5, 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.15".

Why a release. The installed keg on the M4 is 1.5.14 / build_sha 3bbe19f.
Verified: `git merge-base --is-ancestor 7369f80 3bbe19f` -> false, so #781
-- the watcher per-poll burst fix, 14.97% -> 2.39% under the LaunchAgent's
background QoS -- is NOT in any installed keg. Enabling com.brainlayer.watch
today would start the burst-y watcher. 1.5.15 is what carries #781 (7369f80)
onto the Mac. Also in: #772 #773 #775 #776.

Co-authored-by: brainlayerClaude-ebe88b04 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

size:S Tight-loop PR size: 21-100 hand-written lines changed XS Extra-small change (400 lines or fewer)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant