CI & Build / Python lint (push) Successful in 2s
CI & Build / Plugin hooks (push) Successful in 14s
CI & Build / TypeScript typecheck (push) Successful in 52s
CI & Build / integration (push) Successful in 1m12s
CI & Build / Python tests (push) Successful in 1m53s
CI & Build / Build & push image (push) Successful in 12s
shape ledger, MCP projects/search/rulebooks tools, backup, chunking, plugin context, derived mirror, rule band, shape form gate, plugin version mint and note usage tests drop issue, milestone and rule numbers, dates and one-install figures from docstrings, comments and messages. Three shape-form-gate test names that told the discovery story now name the property: a registry module's helpers are not service functions, the divergence gate silences only a family contradiction, and callable helpers beside a callable canon still prompt. The rulebook tool-count comment that logged each milestone's additions is replaced by the reason it is a count. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
212 lines
8.9 KiB
Python
212 lines
8.9 KiB
Python
"""An act surfaces a SET of rules, and rank decides how loudly.
|
|
|
|
WHY THIS EXISTS
|
|
|
|
This arm is the whole delivery of rules to an act, and one command can be
|
|
governed by several rules at once — a `git push` by where to push, what not
|
|
to push, who polls CI and what to wait for — each of which alone permits the
|
|
mistake the others catch. One slot cannot serve that.
|
|
|
|
Two instruments, and they answer different questions:
|
|
|
|
- `_rule_band` decides HOW MANY. A fixed k fills its slots whether or not
|
|
anything deserves them; a band keeps only what scored close to the top,
|
|
so one clearly-relevant rule still shows one.
|
|
- `compact` decides HOW LOUD. A full line is ~143 tokens once the trigger
|
|
is rendered, so five of them cost ~646 before every Bash call.
|
|
Top-full-plus-references costs ~198.
|
|
|
|
WHAT THIS PINS
|
|
|
|
Structure, never wording — the lines are prose and will be rewritten:
|
|
|
|
1. The band keeps the top hit and everything within `_RULEHINT_BAND`, and
|
|
drops what falls outside. Falsified below from both sides: a hit just
|
|
inside survives, a hit just outside does not.
|
|
2. Rank decides volume — the first line carries the trigger, later lines do
|
|
not, and every line names its rule's id so any of them can be pulled.
|
|
3. The band reads SCORES ONLY. A top hit the session has already seen still
|
|
anchors the band, and its score still sets the cutoff. This is the axis
|
|
independence the renderer already keeps between `kind` and `seen`, and
|
|
the regression it prevents is subtle: letting the ledger reorder the
|
|
band would make "you were told this" change what counts as relevant.
|
|
|
|
The band width itself is deliberately NOT pinned. It is a tuning value with
|
|
a comment recording the measurement behind it, and a test asserting 0.05
|
|
would fail on every future retune while proving nothing about behaviour —
|
|
so the cases below express their scores as offsets from the constant.
|
|
"""
|
|
import pytest
|
|
|
|
from scribe.services.plugin_context import (
|
|
_RULEHINT_BAND,
|
|
_rule_band,
|
|
_rule_hint_line,
|
|
)
|
|
from tests.helpers import fake_rule
|
|
|
|
_TRIGGER = "about to run git push with an earlier CI run still unread"
|
|
|
|
|
|
def _hit(score: float, rule_id: int):
|
|
return (score, fake_rule(id=rule_id, title=f"rule {rule_id}",
|
|
when_to_apply=_TRIGGER))
|
|
|
|
|
|
def test_an_empty_result_stays_empty():
|
|
"""No hits is not a crash and not a phantom line."""
|
|
assert _rule_band([]) == []
|
|
|
|
|
|
def test_the_band_keeps_a_hit_just_inside_it():
|
|
"""The whole point: a close second rule reaches the agent."""
|
|
top = 0.75
|
|
hits = [_hit(top, 1), _hit(top - _RULEHINT_BAND + 0.01, 2)]
|
|
assert [r.id for _s, r in _rule_band(hits)] == [1, 2]
|
|
|
|
|
|
def test_the_band_drops_a_hit_just_outside_it():
|
|
"""And the band must actually BIND, or it is a fixed k wearing a hat."""
|
|
top = 0.75
|
|
hits = [_hit(top, 1), _hit(top - _RULEHINT_BAND - 0.01, 2)]
|
|
assert [r.id for _s, r in _rule_band(hits)] == [1]
|
|
|
|
|
|
def test_one_clearly_better_rule_still_surfaces_alone():
|
|
"""The behaviour the old limit of 1 got right, which must not regress.
|
|
|
|
A moment with a single relevant rule shows one line, because the corpus
|
|
said so — not because a constant capped it.
|
|
"""
|
|
hits = [_hit(0.80, 1), _hit(0.55, 2), _hit(0.54, 3)]
|
|
assert [r.id for _s, r in _rule_band(hits)] == [1]
|
|
|
|
|
|
def test_a_flat_cluster_surfaces_together():
|
|
"""Measured shape of this corpus: adjacent rules sit ~0.02 apart.
|
|
|
|
Four rules governing one act is the `git push` case the step exists for,
|
|
and at the measured spacing they must arrive together rather than the
|
|
ranker picking one of four near-ties.
|
|
"""
|
|
hits = [_hit(0.757, 2), _hit(0.735, 7), _hit(0.726, 1), _hit(0.711, 9)]
|
|
assert [r.id for _s, r in _rule_band(hits)] == [2, 7, 1, 9]
|
|
|
|
|
|
def test_the_band_is_computed_from_scores_not_from_the_ledger():
|
|
"""A seen top hit still anchors the band.
|
|
|
|
`_rule_band` never learns what the session has seen — dedup happens after
|
|
it, in the arms. Pinned here because the tempting "reorder so a fresh rule
|
|
leads" would silently change the cutoff, and the failure is invisible: the
|
|
arm would still emit lines, just the wrong set.
|
|
"""
|
|
hits = [_hit(0.80, 1), _hit(0.78, 2), _hit(0.60, 3)]
|
|
kept = _rule_band(hits)
|
|
# Independent of any `already` set, because it is not consulted.
|
|
assert [r.id for _s, r in kept] == [1, 2]
|
|
|
|
|
|
@pytest.mark.parametrize("seen", [False, True])
|
|
def test_the_leading_line_carries_the_trigger(seen):
|
|
"""Rank 0 gets the full rendering, on either tail."""
|
|
line = _rule_hint_line(
|
|
fake_rule(id=4, title="dev is home", when_to_apply=_TRIGGER),
|
|
where="to this Bash call", seen=seen, compact=False,
|
|
)
|
|
assert _TRIGGER in line
|
|
assert "get_rule(4)" in line
|
|
|
|
|
|
@pytest.mark.parametrize("seen", [False, True])
|
|
def test_a_later_line_cites_its_rule_without_quoting_the_trigger(seen):
|
|
"""Rank > 0 is a reference: identity and pointer, no trigger.
|
|
|
|
The trigger is the expensive half — often 300-400 characters — and
|
|
the leading line has already demonstrated the shape. Both assertions
|
|
matter: dropping the trigger is the saving, and keeping `get_rule(id)` is
|
|
what makes the saving safe, because a cited rule the reader cannot pull is
|
|
just noise.
|
|
"""
|
|
line = _rule_hint_line(
|
|
fake_rule(id=4, title="dev is home", when_to_apply=_TRIGGER),
|
|
where="to this Bash call", seen=seen, compact=True,
|
|
)
|
|
assert _TRIGGER not in line
|
|
assert "dev is home" in line
|
|
assert "get_rule(4)" in line
|
|
|
|
|
|
def test_shortening_a_line_does_not_decide_what_it_says_about_holding():
|
|
"""A reference still tells a repeat from a first surfacing.
|
|
|
|
A compact branch that drops the tail along with the trigger makes a rule
|
|
the session had already been told read exactly like one it had not. The
|
|
two are different claims — a repeat is rendered
|
|
precisely because the session may no longer HOLD what it was told — and
|
|
the tail is the entire difference a reader can act on.
|
|
|
|
`compact` and the ledger are independent axes. How much room a line gets is
|
|
a fact about its rank; what the session holds is a fact about the ledger;
|
|
and neither may be allowed to answer the other's question.
|
|
|
|
THREE STATES, so this checks three. Pinning only two would leave the
|
|
compact branch free to collapse the middle state into either neighbour.
|
|
"""
|
|
rule = fake_rule(id=4, title="dev is home", when_to_apply=_TRIGGER)
|
|
fresh = _rule_hint_line(rule, where="here", seen=False, compact=True)
|
|
named = _rule_hint_line(rule, where="here", seen=True, compact=True)
|
|
held = _rule_hint_line(rule, where="here", seen=True, held=True, compact=True)
|
|
|
|
assert len({fresh, named, held}) == 3, (
|
|
"the compact branch collapsed two holding states into one line"
|
|
)
|
|
assert "not in this session's loaded set" in fresh
|
|
assert "not opened" in named
|
|
assert "no longer hold it" in held
|
|
# The claim that most needs to survive shortening: a line the session never
|
|
# opened must not imply it did, however little room the line was given.
|
|
assert "no longer hold it" not in named
|
|
|
|
|
|
def test_a_compact_line_is_materially_shorter_than_a_full_one():
|
|
"""The cost claim, asserted rather than left in a comment.
|
|
|
|
Not a token count — that would pin the tokenizer. Half the characters is
|
|
the property that makes widening the arm affordable, and it is what fails
|
|
if a later edit puts the trigger back into the compact branch.
|
|
|
|
Measured against a REALISTIC trigger, because that is where the saving
|
|
lives: the rules this arm carries run 300-400 characters of trigger, and
|
|
a toy one-line trigger would make this pass on a compact branch
|
|
that had stopped saving anything.
|
|
"""
|
|
long_trigger = (
|
|
"Opening or merging a `dev`->`main` pull request, running "
|
|
"`git push origin main`, `git tag`, or minting a release, image tag "
|
|
"or other public artifact. Also whenever CI has just gone green and "
|
|
"the next step feels like shipping it, and whenever an earlier merge "
|
|
"this session reads like standing permission for the next one."
|
|
)
|
|
rule = fake_rule(id=4, title="dev is home", when_to_apply=long_trigger)
|
|
full = _rule_hint_line(rule, where="here", seen=False, compact=False)
|
|
compact = _rule_hint_line(rule, where="here", seen=False, compact=True)
|
|
assert len(compact) * 2 < len(full)
|
|
|
|
|
|
def test_a_preference_keeps_its_noun_when_compact():
|
|
"""Force survives the shortening.
|
|
|
|
`kind` and `compact` are independent axes. A preference rendered as a
|
|
reference must still not read as a rule — the noun is the whole of the
|
|
visual difference, so losing it in the compact branch would make every
|
|
cited preference bind.
|
|
"""
|
|
line = _rule_hint_line(
|
|
fake_rule(id=5, title="pace debugging", kind="preference",
|
|
when_to_apply=_TRIGGER),
|
|
where="here", seen=False, compact=True,
|
|
)
|
|
assert "preference" in line.lower()
|
|
assert "standing rule" not in line.lower()
|