REUSE-WP-0019-T05: reuse telemetry aggregation into R-axis evidence
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:
parent
e6e275ce79
commit
bca7165e02
8 changed files with 576 additions and 13 deletions
|
|
@ -35,11 +35,16 @@ from reuse_surface.plan_check import (
|
|||
from reuse_surface.reports import (
|
||||
cohort_filters_from_args,
|
||||
collect_gap_report,
|
||||
collect_reuse_events,
|
||||
collect_reuse_report,
|
||||
collect_reused_by_suggestions,
|
||||
default_roster_path,
|
||||
format_cohort_json,
|
||||
format_cohort_markdown,
|
||||
format_gap_json,
|
||||
format_gap_markdown,
|
||||
format_reuse_report_json,
|
||||
format_reuse_report_markdown,
|
||||
select_cohort,
|
||||
)
|
||||
from reuse_surface.establish import (
|
||||
|
|
@ -753,6 +758,46 @@ def cmd_report_gaps(args: argparse.Namespace) -> int:
|
|||
return 0
|
||||
|
||||
|
||||
def cmd_report_reuse(args: argparse.Namespace) -> int:
|
||||
if args.apply and not args.suggest_relations:
|
||||
print("error: --apply requires --suggest-relations", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
events = collect_reuse_events(hub_url=args.hub_url)
|
||||
report = collect_reuse_report(events, capability_id=args.capability_id)
|
||||
|
||||
suggestions: list[dict[str, Any]] = []
|
||||
if args.suggest_relations:
|
||||
suggestions = collect_reused_by_suggestions(report)
|
||||
|
||||
applied: list[str] = []
|
||||
if args.apply and suggestions:
|
||||
from reuse_surface.patches import apply_patches
|
||||
from reuse_surface.registry import ROOT
|
||||
|
||||
applied = apply_patches(ROOT, suggestions)
|
||||
|
||||
if args.format == "json":
|
||||
payload = dict(report)
|
||||
if args.suggest_relations:
|
||||
payload["reused_by_suggestions"] = suggestions
|
||||
if args.apply:
|
||||
payload["applied"] = applied
|
||||
print(format_reuse_report_json(payload))
|
||||
else:
|
||||
print(format_reuse_report_markdown(report), end="")
|
||||
if args.suggest_relations:
|
||||
print(f"\n## relations.reused_by suggestions ({len(suggestions)})\n")
|
||||
if not suggestions:
|
||||
print("_None — all observed reuse already reflected, or no capabilities owned here._")
|
||||
else:
|
||||
for s in suggestions:
|
||||
print(f"- `{s['capability_id']}`: {s['detail']}")
|
||||
if args.apply:
|
||||
print(f"\nApplied {len(applied)} patch(es).")
|
||||
return 0
|
||||
|
||||
|
||||
def cmd_export(args: argparse.Namespace) -> int:
|
||||
index = load_index()
|
||||
bundle: dict[str, Any] = {
|
||||
|
|
@ -1073,6 +1118,27 @@ def main(argv: list[str] | None = None) -> int:
|
|||
)
|
||||
gaps.set_defaults(func=cmd_report_gaps)
|
||||
|
||||
reuse = report_sub.add_parser(
|
||||
"reuse",
|
||||
help="reuse telemetry aggregation: consumer counts, outcomes, last-used (REUSE-WP-0019-T05)",
|
||||
)
|
||||
reuse.add_argument("--capability-id", help="filter to one capability")
|
||||
reuse.add_argument("--hub-url", help="hub base URL (or REUSE_SURFACE_URL)")
|
||||
reuse.add_argument("--format", choices=["markdown", "json"], default="markdown")
|
||||
reuse.add_argument(
|
||||
"--suggest-relations",
|
||||
action="store_true",
|
||||
help="also list evidence-gated relations.reused_by suggestions for "
|
||||
"capabilities this repo owns",
|
||||
)
|
||||
reuse.add_argument(
|
||||
"--apply",
|
||||
action="store_true",
|
||||
help="apply --suggest-relations suggestions (requires --suggest-relations; "
|
||||
"never applies without this explicit flag)",
|
||||
)
|
||||
reuse.set_defaults(func=cmd_report_reuse)
|
||||
|
||||
stats = subparsers.add_parser("stats", help="registry maturity and federation stats")
|
||||
stats.add_argument("--path", help="repo root (default: cwd)")
|
||||
stats.add_argument(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue