REUSE-WP-0019-T04: reuse telemetry store and recording
Implements the hub side of the shared reuse-event schema (already drafted in WP-0018-T01, schemas/reuse-event.schema.json): a SQLite reuse_events table, POST /v1/reuse-events (token-auth), GET /v1/reuse-events?capability_id= (read-only). reuse_surface/plan_check.py: refactored record_outcome around a new shared post_or_fallback_reuse_event() helper -- tries the hub first, falls back to the local JSONL only on failure/unreachability, never both. New record_manual_reuse_event() backs a new CLI command, reuse-surface record-reuse, for retroactive facts recorded outside plan-check. Privacy/scope (repo slugs and capability ids only, no code, no secrets) is enforced structurally via the schema's additionalProperties: false, not just by convention. 21 new pytest cases, 145 total pass. Live-verified against a real running hub instance: POST/GET /v1/reuse-events directly, record-reuse and plan-check --record-outcome both posting successfully to the hub, and -- after actually killing the hub process -- confirmed the fallback path writes correctly to the local JSONL instead of erroring. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
parent
2fcc91f2aa
commit
d181043717
12 changed files with 562 additions and 32 deletions
|
|
@ -28,6 +28,7 @@ from reuse_surface.plan_check import (
|
|||
load_query_from_intent,
|
||||
load_query_from_workplan,
|
||||
maybe_file_capability_request,
|
||||
record_manual_reuse_event,
|
||||
record_outcome,
|
||||
run_plan_check,
|
||||
)
|
||||
|
|
@ -663,8 +664,9 @@ def cmd_plan_check(args: argparse.Namespace) -> int:
|
|||
llm_url=args.llm_url,
|
||||
)
|
||||
|
||||
recorded = None
|
||||
if args.record_outcome:
|
||||
record_outcome(result, args.record_outcome, consumer_repo=args.consumer_repo)
|
||||
recorded = record_outcome(result, args.record_outcome, consumer_repo=args.consumer_repo)
|
||||
|
||||
filed = None
|
||||
if args.file_request and result["verdict"] == "new":
|
||||
|
|
@ -677,6 +679,8 @@ def cmd_plan_check(args: argparse.Namespace) -> int:
|
|||
if args.format == "json":
|
||||
if filed is not None:
|
||||
result["filed_capability_request"] = filed
|
||||
if recorded is not None:
|
||||
result["recorded_reuse_event"] = recorded
|
||||
print(format_plan_check_json(result))
|
||||
else:
|
||||
print(format_plan_check_markdown(result), end="")
|
||||
|
|
@ -685,6 +689,32 @@ def cmd_plan_check(args: argparse.Namespace) -> int:
|
|||
print(f"\nFiled State Hub capability request: {filed.get('id')}")
|
||||
else:
|
||||
print("\nState Hub unreachable — capability request not filed.")
|
||||
if recorded is not None:
|
||||
if recorded["recorded_to"] == "hub":
|
||||
print("\nReuse event recorded to hub.")
|
||||
else:
|
||||
print("\nReuse hub unreachable — recorded to local JSONL fallback.")
|
||||
return 0
|
||||
|
||||
|
||||
def cmd_record_reuse(args: argparse.Namespace) -> int:
|
||||
try:
|
||||
recorded = record_manual_reuse_event(
|
||||
consumer_repo=args.consumer_repo,
|
||||
capability_id=args.capability_id,
|
||||
verdict=args.verdict,
|
||||
outcome=args.outcome,
|
||||
hub_url=args.hub_url,
|
||||
)
|
||||
except ValueError as exc:
|
||||
print(f"error: {exc}", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
if args.format == "json":
|
||||
print(json.dumps(recorded, indent=2, sort_keys=True))
|
||||
else:
|
||||
destination = "hub" if recorded["recorded_to"] == "hub" else f"local ({recorded['path']})"
|
||||
print(f"ok: recorded reuse event to {destination}")
|
||||
return 0
|
||||
|
||||
|
||||
|
|
@ -880,7 +910,8 @@ def main(argv: list[str] | None = None) -> int:
|
|||
plan_check.add_argument(
|
||||
"--record-outcome",
|
||||
choices=["reused", "extended", "new", "skipped"],
|
||||
help="append this outcome to registry/telemetry/plan-check-events.jsonl",
|
||||
help="record this outcome as a reuse event: POST /v1/reuse-events if the "
|
||||
"hub is reachable, else append to registry/telemetry/plan-check-events.jsonl",
|
||||
)
|
||||
plan_check.add_argument(
|
||||
"--consumer-repo", default="reuse-surface",
|
||||
|
|
@ -903,6 +934,26 @@ def main(argv: list[str] | None = None) -> int:
|
|||
)
|
||||
plan_check.set_defaults(func=cmd_plan_check)
|
||||
|
||||
record_reuse = subparsers.add_parser(
|
||||
"record-reuse",
|
||||
help="manually record a retroactive reuse fact (REUSE-WP-0019-T04)",
|
||||
)
|
||||
record_reuse.add_argument("--consumer-repo", required=True, help="repo slug that reused/extended/built new")
|
||||
record_reuse.add_argument(
|
||||
"--capability-id", help="capability id involved, if any (omit for a pure 'new' fact)"
|
||||
)
|
||||
record_reuse.add_argument(
|
||||
"--verdict", required=True, choices=["reuse", "extend", "new"],
|
||||
)
|
||||
record_reuse.add_argument(
|
||||
"--outcome", choices=["reused", "extended", "new", "skipped"],
|
||||
)
|
||||
record_reuse.add_argument(
|
||||
"--hub-url", help="hub base URL (or REUSE_SURFACE_URL)",
|
||||
)
|
||||
record_reuse.add_argument("--format", choices=["markdown", "json"], default="markdown")
|
||||
record_reuse.set_defaults(func=cmd_record_reuse)
|
||||
|
||||
catalog = subparsers.add_parser(
|
||||
"catalog", help="generate human-readable capability catalog"
|
||||
)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue