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

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:
2026-10-26 16:29:40 -04:00
co-authored by Claude Opus 5.5
parent 83cb6420e2
commit 7faaa311d7
7 changed files with 178 additions and 30 deletions
+43
View File
@@ -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"