REUSE-WP-0019-T05: reuse telemetry aggregation into R-axis evidence
Some checks failed
CI Smoke / host-smoke (push) Successful in 1s
CI Smoke / container-smoke (push) Successful in 2s
ci / validate-registry (push) Has been cancelled
Build and Publish Container Image / build-and-push (push) Successful in 1m23s

reuse_surface/reports.py: collect_reuse_events() merges the hub's
GET /v1/reuse-events (if reachable) with this repo's local JSONL fallback,
deduped. collect_reuse_report() aggregates per-capability consumer counts,
outcome breakdown, and last-used. collect_reused_by_suggestions() proposes
evidence-gated relation_add patches -- only for capabilities this repo
owns, only for consumer repos not already listed -- reusing the existing
patches.py:apply_patches mechanism (relation_add already isn't in
SAFE_DETERMINISTIC_KINDS, so it was already never auto-applied by
maintain --auto).

New CLI: reuse-surface report reuse [--capability-id] [--format]
[--suggest-relations] [--apply]. --apply requires --suggest-relations and
is the only thing that writes -- nothing happens automatically from
telemetry alone.

schemas/capability.schema.yaml: added relations.reused_by as a new
repoSlugList type, distinct from the existing capability-id relations,
since reused-by targets are consumer repo slugs.

specs/CapabilityMaturityStandard.md Sec8.9: what observed-reuse evidence
counts toward R2->R3 (single corroborating consumer) vs R3->R4+ (multiple
independent consumers) and what it never substitutes for.

19 new pytest cases, 162 total pass. Live-verified with synthetic local
events against a real capability entry: --suggest-relations --apply
correctly wrote relations.reused_by via the real apply_patches path
(reverted after, since it was a smoke test).

Deliberately deferred: surfacing consumer counts in the catalog/graph --
graph.py's relation model is capability-to-capability edges, a different
namespace than repo-slug reused_by targets; catalog.py doesn't currently
parse full front matter per entry. Left for a follow-up.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
tegwick 2026-07-07 22:47:51 +02:00
parent e6e275ce79
commit bca7165e02
8 changed files with 576 additions and 13 deletions

View file

@ -5,12 +5,19 @@ import json
from pathlib import Path
import yaml
from reuse_surface.reports import (
cohort_filters_from_args,
collect_gap_report,
collect_reuse_events,
collect_reuse_report,
collect_reused_by_suggestions,
format_cohort_json,
format_cohort_markdown,
format_gap_markdown,
format_reuse_report_json,
format_reuse_report_markdown,
select_cohort,
)
@ -189,4 +196,244 @@ def test_cmd_report_cohorts_markdown(monkeypatch):
lambda: SAMPLE_INDEX,
)
exit_code = main(["report", "cohorts", "--planning-min", "D5"])
assert exit_code == 0
assert exit_code == 0
# --- T05: reuse telemetry aggregation ---
SAMPLE_REUSE_EVENTS = [
{
"ts": "2026-07-01T00:00:00Z",
"consumer_repo": "repo-a",
"capability_id": "capability.infotech.issue-tracking",
"verdict": "reuse",
"outcome": "reused",
"source": "plan-check",
},
{
"ts": "2026-07-02T00:00:00Z",
"consumer_repo": "repo-b",
"capability_id": "capability.infotech.issue-tracking",
"verdict": "reuse",
"outcome": "reused",
"source": "manual",
},
{
"ts": "2026-07-03T00:00:00Z",
"consumer_repo": "repo-a",
"capability_id": "capability.audit.event-retain",
"verdict": "extend",
"outcome": "extended",
"source": "plan-check",
},
]
def test_collect_reuse_report_aggregates_per_capability():
report = collect_reuse_report(SAMPLE_REUSE_EVENTS)
assert report["total_events"] == 3
by_id = {row["capability_id"]: row for row in report["capabilities"]}
assert by_id["capability.infotech.issue-tracking"]["consumer_count"] == 2
assert by_id["capability.infotech.issue-tracking"]["consumer_repos"] == ["repo-a", "repo-b"]
assert by_id["capability.infotech.issue-tracking"]["outcomes"] == {"reused": 2}
assert by_id["capability.infotech.issue-tracking"]["last_used"] == "2026-07-02T00:00:00Z"
assert by_id["capability.audit.event-retain"]["consumer_count"] == 1
def test_collect_reuse_report_filters_by_capability_id():
report = collect_reuse_report(SAMPLE_REUSE_EVENTS, capability_id="capability.audit.event-retain")
assert len(report["capabilities"]) == 1
assert report["capabilities"][0]["capability_id"] == "capability.audit.event-retain"
def test_collect_reuse_report_ignores_events_without_capability_id():
events = SAMPLE_REUSE_EVENTS + [
{"ts": "2026-07-04T00:00:00Z", "consumer_repo": "repo-c", "capability_id": None, "verdict": "new", "outcome": "new", "source": "manual"}
]
report = collect_reuse_report(events)
assert report["total_events"] == 4
assert len(report["capabilities"]) == 2
def test_format_reuse_report_markdown_empty():
output = format_reuse_report_markdown({"capabilities": [], "total_events": 0})
assert "No reuse events recorded yet" in output
def test_format_reuse_report_markdown_nonempty():
report = collect_reuse_report(SAMPLE_REUSE_EVENTS)
output = format_reuse_report_markdown(report)
assert "capability.infotech.issue-tracking" in output
assert "3" in output
def test_format_reuse_report_json_roundtrips():
report = collect_reuse_report(SAMPLE_REUSE_EVENTS)
payload = json.loads(format_reuse_report_json(report))
assert payload["total_events"] == 3
def test_collect_reuse_events_merges_hub_and_local(tmp_path, monkeypatch):
monkeypatch.setattr(
"reuse_surface.hub_client.hub_list_reuse_events",
lambda capability_id=None, base_url=None: (200, {"events": [SAMPLE_REUSE_EVENTS[0]]}),
)
telemetry_dir = tmp_path / "registry" / "telemetry"
telemetry_dir.mkdir(parents=True)
(telemetry_dir / "plan-check-events.jsonl").write_text(
json.dumps(SAMPLE_REUSE_EVENTS[1], sort_keys=True) + "\n", encoding="utf-8"
)
events = collect_reuse_events(repo_root=tmp_path)
assert len(events) == 2
def test_collect_reuse_events_dedupes_identical_facts(tmp_path, monkeypatch):
monkeypatch.setattr(
"reuse_surface.hub_client.hub_list_reuse_events",
lambda capability_id=None, base_url=None: (200, {"events": [SAMPLE_REUSE_EVENTS[0]]}),
)
telemetry_dir = tmp_path / "registry" / "telemetry"
telemetry_dir.mkdir(parents=True)
(telemetry_dir / "plan-check-events.jsonl").write_text(
json.dumps(SAMPLE_REUSE_EVENTS[0], sort_keys=True) + "\n", encoding="utf-8"
)
events = collect_reuse_events(repo_root=tmp_path)
assert len(events) == 1
def test_collect_reuse_events_degrades_gracefully_when_hub_unreachable(tmp_path, monkeypatch):
monkeypatch.delenv("REUSE_SURFACE_URL", raising=False)
events = collect_reuse_events(repo_root=tmp_path)
assert events == []
def _write_entry_with_relations(tmp_path: Path, cap_id: str, reused_by: list[str]) -> str:
rel = "registry/capabilities/capability-demo-sample.md"
front_matter = {
"id": cap_id,
"name": "Sample",
"summary": "Sample",
"owner": "demo",
"status": "draft",
"domain": "helix_forge",
"tags": ["demo"],
"maturity": {
"discovery": {"current": "D3", "target": "D5", "confidence": "low"},
"availability": {"current": "A3", "target": "A4", "confidence": "low"},
},
"external_evidence": {
"completeness": {"level": "C2", "confidence": "low"},
"reliability": {"level": "R2", "confidence": "low"},
},
"discovery": {"intent": "demo", "includes": [], "excludes": []},
"availability": {
"current_level": "A3",
"target_level": "A4",
"current_artifacts": [],
"consumption_modes": ["informational"],
},
"relations": {"depends_on": [], "supports": [], "related_to": [], "reused_by": reused_by},
"evidence": {"documentation": [], "tests": []},
"consumer_guidance": {
"recommended_for": [],
"not_recommended_for": [],
"known_limitations": [],
},
}
path = tmp_path / rel
path.parent.mkdir(parents=True, exist_ok=True)
path.write_text("---\n" + yaml.safe_dump(front_matter, sort_keys=False) + "---\n", encoding="utf-8")
return rel
def test_collect_reused_by_suggestions_skips_already_listed_consumers(tmp_path):
rel = _write_entry_with_relations(tmp_path, "capability.infotech.issue-tracking", reused_by=["repo-a"])
index_path = tmp_path / "registry" / "indexes" / "capabilities.yaml"
index_path.parent.mkdir(parents=True, exist_ok=True)
index_path.write_text(
yaml.safe_dump({
"version": 1, "domain": "helix_forge", "updated": "2026-07-01",
"capabilities": [{"id": "capability.infotech.issue-tracking", "path": rel, "vector": "D3/A3/C2/R2"}],
}),
encoding="utf-8",
)
report = collect_reuse_report(SAMPLE_REUSE_EVENTS)
suggestions = collect_reused_by_suggestions(report, repo_root=tmp_path)
# repo-a already listed -> only repo-b should be suggested
assert len(suggestions) == 1
assert suggestions[0]["value"] == {"type": "reused_by", "target": "repo-b"}
assert suggestions[0]["kind"] == "relation_add"
def test_collect_reused_by_suggestions_skips_capabilities_not_owned_locally(tmp_path):
# empty local index -- no capabilities owned here at all
index_path = tmp_path / "registry" / "indexes" / "capabilities.yaml"
index_path.parent.mkdir(parents=True, exist_ok=True)
index_path.write_text(
yaml.safe_dump({"version": 1, "domain": "helix_forge", "updated": "2026-07-01", "capabilities": []}),
encoding="utf-8",
)
report = collect_reuse_report(SAMPLE_REUSE_EVENTS)
suggestions = collect_reused_by_suggestions(report, repo_root=tmp_path)
assert suggestions == []
def test_collect_reused_by_suggestions_no_index_returns_empty(tmp_path):
report = collect_reuse_report(SAMPLE_REUSE_EVENTS)
suggestions = collect_reused_by_suggestions(report, repo_root=tmp_path)
assert suggestions == []
def test_cmd_report_reuse_markdown(monkeypatch):
from reuse_surface.cli import main
monkeypatch.setattr("reuse_surface.cli.collect_reuse_events", lambda hub_url=None: SAMPLE_REUSE_EVENTS)
exit_code = main(["report", "reuse"])
assert exit_code == 0
def test_cmd_report_reuse_json(monkeypatch, capsys):
from reuse_surface.cli import main
monkeypatch.setattr("reuse_surface.cli.collect_reuse_events", lambda hub_url=None: SAMPLE_REUSE_EVENTS)
exit_code = main(["report", "reuse", "--format", "json"])
assert exit_code == 0
payload = json.loads(capsys.readouterr().out)
assert payload["total_events"] == 3
def test_cmd_report_reuse_apply_without_suggest_relations_errors(monkeypatch):
from reuse_surface.cli import main
monkeypatch.setattr("reuse_surface.cli.collect_reuse_events", lambda hub_url=None: [])
exit_code = main(["report", "reuse", "--apply"])
assert exit_code == 1
def test_cmd_report_reuse_suggest_relations(monkeypatch, capsys):
from reuse_surface.cli import main
monkeypatch.setattr("reuse_surface.cli.collect_reuse_events", lambda hub_url=None: SAMPLE_REUSE_EVENTS)
monkeypatch.setattr(
"reuse_surface.cli.collect_reused_by_suggestions",
lambda report: [{"capability_id": "capability.infotech.issue-tracking", "kind": "relation_add", "detail": "observed reuse by repo-a", "value": {"type": "reused_by", "target": "repo-a"}}],
)
exit_code = main(["report", "reuse", "--suggest-relations"])
assert exit_code == 0
out = capsys.readouterr().out
assert "repo-a" in out
def test_cmd_report_reuse_apply_calls_apply_patches(monkeypatch):
from reuse_surface.cli import main
monkeypatch.setattr("reuse_surface.cli.collect_reuse_events", lambda hub_url=None: SAMPLE_REUSE_EVENTS)
suggestion = {"capability_id": "capability.infotech.issue-tracking", "kind": "relation_add", "detail": "x", "value": {"type": "reused_by", "target": "repo-a"}}
monkeypatch.setattr("reuse_surface.cli.collect_reused_by_suggestions", lambda report: [suggestion])
applied_calls = []
monkeypatch.setattr(
"reuse_surface.patches.apply_patches",
lambda repo_root, patches: applied_calls.append(patches) or ["applied one"],
)
exit_code = main(["report", "reuse", "--suggest-relations", "--apply"])
assert exit_code == 0
assert applied_calls == [[suggestion]]