feat(rulings): a command or edit touching an area's files shows its rulings, once per session (milestone 444 step 4, #4757)
CI & Build / Python lint (push) Successful in 3s
CI & Build / Plugin hooks (push) Successful in 12s
CI & Build / TypeScript typecheck (push) Successful in 54s
CI & Build / integration (push) Successful in 1m6s
CI & Build / Python tests (push) Failing after 1m22s
CI & Build / Build & push image (push) Skipped
CI & Build / Python lint (push) Successful in 3s
CI & Build / Plugin hooks (push) Successful in 12s
CI & Build / TypeScript typecheck (push) Successful in 54s
CI & Build / integration (push) Successful in 1m6s
CI & Build / Python tests (push) Failing after 1m22s
CI & Build / Build & push image (push) Skipped
A System's rulings (the Rulings section of its description) now reach the work by path, not by similarity. Both PreToolUse arms resolve the files a command or edit names to the Systems whose path_patterns cover them, and the first touch in a session shows each area's rulings in one line; a repeat is a one-line reference. A lookup, so no floor, no budget, no retrieval_logs row. - services/system_rulings: parse_rulings, command_paths (reads and writes, relative to the repo root from any cwd; flags, URLs, globs skipped), rulings_for_paths - /tool-rules takes root, cwd and seen_ruling_systems; /prior-art takes seen_ruling_systems; both return ruling_system_ids - hooks share <sid>.rulings.ids (cleared on compaction by the ledger naming convention); the Bash hook sends the repo root and cwd - system_usage_events (migration 0114): surfacings by source, pulls from get_system; carried by backup (v20) through the system map - writing-records: rulings also arrive when the area's files are touched Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,67 @@
|
||||
"""System usage telemetry — were an area's rulings read once shown?
|
||||
|
||||
The twin of `note_usage` and `rule_usage` for Systems (milestone 444). The
|
||||
rulings arm shows a System's rulings when a command or edit touches the
|
||||
System's files; a pull is somebody then opening the System (`get_system`). The
|
||||
ratio says whether delivering rulings by path earns its line.
|
||||
|
||||
Fire-and-forget like its siblings: telemetry never adds latency to, or
|
||||
breaks, the surface it observes, and failures report through the shared
|
||||
canary rather than vanishing.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
|
||||
from scribe.models import async_session
|
||||
from scribe.models.system_usage import PULLED, SURFACED, SystemUsageEvent
|
||||
from scribe.services.background import report_telemetry_failure, spawn
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
async def _insert_events(rows: list[dict]) -> None:
|
||||
"""Persist usage rows. Best-effort: failures degrade, visibly."""
|
||||
try:
|
||||
async with async_session() as session:
|
||||
session.add_all([SystemUsageEvent(**row) for row in rows])
|
||||
await session.commit()
|
||||
except Exception:
|
||||
await report_telemetry_failure("system_usage", "write")
|
||||
|
||||
|
||||
def _rows(user_id, system_ids, event: str, source: str, project_id) -> list[dict]:
|
||||
pid = int(project_id or 0) or None
|
||||
return [
|
||||
{"user_id": user_id, "system_id": int(sid), "event": event,
|
||||
"source": source, "project_id": pid}
|
||||
for sid in system_ids
|
||||
]
|
||||
|
||||
|
||||
def record_system_surfaced(
|
||||
*, user_id: int | None, system_ids: list[int], source: str,
|
||||
project_id: int | None = None,
|
||||
) -> None:
|
||||
"""Fire-and-forget: these Systems' rulings were shown in full. A repeat
|
||||
rendered as a short reference is not a surfacing and is not recorded."""
|
||||
try:
|
||||
rows = _rows(user_id, system_ids, SURFACED, source, project_id)
|
||||
except Exception:
|
||||
logger.debug("system usage payload build failed", exc_info=True)
|
||||
return
|
||||
if rows:
|
||||
spawn(_insert_events(rows), site="system_usage_write")
|
||||
|
||||
|
||||
def record_system_pulled(
|
||||
*, user_id: int | None, system_id: int, source: str,
|
||||
project_id: int | None = None,
|
||||
) -> None:
|
||||
"""Fire-and-forget: a System was opened in full."""
|
||||
try:
|
||||
rows = _rows(user_id, [system_id], PULLED, source, project_id)
|
||||
except Exception:
|
||||
logger.debug("system usage payload build failed", exc_info=True)
|
||||
return
|
||||
spawn(_insert_events(rows), site="system_usage_write")
|
||||
Reference in New Issue
Block a user