session-memory: map signals to catalog recommendations via covers (WP-0010 follow-up)

Closes the gap where recurring_error suggestions showed generic 'Investigate'
instead of the curated recommendation. Added a covers[] field to SolutionPattern
(lowercase substrings a pattern's recommendation also applies to) + Catalog.find_for
(exact key first, then covers match against signal key+locus). Retro now resolves
recommendations through find_for. Tagged the read-before-edit pattern with
covers=['file has not been read','modified since read','file_not_read'] (v1.0.1).
Live: file-not-read suggestions across all repos now inherit 'Read the file before
Edit/Write'. 6 new tests; suite 158/158.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-07 21:09:44 +02:00
parent 0d05dfcc5d
commit e237dcc622
9 changed files with 143 additions and 35 deletions

View File

@@ -14,7 +14,6 @@ from dataclasses import asdict, dataclass
from datetime import datetime, timedelta, timezone
from typing import Optional
from ..curate.schema import SolutionPattern
from ..detect.cluster import cluster
from ..detect.quality import QualityConfig, filter_real
from ..detect.signals import extract_signals
@@ -48,10 +47,10 @@ class Suggestion:
pattern_key: str
def _recommendation(pattern_key: str, catalog) -> Optional[str]:
def _recommendation(pattern_key: str, locus: str, catalog) -> Optional[str]:
if catalog is None:
return None
sp = catalog.load(SolutionPattern.make_id(pattern_key))
sp = catalog.find_for(pattern_key, locus)
if sp and sp.resolutions:
return sp.resolutions[0].summary
return None
@@ -75,7 +74,7 @@ def weekly_retro(digests: list[dict], catalog=None, *, since: Optional[str] = No
for p in patterns:
if p.polarity != "problem":
continue # improvements come from problems
rec = (_recommendation(p.key, catalog)
rec = (_recommendation(p.key, p.locus, catalog)
or f"Investigate {p.signal_type.replace('_', ' ')} on {p.locus}")
priority = "high" if (p.cross_flavor or p.score >= _HIGH_SCORE) else "medium"
for repo in (p.repos or ["(unknown)"]):