feat(4636): rule pull-through per surface, and per-rule usage with confirmed lessons on list_rules
CI & Build / Python lint (push) Successful in 3s
CI & Build / Plugin hooks (push) Successful in 13s
CI & Build / TypeScript typecheck (push) Successful in 55s
CI & Build / integration (push) Successful in 1m3s
CI & Build / Python tests (push) Successful in 1m56s
CI & Build / Build & push image (push) Successful in 22s
CI & Build / Python lint (push) Successful in 3s
CI & Build / Plugin hooks (push) Successful in 13s
CI & Build / TypeScript typecheck (push) Successful in 55s
CI & Build / integration (push) Successful in 1m3s
CI & Build / Python tests (push) Successful in 1m56s
CI & Build / Build & push image (push) Successful in 22s
retrieval_telemetry gains rule_usage.by_source, the twin of usage.by_source: distinct rules each surface showed, how many an agent opened, and a ratio that is null on a bulk delivery. list_rules(with_usage=True, days=N) adds each rule's usage, windowed, and how many lessons are confirmed instances of it, so linked and unlinked rules can be compared through MCP. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -198,6 +198,47 @@ async def test_usage_for_rules_aggregates_per_rule(_dispose_engine):
|
||||
await s.commit()
|
||||
|
||||
|
||||
@pytest.mark.integration
|
||||
@pytest.mark.asyncio
|
||||
async def test_usage_for_rules_counts_only_the_window_it_is_given(_dispose_engine):
|
||||
"""Two windows have to be comparable, so an event before `since` is left
|
||||
out of every count — and without `since` it is counted."""
|
||||
from datetime import datetime, timedelta, timezone
|
||||
|
||||
from sqlalchemy import delete
|
||||
|
||||
from grimoire.models import async_session
|
||||
from grimoire.models.rule_usage import RuleUsageEvent
|
||||
|
||||
old = datetime.now(timezone.utc) - timedelta(days=30)
|
||||
async with async_session() as s:
|
||||
s.add_all([
|
||||
RuleUsageEvent(user_id=990022, rule_id=6011, event=SURFACED,
|
||||
source="write_path_rule", created_at=old),
|
||||
RuleUsageEvent(user_id=990022, rule_id=6011, event=PULLED,
|
||||
source="mcp_get_rule", created_at=old),
|
||||
RuleUsageEvent(user_id=990022, rule_id=6011, event=SURFACED,
|
||||
source="write_path_rule"),
|
||||
])
|
||||
await s.commit()
|
||||
try:
|
||||
since = datetime.now(timezone.utc) - timedelta(days=14)
|
||||
recent = (await rule_usage.usage_for_rules([6011], since=since))[6011]
|
||||
assert recent["surfaced_count"] == 1
|
||||
assert recent["pull_count"] == 0
|
||||
assert recent["last_pulled_at"] is None
|
||||
|
||||
everything = (await rule_usage.usage_for_rules([6011]))[6011]
|
||||
assert everything["surfaced_count"] == 2
|
||||
assert everything["pull_count"] == 1
|
||||
finally:
|
||||
async with async_session() as s:
|
||||
await s.execute(
|
||||
delete(RuleUsageEvent).where(RuleUsageEvent.user_id == 990022)
|
||||
)
|
||||
await s.commit()
|
||||
|
||||
|
||||
@pytest.mark.integration
|
||||
@pytest.mark.asyncio
|
||||
async def test_usage_for_rules_on_an_empty_id_list_asks_the_database_nothing(
|
||||
|
||||
Reference in New Issue
Block a user