REUSE-WP-0018 T01/T02/T04/T06: plan-check deterministic matching + State Hub bridge
Some checks failed
ci / validate-registry (push) Has been cancelled

T01: specs/PlanCheck.md design doc, plan-check-result.schema.json and
reuse-event.schema.json (the latter shared with WP-0019's reuse telemetry).

T02: reuse_surface/plan_check.py + 'reuse-surface plan-check' CLI command.
Deterministic token-Jaccard matching against registry/indexes/federated.yaml
(reuses overlaps.py's TOKEN_RE rather than a second scoring method), with
reuse/extend/new verdicts, markdown and --format json output, staleness
warning, and --record-outcome JSONL telemetry.

T04: reuse_surface/statehub_bridge.py bridges plan-check 'new' verdicts to
State Hub capability requests (--file-request) and surfaces open requests
with no matching capability (report gaps --check-capability-requests, opt-in
to stay offline-safe). Verified against the live local State Hub API;
status field (not catalog_entry_id presence) is the correct open/closed
signal, and the list endpoint needs a longer timeout than the health check
(~7s observed with 5 rows).

T06: docs (tools/README.md, RegistryFederation.md, SCOPE.md,
IntentScopeGapAnalysis.md priority 29) and an informational CI smoke step.

T03 (LLM rerank) not started -- llm-connect isn't running on this
workstation. T05 (ecosystem rollout) remains blocked: WP-0017 has drafted
entries for all 61 repos but they're still local-only pending its own T05
push/publish pass, so the federated index isn't yet worth rolling out
plan-check as ecosystem convention.

16 new tests, all mocked -- no network calls in the default test run.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-07 00:57:18 +02:00
parent 2a6818d4fe
commit e72966a658
15 changed files with 1179 additions and 29 deletions

View File

@@ -20,6 +20,16 @@ from reuse_surface.hub_sync import (
write_sources_manifest,
)
from reuse_surface.overlaps import find_overlaps
from reuse_surface.statehub_bridge import list_open_capability_requests
from reuse_surface.plan_check import (
format_plan_check_json,
format_plan_check_markdown,
load_query_from_intent,
load_query_from_workplan,
maybe_file_capability_request,
record_outcome,
run_plan_check,
)
from reuse_surface.reports import (
cohort_filters_from_args,
collect_gap_report,
@@ -578,16 +588,85 @@ def cmd_report_cohorts(args: argparse.Namespace) -> int:
return 0
def cmd_plan_check(args: argparse.Namespace) -> int:
if args.workplan and args.intent:
print("error: pass either a workplan file or --intent, not both", file=sys.stderr)
return 1
if args.workplan:
path = Path(args.workplan).resolve()
if not path.exists():
print(f"error: workplan not found: {path}", file=sys.stderr)
return 1
query = load_query_from_workplan(path)
elif args.intent:
query = load_query_from_intent(args.intent)
else:
print("error: provide a workplan file or --intent", file=sys.stderr)
return 1
result = run_plan_check(
query,
reuse_threshold=args.reuse_threshold,
extend_threshold=args.extend_threshold,
)
if args.record_outcome:
record_outcome(result, args.record_outcome, consumer_repo=args.consumer_repo)
filed = None
if args.file_request and result["verdict"] == "new":
filed = maybe_file_capability_request(
result,
requesting_domain=args.requesting_domain,
requesting_agent=args.consumer_repo,
)
if args.format == "json":
if filed is not None:
result["filed_capability_request"] = filed
print(format_plan_check_json(result))
else:
print(format_plan_check_markdown(result), end="")
if args.file_request and result["verdict"] == "new":
if filed:
print(f"\nFiled State Hub capability request: {filed.get('id')}")
else:
print("\nState Hub unreachable — capability request not filed.")
return 0
def cmd_report_gaps(args: argparse.Namespace) -> int:
roster_path = Path(args.roster).resolve() if args.roster else default_roster_path()
if not roster_path.exists():
print(f"error: roster not found: {roster_path}", file=sys.stderr)
return 1
report = collect_gap_report(roster_path)
if args.check_capability_requests:
open_requests = list_open_capability_requests()
report["open_capability_requests"] = (
[
{"id": r["id"], "title": r["title"], "requesting_domain": r.get("requesting_domain_slug")}
for r in open_requests
]
if open_requests is not None
else None
)
if args.format == "json":
print(format_gap_json(report))
else:
print(format_gap_markdown(report), end="")
if args.check_capability_requests:
requests_ = report["open_capability_requests"]
print("\n## Open State Hub capability requests (no matching federated capability)\n")
if requests_ is None:
print("_State Hub unreachable — skipped._\n")
elif not requests_:
print("- none\n")
else:
for r in requests_:
print(f"- `{r['id']}` ({r['requesting_domain']}): {r['title']}")
return 0
@@ -697,6 +776,44 @@ def main(argv: list[str] | None = None) -> int:
)
overlaps.set_defaults(func=cmd_overlaps)
plan_check = subparsers.add_parser(
"plan-check",
help="match a draft workplan or intent against the federated capability index",
)
plan_check.add_argument(
"workplan", nargs="?", help="path to a workplan file (frontmatter + body)"
)
plan_check.add_argument("--intent", help="free-text intent instead of a workplan file")
plan_check.add_argument(
"--format", choices=["markdown", "json"], default="markdown"
)
plan_check.add_argument(
"--reuse-threshold", type=float, default=0.45,
help="score at or above which the verdict is 'reuse'",
)
plan_check.add_argument(
"--extend-threshold", type=float, default=0.22,
help="score at or above which the verdict is 'extend'",
)
plan_check.add_argument(
"--record-outcome",
choices=["reused", "extended", "new", "skipped"],
help="append this outcome to registry/telemetry/plan-check-events.jsonl",
)
plan_check.add_argument(
"--consumer-repo", default="reuse-surface",
help="repo slug recorded with --record-outcome and --file-request",
)
plan_check.add_argument(
"--file-request", action="store_true",
help="on a 'new' verdict, file a State Hub capability request for the gap",
)
plan_check.add_argument(
"--requesting-domain", default="infotech",
help="domain slug recorded on a filed capability request",
)
plan_check.set_defaults(func=cmd_plan_check)
catalog = subparsers.add_parser(
"catalog", help="generate human-readable capability catalog"
)
@@ -808,6 +925,12 @@ def main(argv: list[str] | None = None) -> int:
choices=["markdown", "json"],
default="markdown",
)
gaps.add_argument(
"--check-capability-requests",
action="store_true",
help="also list open State Hub capability requests with no matching "
"federated capability (requires State Hub reachable at 127.0.0.1:8000)",
)
gaps.set_defaults(func=cmd_report_gaps)
stats = subparsers.add_parser("stats", help="registry maturity and federation stats")