align(4909b): every write with a path gets its rule check, whether or not prior art matched
CI & Build / Python lint (push) Successful in 2s
CI & Build / Plugin hooks (push) Successful in 14s
CI & Build / TypeScript typecheck (push) Successful in 53s
CI & Build / integration (push) Successful in 1m4s
CI & Build / Python tests (push) Successful in 1m56s
CI & Build / Build & push image (push) Successful in 22s
CI & Build / Python lint (push) Successful in 2s
CI & Build / Plugin hooks (push) Successful in 14s
CI & Build / TypeScript typecheck (push) Successful in 53s
CI & Build / integration (push) Successful in 1m4s
CI & Build / Python tests (push) Successful in 1m56s
CI & Build / Build & push image (push) Successful in 22s
The write-path rule arm ran only past the notes guard: a write whose code matched no snippet, issue or lesson returned before any rule was searched. It now runs before that guard, on `code or path`, and a write that matched nothing but a rule still returns the rule lines. Operator ruling (2026-10-05): yes. A rule about the file being written does not depend on a snippet resembling it. Cost: one more rule search per write that matched no prior art, with its own embedding (the query is `code or path`, not the notes arm's concept query, so the per-request memo does not cover it). Plus the preference slot from (c) on those writes. Expected telemetry shift, to be read on its own once this reaches main: write_path_rule calls rise toward write_path's count (14 days to 2026-10-22: write_path_rule 4,634 against write_path 3,786 — the notes arm skips trivial payloads, the rule arm does not, so the rule arm will now exceed it). Its zero-result share rises too, since the newly covered writes are the ones that matched nothing in the notes corpus. Tests: the gate test is inverted (a write with no prior art still gets its rule check); the design-only write now runs the rule arm on its path; two notes-arm tests read the write_path row instead of any row, since the rule arm writes its own. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -33,16 +33,8 @@ pytestmark = pytest.mark.usefixtures("_bind_user")
|
||||
# each of these does.
|
||||
|
||||
|
||||
# The write-path hint returns early when a write matched nothing at all — no
|
||||
# staleness, no synced record, no prior-art menu, no shape signal. The rule arm
|
||||
# sits deliberately on the FAR side of that guard, because it runs a semantic
|
||||
# search and moving it above would mean an embedding query on every write in
|
||||
# the session (which is why its gating is a separate question from
|
||||
# precision).
|
||||
#
|
||||
# So a fixture that stubs every other arm to empty never reaches the rule arm
|
||||
# at all — which is what the first run of this file did. The note hit below is
|
||||
# not decoration: it is the condition the arm requires in order to fire.
|
||||
# A prior-art hit for the fixtures that want the menu beside the rule lines.
|
||||
# The rule arm runs on every write with a path, whether or not this matched.
|
||||
_PRIOR_ART = [(0.72, fake_note(id=9, title="debounce helper", user_id=1,
|
||||
note_type="snippet"))]
|
||||
|
||||
@@ -180,21 +172,16 @@ async def test_the_arm_searches_on_its_OWN_bar_not_the_code_one():
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_the_arm_does_not_fire_on_a_write_that_matched_nothing():
|
||||
"""The gate, pinned — because the fixture above now depends on it and a
|
||||
silent change would make every other test here pass vacuously.
|
||||
|
||||
A write matching no prior art returns before the rule arm runs. That is
|
||||
deliberate: the arm is a semantic search, and ungating it means an
|
||||
embedding query on every write in the session. The gate stays until the
|
||||
arm's precision is fixed, so this failing is a reason to look at precision
|
||||
rather than to update the assertion.
|
||||
"""
|
||||
async def test_a_write_that_matched_no_prior_art_still_gets_its_rule_check():
|
||||
"""A rule about the file being written does not depend on a snippet
|
||||
resembling it, so the arm runs before the prior-art guard, not behind it."""
|
||||
rec = MagicMock()
|
||||
hits = [(0.71, fake_rule(id=156, title="A wait with no deadline is a bug"))]
|
||||
await _run_arm(hits, rec, prior_art=[])
|
||||
out = await _run_arm(hits, rec, prior_art=[])
|
||||
|
||||
assert rec.call_count == 0
|
||||
assert rec.call_args.kwargs["rule_ids"] == [156]
|
||||
assert "get_rule(156)" in out["context"]
|
||||
assert out["rule_ids"] == [156]
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
|
||||
Reference in New Issue
Block a user