feat(moments): a mount that keeps arriving where it does not apply proposes its own removal (milestone 458 step 7b, #4955)
CI & Build / Python lint (push) Successful in 2s
CI & Build / Plugin hooks (push) Successful in 16s
CI & Build / TypeScript typecheck (push) Successful in 54s
CI & Build / integration (push) Successful in 1m19s
CI & Build / Python tests (push) Successful in 2m3s
CI & Build / Build & push image (push) Successful in 18s
CI & Build / Python lint (push) Successful in 2s
CI & Build / Plugin hooks (push) Successful in 16s
CI & Build / TypeScript typecheck (push) Successful in 54s
CI & Build / integration (push) Successful in 1m19s
CI & Build / Python tests (push) Successful in 2m3s
CI & Build / Build & push image (push) Successful in 18s
The open-after-moment signal proposes a mount; nothing proposed taking one off, so a wrong mount was noise at every occurrence until someone happened to notice. rule_misfired(rule_id, moment, why, reached_by) records a report against a MOUNTED pair, counted per distinct day (the MCP door carries no session id) on a new rule_moment_judgments.misfire column (migration 0119, backup v24). At three days the response carries a line asking the agent to offer the operator the fix - reject takes the rule off, unmap_action stops the action reaching the moment, confirm keeps the mount and stops the asking - and Settings > Moments lists it as an unmount proposal with the reasons and the actions that reached it. A re-mount clears the count. Taught in moments.md, missed-retrieval.md and the reply hold's wording. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -181,13 +181,22 @@ def reply_hold_reason(held: list[dict]) -> str:
|
||||
trigger = f"; it applies when {item['trigger']}" if item.get("trigger") else ""
|
||||
parts.append(f"“{item['title']}” ({why}{trigger}) — get_rule({item['rule_id']})")
|
||||
noun = "a standing rule" if len(held) == 1 else "standing rules"
|
||||
# A mount that does not bear on this reply is a misfire worth one call:
|
||||
# reports gather into an unmount proposal for the operator (step 7b).
|
||||
mounted = [item for item in held if item.get("moment")]
|
||||
misfire = (
|
||||
" If one mounted on a moment has nothing to do with this reply, "
|
||||
f"rule_misfired({mounted[0]['rule_id']}, \"{mounted[0]['moment']}\", why) "
|
||||
"records that."
|
||||
if mounted else ""
|
||||
)
|
||||
return (
|
||||
f"Held for one read before this reply goes out: {noun} this session "
|
||||
f"has not opened: " + "; ".join(parts) + ". Read "
|
||||
+ ("it" if len(held) == 1 else "them")
|
||||
+ ", then send the reply — unchanged if it already does what the rule "
|
||||
"asks, which is a judgement only you can make. This check runs once "
|
||||
"per rule; the rewrite is never held."
|
||||
"asks, which is a judgement only you can make." + misfire
|
||||
+ " This check runs once per rule; the rewrite is never held."
|
||||
)
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user