fix(6470): a moment proposal counts only opens no hook explained, and asks the reader to judge it
CI & Build / Python lint (push) Successful in 3s
CI & Build / Plugin hooks (push) Successful in 12s
CI & Build / TypeScript typecheck (push) Successful in 35s
CI & Build / integration (push) Successful in 1m4s
CI & Build / Python tests (push) Successful in 1m46s
CI & Build / Build & push image (push) Successful in 37s
CI & Build / Python lint (push) Successful in 3s
CI & Build / Plugin hooks (push) Successful in 12s
CI & Build / TypeScript typecheck (push) Successful in 35s
CI & Build / integration (push) Successful in 1m4s
CI & Build / Python tests (push) Successful in 1m46s
CI & Build / Build & push image (push) Successful in 37s
The signal counted every get_rule open against every moment from the previous three minutes, so a rule a search arm had just shown was proposed for whatever moment happened to fire. All nine pending signal proposals were wrong. - The hook skips an open of a rule a hook named this session, and sends the last three acts from 90 seconds instead of 30 from 180. - A rule already mounted anywhere gathers no signal evidence. - A signal pair keeps the actions that reached its moment and shows them as its why. - The proposal line says it is co-occurrence, not a recommendation, and asks the reader to check the rule against the moment before offering it; moments.md says the same. Plugin 2026.10.26.2029. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -195,7 +195,23 @@ async def test_the_open_resolves_acts_through_the_installs_mappings(world):
|
||||
out = await judgments_svc.opened_after(uid, done.id, acts, session_id="s1")
|
||||
assert "work.deliver" in out["moments"]
|
||||
assert "work.run" not in out["moments"]
|
||||
assert (await _row(done.id, "work.deliver")).source == "signal"
|
||||
row = await _row(done.id, "work.deliver")
|
||||
assert row.source == "signal"
|
||||
# The action that reached the moment is kept, and shown as the why.
|
||||
assert row.evidence["reached_by"] == {"git push": 1}
|
||||
assert row.note.startswith("Opened just after `work.deliver` (reached by `git push`)")
|
||||
|
||||
|
||||
async def test_a_rule_already_mounted_gathers_no_signal(world):
|
||||
"""A mounted rule arrives by lookup at its own moments, so an open of it
|
||||
is no evidence it is missing another."""
|
||||
uid, done = world["uid"], world["done"]
|
||||
await rulebooks_svc.set_rule_moments(done.id, uid, ["work.finish"])
|
||||
for situation in ("a", "b", "c", "d"):
|
||||
assert await judgments_svc.co_occurred(
|
||||
uid, done.id, ["work.verify"], situation=situation,
|
||||
) == ""
|
||||
assert await _row(done.id, "work.verify") is None
|
||||
|
||||
|
||||
# ── The misfire ──────────────────────────────────────────────────────────────
|
||||
|
||||
@@ -61,6 +61,29 @@ def test_the_proposal_line_names_the_tool_that_answers_it():
|
||||
assert "judge_rule_moments" in line and '"reject"' in line
|
||||
|
||||
|
||||
def test_the_proposal_line_is_a_question_to_check_not_advice_to_relay():
|
||||
rule = SimpleNamespace(id=11, title="Definition of done", kind="rule")
|
||||
evidence = {"situations": ["a", "b", "c"],
|
||||
"reached_by": {"git push": 3, "git push --tags": 1}}
|
||||
line = svc._proposal_line(rule, "work.deliver", evidence)
|
||||
assert "co-occurrence, not a recommendation" in line
|
||||
assert "`list_moments`" in line and "if it is about a subject, leave it" in line
|
||||
assert "(reached by `git push`, `git push --tags`)" in line
|
||||
note = svc._signal_note("work.deliver", evidence)
|
||||
assert note.startswith("Opened just after `work.deliver` (reached by `git push`")
|
||||
assert "3 distinct sessions" in note
|
||||
|
||||
|
||||
def test_the_actions_a_signal_remembers_are_bounded():
|
||||
ev: dict = {}
|
||||
for i in range(svc._SIGNAL_ACTIONS_CAP + 3):
|
||||
ev = svc._add_reached(ev, f"cmd {i}")
|
||||
ev = svc._add_reached(ev, "cmd 0")
|
||||
assert len(ev["reached_by"]) == svc._SIGNAL_ACTIONS_CAP
|
||||
assert ev["reached_by"]["cmd 0"] == 2
|
||||
assert svc._add_reached({}, "")["reached_by"] == {}
|
||||
|
||||
|
||||
# ── The misfire ──────────────────────────────────────────────────────────────
|
||||
|
||||
|
||||
|
||||
@@ -133,6 +133,49 @@ def test_an_open_sends_the_window_and_prints_the_answer(sandbox):
|
||||
assert (tmp / "grimoire-priorart" / "s1.opened.ids").read_text().startswith("11\t")
|
||||
|
||||
|
||||
def test_the_window_is_the_last_three_acts(sandbox):
|
||||
tmp, env = sandbox
|
||||
ledger = tmp / "grimoire-moment"
|
||||
ledger.mkdir()
|
||||
now = int(time.time())
|
||||
acts = [{"tool_name": "Bash", "tool_input": {"command": f"step {i}"}} for i in range(5)]
|
||||
(ledger / "s1.acts").write_text(
|
||||
"".join(f"{now - 10 + i}\t{json.dumps(a)}\n" for i, a in enumerate(acts))
|
||||
)
|
||||
_run("grimoire_record_opened.sh",
|
||||
{"session_id": "s1", "tool_name": "mcp__grimoire__get_rule",
|
||||
"tool_input": {"rule_id": 11}}, env)
|
||||
body = json.loads((tmp / "curl.body").read_text())
|
||||
assert body["acts"] == acts[-3:]
|
||||
|
||||
|
||||
def test_an_open_of_a_rule_a_hook_just_named_is_not_reported(sandbox):
|
||||
"""A ranked arm or a moment line explains that open; the moment beside it
|
||||
does not, so it is no evidence for a mount."""
|
||||
tmp, env = sandbox
|
||||
ledger = tmp / "grimoire-moment"
|
||||
ledger.mkdir()
|
||||
now = int(time.time())
|
||||
(ledger / "s1.acts").write_text(
|
||||
f"{now - 5}\t{json.dumps({'tool_name': 'Bash', 'tool_input': {'command': 'git push'}})}\n"
|
||||
)
|
||||
named = tmp / "grimoire-priorart"
|
||||
named.mkdir()
|
||||
(named / "s1.rules.ids").write_text(f"7\t{now - 30}\n11\t{now - 20}\n")
|
||||
out = _run("grimoire_record_opened.sh",
|
||||
{"session_id": "s1", "tool_name": "mcp__grimoire__get_rule",
|
||||
"tool_input": {"rule_id": 11}}, env)
|
||||
assert out.stdout == ""
|
||||
assert not (tmp / "curl.log").exists()
|
||||
# The open itself is still recorded.
|
||||
assert (named / "s1.opened.ids").read_text().startswith("11\t")
|
||||
# A rule no hook named is still reported.
|
||||
_run("grimoire_record_opened.sh",
|
||||
{"session_id": "s1", "tool_name": "mcp__grimoire__get_rule",
|
||||
"tool_input": {"rule_id": 1}}, env)
|
||||
assert json.loads((tmp / "curl.body").read_text())["rule_id"] == 1
|
||||
|
||||
|
||||
def test_an_open_with_nothing_in_the_window_sends_nothing(sandbox):
|
||||
tmp, env = sandbox
|
||||
ledger = tmp / "grimoire-moment"
|
||||
|
||||
Reference in New Issue
Block a user