Add weekly SkillOps curator report
This commit is contained in:
@@ -2,7 +2,7 @@ PYTHON ?= python3
|
||||
LOCAL_SKILL_INSTALL_DIR ?= $(HOME)/.agents/skills.disabled/yao-meta-skill
|
||||
ACTIVE_SKILL_INSTALL_DIR ?= $(HOME)/.agents/skills/yao-meta-skill
|
||||
|
||||
.PHONY: eval eval-suite route-scorecard route-confusion-check description-optimization judge-blind-eval description-optimization-check promotion-check python-compat-check architecture-maintainability-check yao-cli-check skill-overview-check skill-interpretation-check skill-report-metrics-check skill-report-charts-check html-rendering-check skill-ir-check compiler-check output-eval-check output-execution-check output-review-kit-check output-review-adjudication-check runtime-conformance-check runtime-permission-check trust-check skill-atlas-check registry-audit-check package-verify-check install-simulation-check upgrade-check review-viewer-check review-studio-check skill-os2-audit-check skill-os2-coverage-check world-class-evidence-check world-class-ledger-check world-class-intake-check world-class-preflight-check world-class-submission-review-check world-class-runbook-check world-class-claim-guard-check benchmark-reproducibility-check evidence-consistency-check feedback-check adaptation-safety-check skillops-opportunity-check daily-skillops-check adoption-drift-check telemetry-import-check telemetry-emit-check telemetry-hooks-check telemetry-native-host-check review-waivers-check review-annotations-check baseline-compare-check reference-scan-check github-benchmark-scan-check intent-confidence-check reference-synthesis-check output-risk-profile-check artifact-design-profile-check prompt-quality-profile-check system-model-check iteration-directions-check description-drift-history iteration-ledger results-panel regression-history context-reports portability-report portability-check failure-regression-check package-check package-failure-check security-boundary-check local-install-sync-check snapshot-check validate lint governance-check resource-boundary-check quality-check sync-local-install sync-active-install test ci-test clean
|
||||
.PHONY: eval eval-suite route-scorecard route-confusion-check description-optimization judge-blind-eval description-optimization-check promotion-check python-compat-check architecture-maintainability-check yao-cli-check skill-overview-check skill-interpretation-check skill-report-metrics-check skill-report-charts-check html-rendering-check skill-ir-check compiler-check output-eval-check output-execution-check output-review-kit-check output-review-adjudication-check runtime-conformance-check runtime-permission-check trust-check skill-atlas-check registry-audit-check package-verify-check install-simulation-check upgrade-check review-viewer-check review-studio-check skill-os2-audit-check skill-os2-coverage-check world-class-evidence-check world-class-ledger-check world-class-intake-check world-class-preflight-check world-class-submission-review-check world-class-runbook-check world-class-claim-guard-check benchmark-reproducibility-check evidence-consistency-check feedback-check adaptation-safety-check skillops-opportunity-check daily-skillops-check weekly-curator-check adoption-drift-check telemetry-import-check telemetry-emit-check telemetry-hooks-check telemetry-native-host-check review-waivers-check review-annotations-check baseline-compare-check reference-scan-check github-benchmark-scan-check intent-confidence-check reference-synthesis-check output-risk-profile-check artifact-design-profile-check prompt-quality-profile-check system-model-check iteration-directions-check description-drift-history iteration-ledger results-panel regression-history context-reports portability-report portability-check failure-regression-check package-check package-failure-check security-boundary-check local-install-sync-check snapshot-check validate lint governance-check resource-boundary-check quality-check sync-local-install sync-active-install test ci-test clean
|
||||
|
||||
eval:
|
||||
$(PYTHON) scripts/trigger_eval.py --description-file evals/improved_description.txt --cases evals/trigger_cases.json --baseline-description-file evals/baseline_description.txt
|
||||
@@ -146,6 +146,9 @@ skillops-opportunity-check:
|
||||
daily-skillops-check:
|
||||
$(PYTHON) tests/verify_daily_skillops.py
|
||||
|
||||
weekly-curator-check:
|
||||
$(PYTHON) tests/verify_weekly_curator.py
|
||||
|
||||
adoption-drift-check:
|
||||
$(PYTHON) tests/verify_adoption_drift.py
|
||||
|
||||
@@ -257,11 +260,11 @@ sync-local-install: package-check
|
||||
sync-active-install: package-check
|
||||
$(PYTHON) scripts/sync_local_install.py --install-dir "$(ACTIVE_SKILL_INSTALL_DIR)"
|
||||
|
||||
test: eval eval-suite route-scorecard route-confusion-check description-optimization description-optimization-check promotion-check python-compat-check architecture-maintainability-check yao-cli-check skill-overview-check skill-interpretation-check skill-report-metrics-check skill-report-charts-check html-rendering-check skill-ir-check compiler-check output-eval-check output-execution-check output-review-adjudication-check runtime-conformance-check runtime-permission-check trust-check skill-atlas-check registry-audit-check package-verify-check install-simulation-check upgrade-check review-viewer-check review-studio-check skill-os2-audit-check skill-os2-coverage-check world-class-evidence-check world-class-ledger-check world-class-intake-check world-class-preflight-check world-class-submission-review-check world-class-runbook-check world-class-claim-guard-check benchmark-reproducibility-check evidence-consistency-check feedback-check adaptation-safety-check skillops-opportunity-check daily-skillops-check adoption-drift-check telemetry-import-check telemetry-emit-check telemetry-hooks-check telemetry-native-host-check review-waivers-check review-annotations-check baseline-compare-check reference-scan-check github-benchmark-scan-check intent-confidence-check reference-synthesis-check output-risk-profile-check artifact-design-profile-check prompt-quality-profile-check system-model-check iteration-directions-check description-drift-history iteration-ledger regression-history context-reports portability-report portability-check failure-regression-check package-check package-failure-check security-boundary-check local-install-sync-check snapshot-check validate lint governance-check resource-boundary-check quality-check
|
||||
test: eval eval-suite route-scorecard route-confusion-check description-optimization description-optimization-check promotion-check python-compat-check architecture-maintainability-check yao-cli-check skill-overview-check skill-interpretation-check skill-report-metrics-check skill-report-charts-check html-rendering-check skill-ir-check compiler-check output-eval-check output-execution-check output-review-adjudication-check runtime-conformance-check runtime-permission-check trust-check skill-atlas-check registry-audit-check package-verify-check install-simulation-check upgrade-check review-viewer-check review-studio-check skill-os2-audit-check skill-os2-coverage-check world-class-evidence-check world-class-ledger-check world-class-intake-check world-class-preflight-check world-class-submission-review-check world-class-runbook-check world-class-claim-guard-check benchmark-reproducibility-check evidence-consistency-check feedback-check adaptation-safety-check skillops-opportunity-check daily-skillops-check weekly-curator-check adoption-drift-check telemetry-import-check telemetry-emit-check telemetry-hooks-check telemetry-native-host-check review-waivers-check review-annotations-check baseline-compare-check reference-scan-check github-benchmark-scan-check intent-confidence-check reference-synthesis-check output-risk-profile-check artifact-design-profile-check prompt-quality-profile-check system-model-check iteration-directions-check description-drift-history iteration-ledger regression-history context-reports portability-report portability-check failure-regression-check package-check package-failure-check security-boundary-check local-install-sync-check snapshot-check validate lint governance-check resource-boundary-check quality-check
|
||||
|
||||
ci-test:
|
||||
$(PYTHON) scripts/ci_test.py
|
||||
|
||||
clean:
|
||||
rm -rf dist tests/tmp tests/tmp_snapshot tests/tmp_cli tests/tmp_python_compat tests/tmp_architecture_maintainability tests/tmp_skill_overview tests/tmp_skill_interpretation tests/tmp_skill_report_metrics tests/tmp_skill_report_charts tests/tmp_skill_ir tests/tmp_compile_skill tests/tmp_output_eval tests/tmp_output_execution tests/tmp_output_review_adjudication tests/tmp_conformance tests/tmp_runtime_permission tests/tmp_trust tests/tmp_skill_atlas tests/tmp_registry tests/tmp_package_verification tests/tmp_install_simulation tests/tmp_upgrade_check tests/tmp_reference_scan tests/tmp_iteration_directions tests/tmp_review_viewer tests/tmp_review_studio tests/tmp_skill_os2_audit tests/tmp_skill_os2_coverage tests/tmp_world_class_evidence tests/tmp_world_class_evidence_ledger tests/tmp_world_class_evidence_intake tests/tmp_world_class_submission_review tests/tmp_world_class_operator_runbook tests/tmp_world_class_claim_guard tests/tmp_benchmark_reproducibility tests/tmp_evidence_consistency tests/tmp_feedback tests/tmp_daily_skillops tests/tmp_adoption_drift tests/tmp_telemetry_import tests/tmp_telemetry_emit tests/tmp_telemetry_hooks tests/tmp_telemetry_native_host tests/tmp_review_waivers tests/tmp_review_annotations tests/tmp_github_benchmark_scan tests/tmp_intent_confidence tests/tmp_reference_synthesis tests/tmp_output_risk_profile tests/tmp_artifact_design_profile tests/tmp_prompt_quality_profile tests/tmp_system_model tests/tmp_security tests/tmp_baseline_compare.json tests/tmp_baseline_compare.md
|
||||
rm -rf dist tests/tmp tests/tmp_snapshot tests/tmp_cli tests/tmp_python_compat tests/tmp_architecture_maintainability tests/tmp_skill_overview tests/tmp_skill_interpretation tests/tmp_skill_report_metrics tests/tmp_skill_report_charts tests/tmp_skill_ir tests/tmp_compile_skill tests/tmp_output_eval tests/tmp_output_execution tests/tmp_output_review_adjudication tests/tmp_conformance tests/tmp_runtime_permission tests/tmp_trust tests/tmp_skill_atlas tests/tmp_registry tests/tmp_package_verification tests/tmp_install_simulation tests/tmp_upgrade_check tests/tmp_reference_scan tests/tmp_iteration_directions tests/tmp_review_viewer tests/tmp_review_studio tests/tmp_skill_os2_audit tests/tmp_skill_os2_coverage tests/tmp_world_class_evidence tests/tmp_world_class_evidence_ledger tests/tmp_world_class_evidence_intake tests/tmp_world_class_submission_review tests/tmp_world_class_operator_runbook tests/tmp_world_class_claim_guard tests/tmp_benchmark_reproducibility tests/tmp_evidence_consistency tests/tmp_feedback tests/tmp_daily_skillops tests/tmp_weekly_curator tests/tmp_adoption_drift tests/tmp_telemetry_import tests/tmp_telemetry_emit tests/tmp_telemetry_hooks tests/tmp_telemetry_native_host tests/tmp_review_waivers tests/tmp_review_annotations tests/tmp_github_benchmark_scan tests/tmp_intent_confidence tests/tmp_reference_synthesis tests/tmp_output_risk_profile tests/tmp_artifact_design_profile tests/tmp_prompt_quality_profile tests/tmp_system_model tests/tmp_security tests/tmp_baseline_compare.json tests/tmp_baseline_compare.md
|
||||
find . -type d -name __pycache__ -prune -exec rm -rf {} +
|
||||
|
||||
@@ -46,6 +46,7 @@ It turns rough workflows, transcripts, prompts, notes, and runbooks into reusabl
|
||||
- a local-first metadata-only adoption and drift report that turns real usage signals into next iteration candidates, with optional `yao.py` CLI run capture, external client event emit hooks, hook recipes, and JSONL import that record command names and outcomes without arguments or raw content
|
||||
- an explicit-source adaptive proposal loop that summarizes redacted repeated user preferences and generates approval-gated adaptation proposals without scanning private logs or writing source files
|
||||
- a SkillOps opportunity scorer and decision policy that ranks redacted repeated signals, maps them to report-only, AGENTS update, existing-skill patch, or eval-addition actions, and keeps every durable write approval-gated
|
||||
- a weekly SkillOps curator report that aggregates daily opportunities, Skill Atlas portfolio signals, release lock state, and world-class evidence gaps into a proposal-only maintenance queue
|
||||
- a Browser/Chrome Native Messaging telemetry host that can receive length-prefixed metadata-only client events and generate a local launcher plus manifest without storing raw content
|
||||
- a Skill Atlas drift layer that reads aggregate adoption reports and surfaces portfolio-level drift signals without packaging raw telemetry logs
|
||||
- a baseline compare report for with-skill vs baseline review
|
||||
@@ -126,6 +127,7 @@ python3 scripts/yao.py feedback my-skill --note "Tighten exclusions before addin
|
||||
python3 scripts/yao.py adapt-scan my-skill --source ./curated-user-signals.jsonl
|
||||
python3 scripts/yao.py adapt-propose my-skill
|
||||
python3 scripts/yao.py daily-skillops my-skill --source ./curated-user-signals.jsonl
|
||||
python3 scripts/yao.py weekly-curator my-skill
|
||||
python3 scripts/yao.py adoption-drift my-skill --record-event skill_activation --activation-type explicit --outcome accepted
|
||||
YAO_CLI_TELEMETRY=1 python3 scripts/yao.py validate my-skill
|
||||
python3 scripts/yao.py telemetry-emit my-skill --event skill_activation --activation-type explicit --outcome accepted --command browser-extension
|
||||
@@ -434,7 +436,7 @@ Utility scripts that make the meta-skill operational:
|
||||
- `run_description_optimization_suite.py`: runs description optimization across the root skill and governed examples, then writes reusable reports and optional drift snapshots with calibration and family summaries
|
||||
- `promotion_checker.py`: applies promotion policy to current description candidates, writes promotion decisions, builds candidate registries, and emits iteration bundles with review stubs
|
||||
- `create_iteration_snapshot.py`: freezes the current promotion decision into a versioned release snapshot with review, route, and context evidence
|
||||
- `yao.py`: unified authoring CLI that exposes init, validate, optimize-description, promote-check, python-compat, review, release-snapshot, workspace-flow, report, skill-report, skill-interpretation, skill-ir, compile-skill, output-exec, output-review, skill-os2-audit, skill-os2-coverage, world-class-evidence, world-class-ledger, world-class-intake, world-class-preflight, world-class-submission-kit, world-class-submission-review, world-class-runbook, world-class-claim-guard, benchmark-reproducibility, evidence-consistency, adapt-scan, adapt-propose, adapt-apply, daily-skillops, telemetry-emit, telemetry-hooks, telemetry-import, package, registry-audit, package-verify, install-simulate, upgrade-check, review-waivers, and test as one entrypoint
|
||||
- `yao.py`: unified authoring CLI that exposes init, validate, optimize-description, promote-check, python-compat, review, release-snapshot, workspace-flow, report, skill-report, skill-interpretation, skill-ir, compile-skill, output-exec, output-review, skill-os2-audit, skill-os2-coverage, world-class-evidence, world-class-ledger, world-class-intake, world-class-preflight, world-class-submission-kit, world-class-submission-review, world-class-runbook, world-class-claim-guard, benchmark-reproducibility, evidence-consistency, adapt-scan, adapt-propose, adapt-apply, daily-skillops, weekly-curator, telemetry-emit, telemetry-hooks, telemetry-import, package, registry-audit, package-verify, install-simulate, upgrade-check, review-waivers, and test as one entrypoint
|
||||
- `render_description_drift_history.py`: turns description-optimization snapshots into a readable drift-history report
|
||||
- `build_confusion_matrix.py`: scores route confusion across tracked sibling skills and `no_route` cases, then writes a route scorecard and optional milestone snapshot
|
||||
- `render_iteration_ledger.py`: compresses regression milestones, description optimization drift, and route scorecards into one iteration-facing ledger
|
||||
@@ -446,6 +448,7 @@ Utility scripts that make the meta-skill operational:
|
||||
- `render_skill_os2_audit.py`: renders a requirement-by-requirement Skill OS 2.0 audit that separates landed local evidence from human-required and external-required gaps
|
||||
- `render_skill_os2_coverage.py`: maps the Skill OS 2.0 upgrade blueprint to local artifacts, commands, tests, and remaining evidence boundaries
|
||||
- `render_daily_skillops_report.py`: renders an explicit-source Daily SkillOps operations report that summarizes redacted user patterns, proposal-only adaptations, approval state, release evidence, and world-class evidence gaps without scanning private logs or applying patches
|
||||
- `render_weekly_curator_report.py`: renders a weekly SkillOps curator report from generated daily reports, Skill Atlas, benchmark lock, evidence consistency, and world-class ledger state without scanning private logs or applying patches
|
||||
- `skillops_opportunity.py`: scores redacted SkillOps opportunities and maps them to approval-gated action types such as report-only, AGENTS update, existing-skill patch, or eval addition
|
||||
- `render_world_class_evidence_plan.py`: renders executable evidence tasks for remaining world-class gaps without treating planned external work as completed evidence
|
||||
- `render_world_class_evidence_ledger.py`: renders a machine-checkable ledger for current world-class evidence acceptance, anti-overclaim guards, provenance requirements, and privacy contracts
|
||||
|
||||
@@ -69,6 +69,7 @@ DEFAULT_TARGETS = [
|
||||
"adaptation-safety-check",
|
||||
"skillops-opportunity-check",
|
||||
"daily-skillops-check",
|
||||
"weekly-curator-check",
|
||||
"adoption-drift-check",
|
||||
"telemetry-import-check",
|
||||
"telemetry-emit-check",
|
||||
|
||||
@@ -73,6 +73,24 @@ def latest_daily_skillops_paths(skill_dir: Path) -> list[str]:
|
||||
return [*base_paths, rel_path(latest_json, skill_dir), rel_path(latest_md, skill_dir)]
|
||||
|
||||
|
||||
def latest_weekly_curator_paths(skill_dir: Path) -> list[str]:
|
||||
base_paths = [
|
||||
"scripts/render_weekly_curator_report.py",
|
||||
"tests/verify_weekly_curator.py",
|
||||
]
|
||||
weekly_dir = skill_dir / "reports" / "skillops" / "weekly"
|
||||
weekly_json_reports = sorted(weekly_dir.glob("*.json")) if weekly_dir.exists() else []
|
||||
if not weekly_json_reports:
|
||||
return [
|
||||
*base_paths,
|
||||
"reports/skillops/weekly/YYYY-WNN.json",
|
||||
"reports/skillops/weekly/YYYY-WNN.md",
|
||||
]
|
||||
latest_json = weekly_json_reports[-1]
|
||||
latest_md = latest_json.with_suffix(".md")
|
||||
return [*base_paths, rel_path(latest_json, skill_dir), rel_path(latest_md, skill_dir)]
|
||||
|
||||
|
||||
def condition_status(condition: bool, evidence_items: list[dict[str, Any]]) -> str:
|
||||
if not all_exist(evidence_items):
|
||||
return "missing"
|
||||
@@ -425,6 +443,26 @@ def build_coverage(skill_dir: Path, generated_at: str) -> dict[str, Any]:
|
||||
skill_dir=skill_dir,
|
||||
)
|
||||
)
|
||||
weekly_curator_paths = latest_weekly_curator_paths(skill_dir)
|
||||
weekly_curator_ready = paths_exist(skill_dir, weekly_curator_paths)
|
||||
weekly_curator_status = "covered" if weekly_curator_ready else "partial"
|
||||
extension_tracks.append(
|
||||
build_extension_track(
|
||||
key="weekly-curator-report",
|
||||
label="Weekly Curator Report",
|
||||
status=weekly_curator_status,
|
||||
objective="Weekly curator layer aggregates Daily SkillOps opportunities, Skill Atlas portfolio signals, release locks, and world-class evidence gaps into a maintenance queue.",
|
||||
current=(
|
||||
"Weekly curator report is CLI-backed, proposal-only, and backed by committed weekly JSON/Markdown evidence."
|
||||
if weekly_curator_ready
|
||||
else "Daily SkillOps and Skill Atlas exist, but weekly curator aggregation is not fully wired into scripts, tests, and evidence artifacts."
|
||||
),
|
||||
target="Generate reports/skillops/weekly/YYYY-WNN.* without private log scanning, source writes, auto-patching, or world-class overclaiming.",
|
||||
artifact_paths=weekly_curator_paths,
|
||||
next_action="Use weekly curator output as the Skill Librarian maintenance queue before approving any durable skill-library changes.",
|
||||
skill_dir=skill_dir,
|
||||
)
|
||||
)
|
||||
extension_counts: dict[str, int] = {}
|
||||
for item in extension_tracks:
|
||||
extension_counts[item["status"]] = extension_counts.get(item["status"], 0) + 1
|
||||
|
||||
@@ -0,0 +1,433 @@
|
||||
#!/usr/bin/env python3
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import json
|
||||
from collections import Counter
|
||||
from datetime import date, datetime, timezone
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
|
||||
SCRIPT_INTERFACE = "cli"
|
||||
SCRIPT_INTERFACE_REASON = "Renders a weekly SkillOps curator report from generated reports without scanning private logs or writing source files."
|
||||
|
||||
SUMMARY_FIELDS = [
|
||||
"decision",
|
||||
"week_id",
|
||||
"daily_report_count",
|
||||
"opportunity_count",
|
||||
"unique_opportunity_count",
|
||||
"ready_for_approval_review_count",
|
||||
"proposal_review_count",
|
||||
"observe_more_evidence_count",
|
||||
"report_only_count",
|
||||
"top_score",
|
||||
"skill_count",
|
||||
"actionable_portfolio_issue_count",
|
||||
"release_lock_ready",
|
||||
"evidence_consistency_ok",
|
||||
"public_world_class_ready",
|
||||
"world_class_pending_count",
|
||||
"writes_source_files",
|
||||
"auto_patch_enabled",
|
||||
"failure_count",
|
||||
]
|
||||
|
||||
|
||||
def utc_now() -> str:
|
||||
return datetime.now(timezone.utc).replace(microsecond=0).isoformat().replace("+00:00", "Z")
|
||||
|
||||
|
||||
def parse_date(value: str) -> date:
|
||||
candidate = value[:10] if len(value) >= 10 else value
|
||||
try:
|
||||
return date.fromisoformat(candidate)
|
||||
except ValueError:
|
||||
return date.today()
|
||||
|
||||
|
||||
def week_id(generated_at: str) -> str:
|
||||
iso = parse_date(generated_at).isocalendar()
|
||||
return f"{iso.year}-W{iso.week:02d}"
|
||||
|
||||
|
||||
def display_path(path: Path, root: Path) -> str:
|
||||
try:
|
||||
return str(path.resolve().relative_to(root.resolve()))
|
||||
except ValueError:
|
||||
return f"[external-explicit-source]/{path.name}"
|
||||
|
||||
|
||||
def resolve_output(skill_dir: Path, value: str) -> Path:
|
||||
path = Path(value)
|
||||
return path if path.is_absolute() else skill_dir / path
|
||||
|
||||
|
||||
def load_json(path: Path) -> dict[str, Any]:
|
||||
if not path.exists():
|
||||
return {}
|
||||
try:
|
||||
payload = json.loads(path.read_text(encoding="utf-8"))
|
||||
except json.JSONDecodeError:
|
||||
return {}
|
||||
return payload if isinstance(payload, dict) else {}
|
||||
|
||||
|
||||
def write_json(path: Path, payload: dict[str, Any]) -> None:
|
||||
path.parent.mkdir(parents=True, exist_ok=True)
|
||||
path.write_text(json.dumps(payload, ensure_ascii=False, indent=2) + "\n", encoding="utf-8")
|
||||
|
||||
|
||||
def write_text(path: Path, text: str) -> None:
|
||||
path.parent.mkdir(parents=True, exist_ok=True)
|
||||
path.write_text(text, encoding="utf-8")
|
||||
|
||||
|
||||
def default_weekly_path(skill_dir: Path, generated_at: str, suffix: str) -> Path:
|
||||
return skill_dir / "reports" / "skillops" / "weekly" / f"{week_id(generated_at)}.{suffix}"
|
||||
|
||||
|
||||
def daily_report_paths(skill_dir: Path, explicit_paths: list[Path]) -> list[Path]:
|
||||
if explicit_paths:
|
||||
return [path if path.is_absolute() else skill_dir / path for path in explicit_paths]
|
||||
daily_dir = skill_dir / "reports" / "skillops" / "daily"
|
||||
if not daily_dir.exists():
|
||||
return []
|
||||
return sorted(daily_dir.glob("*.json"))
|
||||
|
||||
|
||||
def _as_int(value: Any, default: int = 0) -> int:
|
||||
if isinstance(value, bool):
|
||||
return default
|
||||
try:
|
||||
return int(value)
|
||||
except (TypeError, ValueError):
|
||||
return default
|
||||
|
||||
|
||||
def _dedupe_opportunities(daily_reports: list[dict[str, Any]]) -> list[dict[str, Any]]:
|
||||
by_id: dict[str, dict[str, Any]] = {}
|
||||
for report in daily_reports:
|
||||
report_date = str(report.get("generated_at") or "")[:10]
|
||||
for item in report.get("opportunities", []):
|
||||
if not isinstance(item, dict):
|
||||
continue
|
||||
opportunity_id = str(item.get("opportunity_id") or "")
|
||||
if not opportunity_id:
|
||||
continue
|
||||
current = {**item, "daily_report_date": report_date}
|
||||
existing = by_id.get(opportunity_id)
|
||||
if existing is None or _as_int(current.get("score")) > _as_int(existing.get("score")):
|
||||
by_id[opportunity_id] = current
|
||||
return sorted(by_id.values(), key=lambda item: (-_as_int(item.get("score")), str(item.get("opportunity_id"))))
|
||||
|
||||
|
||||
def _counter(items: list[dict[str, Any]], key: str) -> dict[str, int]:
|
||||
values = Counter(str(item.get(key) or "") for item in items)
|
||||
values.pop("", None)
|
||||
return dict(sorted(values.items()))
|
||||
|
||||
|
||||
def _portfolio_issue_count(atlas_summary: dict[str, Any]) -> int:
|
||||
keys = [
|
||||
"actionable_route_collision_count",
|
||||
"actionable_owner_gap_count",
|
||||
"actionable_stale_count",
|
||||
"actionable_drift_signal_count",
|
||||
"no_route_opportunity_count",
|
||||
]
|
||||
return sum(_as_int(atlas_summary.get(key)) for key in keys)
|
||||
|
||||
|
||||
def build_actions(summary: dict[str, Any], opportunities: list[dict[str, Any]], atlas_summary: dict[str, Any]) -> list[dict[str, str]]:
|
||||
actions: list[dict[str, str]] = []
|
||||
if summary["ready_for_approval_review_count"]:
|
||||
actions.append(
|
||||
{
|
||||
"key": "review-ready-opportunities",
|
||||
"priority": "high",
|
||||
"action": "Review the top ready-for-approval SkillOps opportunities before preparing any approval ledger entry.",
|
||||
}
|
||||
)
|
||||
elif opportunities:
|
||||
actions.append(
|
||||
{
|
||||
"key": "review-proposal-queue",
|
||||
"priority": "medium",
|
||||
"action": "Review proposal-level SkillOps opportunities and keep low-evidence items in observation.",
|
||||
}
|
||||
)
|
||||
if summary["actionable_portfolio_issue_count"]:
|
||||
actions.append(
|
||||
{
|
||||
"key": "triage-skill-library",
|
||||
"priority": "high",
|
||||
"action": "Triage actionable route collisions, owner gaps, stale skills, drift signals, or no-route opportunities from Skill Atlas.",
|
||||
}
|
||||
)
|
||||
if summary["world_class_pending_count"]:
|
||||
actions.append(
|
||||
{
|
||||
"key": "close-world-class-evidence",
|
||||
"priority": "high",
|
||||
"action": "Collect accepted external or human evidence for pending world-class ledger entries before public claims.",
|
||||
}
|
||||
)
|
||||
if summary["evidence_consistency_ok"] is not True:
|
||||
actions.append(
|
||||
{
|
||||
"key": "refresh-evidence-consistency",
|
||||
"priority": "high",
|
||||
"action": "Regenerate evidence consistency before using this curator report for release decisions.",
|
||||
}
|
||||
)
|
||||
if not atlas_summary:
|
||||
actions.append(
|
||||
{
|
||||
"key": "refresh-skill-atlas",
|
||||
"priority": "medium",
|
||||
"action": "Generate Skill Atlas so weekly curation can see portfolio-level drift and stale-skill signals.",
|
||||
}
|
||||
)
|
||||
if not actions:
|
||||
actions.append({"key": "monitor", "priority": "low", "action": "No curation action required beyond routine monitoring."})
|
||||
return actions
|
||||
|
||||
|
||||
def build_report(skill_dir: Path, generated_at: str, daily_json: list[Path] | None = None) -> dict[str, Any]:
|
||||
skill_dir = skill_dir.resolve()
|
||||
reports_dir = skill_dir / "reports"
|
||||
failures: list[str] = []
|
||||
|
||||
daily_paths = daily_report_paths(skill_dir, daily_json or [])
|
||||
daily_reports = []
|
||||
for path in daily_paths:
|
||||
payload = load_json(path)
|
||||
if payload.get("ok") is True:
|
||||
daily_reports.append(payload)
|
||||
else:
|
||||
failures.append(f"Daily SkillOps report is missing or invalid: {display_path(path, skill_dir)}")
|
||||
|
||||
opportunities = _dedupe_opportunities(daily_reports)
|
||||
decision_counts = _counter(opportunities, "decision")
|
||||
action_counts = _counter(opportunities, "action_type")
|
||||
risk_counts = _counter(opportunities, "risk_level")
|
||||
|
||||
atlas = load_json(reports_dir / "skill_atlas.json")
|
||||
atlas_summary = atlas.get("summary", {}) if isinstance(atlas.get("summary"), dict) else {}
|
||||
benchmark = load_json(reports_dir / "benchmark_reproducibility.json")
|
||||
benchmark_summary = benchmark.get("summary", {}) if isinstance(benchmark.get("summary"), dict) else {}
|
||||
consistency = load_json(reports_dir / "evidence_consistency.json")
|
||||
ledger = load_json(reports_dir / "world_class_evidence_ledger.json")
|
||||
ledger_summary = ledger.get("summary", {}) if isinstance(ledger.get("summary"), dict) else {}
|
||||
|
||||
portfolio_issue_count = _portfolio_issue_count(atlas_summary)
|
||||
failure_count = len(failures)
|
||||
summary = {
|
||||
"decision": "blocked"
|
||||
if failure_count
|
||||
else "curator-review"
|
||||
if opportunities or portfolio_issue_count or _as_int(ledger_summary.get("pending_count"))
|
||||
else "monitor",
|
||||
"week_id": week_id(generated_at),
|
||||
"daily_report_count": len(daily_reports),
|
||||
"opportunity_count": sum(_as_int(report.get("opportunity_summary", {}).get("opportunity_count")) for report in daily_reports),
|
||||
"unique_opportunity_count": len(opportunities),
|
||||
"ready_for_approval_review_count": decision_counts.get("ready_for_approval_review", 0),
|
||||
"proposal_review_count": decision_counts.get("proposal_review", 0),
|
||||
"observe_more_evidence_count": decision_counts.get("observe_more_evidence", 0),
|
||||
"report_only_count": decision_counts.get("report_only", 0),
|
||||
"top_score": _as_int(opportunities[0].get("score")) if opportunities else 0,
|
||||
"skill_count": _as_int(atlas_summary.get("skill_count")),
|
||||
"actionable_portfolio_issue_count": portfolio_issue_count,
|
||||
"release_lock_ready": benchmark_summary.get("release_lock_ready") is True,
|
||||
"evidence_consistency_ok": consistency.get("ok") is True,
|
||||
"public_world_class_ready": ledger_summary.get("ready_to_claim_world_class") is True,
|
||||
"world_class_pending_count": _as_int(ledger_summary.get("pending_count")),
|
||||
"writes_source_files": False,
|
||||
"auto_patch_enabled": False,
|
||||
"failure_count": failure_count,
|
||||
}
|
||||
actions = build_actions(summary, opportunities, atlas_summary)
|
||||
curator_contract = {
|
||||
"schema_version": "1.0",
|
||||
"contract": "weekly-skillops-curator-report",
|
||||
"cadence": "weekly",
|
||||
"source_of_truth": [
|
||||
"reports/skillops/daily/*.json",
|
||||
"reports/skill_atlas.json",
|
||||
"reports/benchmark_reproducibility.json",
|
||||
"reports/evidence_consistency.json",
|
||||
"reports/world_class_evidence_ledger.json",
|
||||
],
|
||||
"raw_content_stored": False,
|
||||
"redacted_or_generated_evidence_only": True,
|
||||
"proposal_only": True,
|
||||
"writes_source_files": False,
|
||||
"auto_patch_enabled": False,
|
||||
"approval_required_for_writes": True,
|
||||
"counts_as_world_class_evidence": False,
|
||||
}
|
||||
report = {
|
||||
"schema_version": "1.0",
|
||||
"ok": failure_count == 0,
|
||||
"generated_at": generated_at,
|
||||
"skill_dir": display_path(skill_dir, skill_dir),
|
||||
**{key: summary[key] for key in SUMMARY_FIELDS},
|
||||
"summary": summary,
|
||||
"curator_contract": curator_contract,
|
||||
"report_contract": {
|
||||
"schema_version": "1.0",
|
||||
"contract": "weekly-skillops-curator-report",
|
||||
"top_level_mirrors_summary": True,
|
||||
"summary_fields": SUMMARY_FIELDS,
|
||||
},
|
||||
"daily_reports": [display_path(path, skill_dir) for path in daily_paths],
|
||||
"opportunity_summary": {
|
||||
"action_type_counts": action_counts,
|
||||
"decision_counts": decision_counts,
|
||||
"risk_level_counts": risk_counts,
|
||||
},
|
||||
"curator_queue": opportunities[:20],
|
||||
"portfolio": {
|
||||
"skill_count": summary["skill_count"],
|
||||
"actionable_issue_count": portfolio_issue_count,
|
||||
"route_collision_count": _as_int(atlas_summary.get("route_collision_count")),
|
||||
"actionable_route_collision_count": _as_int(atlas_summary.get("actionable_route_collision_count")),
|
||||
"owner_gap_count": _as_int(atlas_summary.get("owner_gap_count")),
|
||||
"actionable_owner_gap_count": _as_int(atlas_summary.get("actionable_owner_gap_count")),
|
||||
"stale_count": _as_int(atlas_summary.get("stale_count")),
|
||||
"actionable_stale_count": _as_int(atlas_summary.get("actionable_stale_count")),
|
||||
"drift_signal_count": _as_int(atlas_summary.get("drift_signal_count")),
|
||||
"actionable_drift_signal_count": _as_int(atlas_summary.get("actionable_drift_signal_count")),
|
||||
"no_route_opportunity_count": _as_int(atlas_summary.get("no_route_opportunity_count")),
|
||||
},
|
||||
"release_state": {
|
||||
"release_lock_ready": summary["release_lock_ready"],
|
||||
"evidence_consistency_ok": summary["evidence_consistency_ok"],
|
||||
"public_world_class_ready": summary["public_world_class_ready"],
|
||||
"world_class_pending_count": summary["world_class_pending_count"],
|
||||
},
|
||||
"actions": actions,
|
||||
"failures": failures,
|
||||
"source_reports": {
|
||||
"daily_dir": "reports/skillops/daily",
|
||||
"skill_atlas": "reports/skill_atlas.json",
|
||||
"benchmark_reproducibility": "reports/benchmark_reproducibility.json",
|
||||
"evidence_consistency": "reports/evidence_consistency.json",
|
||||
"world_class_ledger": "reports/world_class_evidence_ledger.json",
|
||||
},
|
||||
"artifacts": {
|
||||
"json": str(default_weekly_path(skill_dir, generated_at, "json").relative_to(skill_dir)),
|
||||
"markdown": str(default_weekly_path(skill_dir, generated_at, "md").relative_to(skill_dir)),
|
||||
},
|
||||
}
|
||||
return report
|
||||
|
||||
|
||||
def render_markdown(report: dict[str, Any]) -> str:
|
||||
summary = report["summary"]
|
||||
lines = [
|
||||
"# Weekly SkillOps Curator Report",
|
||||
"",
|
||||
f"Generated at: `{report['generated_at']}`",
|
||||
f"Week: `{summary['week_id']}`",
|
||||
"",
|
||||
"## Summary",
|
||||
"",
|
||||
]
|
||||
for key in [
|
||||
"decision",
|
||||
"daily_report_count",
|
||||
"unique_opportunity_count",
|
||||
"ready_for_approval_review_count",
|
||||
"proposal_review_count",
|
||||
"top_score",
|
||||
"skill_count",
|
||||
"actionable_portfolio_issue_count",
|
||||
"release_lock_ready",
|
||||
"evidence_consistency_ok",
|
||||
"public_world_class_ready",
|
||||
"world_class_pending_count",
|
||||
]:
|
||||
lines.append(f"- {key}: `{summary[key]}`")
|
||||
lines.extend(
|
||||
[
|
||||
"",
|
||||
"This report is a weekly curator cockpit for generated SkillOps evidence. It does not scan private logs, write source files, apply patches, or count as world-class evidence.",
|
||||
"",
|
||||
"## Curator Boundary",
|
||||
"",
|
||||
]
|
||||
)
|
||||
contract = report["curator_contract"]
|
||||
for key in [
|
||||
"raw_content_stored",
|
||||
"redacted_or_generated_evidence_only",
|
||||
"proposal_only",
|
||||
"writes_source_files",
|
||||
"auto_patch_enabled",
|
||||
"approval_required_for_writes",
|
||||
"counts_as_world_class_evidence",
|
||||
]:
|
||||
lines.append(f"- {key}: `{str(contract[key]).lower()}`")
|
||||
lines.extend(["", "## Actions", ""])
|
||||
for action in report["actions"]:
|
||||
lines.append(f"- `{action['priority']}` {action['action']}")
|
||||
lines.extend(["", "## Curator Queue", ""])
|
||||
if not report["curator_queue"]:
|
||||
lines.append("- No weekly curator opportunities.")
|
||||
for item in report["curator_queue"]:
|
||||
lines.extend(
|
||||
[
|
||||
f"### {item.get('title', '')}",
|
||||
"",
|
||||
f"- ID: `{item.get('opportunity_id', '')}`",
|
||||
f"- Action: `{item.get('action_type', '')}`",
|
||||
f"- Decision: `{item.get('decision', '')}`",
|
||||
f"- Score: `{item.get('score', 0)}`",
|
||||
f"- Risk: `{item.get('risk_level', '')}`",
|
||||
f"- Source day: `{item.get('daily_report_date', '')}`",
|
||||
f"- Policy: {item.get('policy_reason', '')}",
|
||||
"",
|
||||
]
|
||||
)
|
||||
lines.extend(["## Portfolio Signals", ""])
|
||||
for key, value in report["portfolio"].items():
|
||||
lines.append(f"- {key}: `{value}`")
|
||||
lines.extend(["", "## Evidence", ""])
|
||||
for label, path in report["source_reports"].items():
|
||||
lines.append(f"- {label}: `{path}`")
|
||||
if report["failures"]:
|
||||
lines.extend(["", "## Failures", ""])
|
||||
lines.extend(f"- {failure}" for failure in report["failures"])
|
||||
return "\n".join(lines).rstrip() + "\n"
|
||||
|
||||
|
||||
def main() -> None:
|
||||
parser = argparse.ArgumentParser(description="Render a weekly SkillOps curator report from generated SkillOps evidence.")
|
||||
parser.add_argument("skill_dir", nargs="?", default=".")
|
||||
parser.add_argument("--daily-json", action="append", default=[], help="Explicit Daily SkillOps JSON report to include.")
|
||||
parser.add_argument("--output-json")
|
||||
parser.add_argument("--output-md")
|
||||
parser.add_argument("--generated-at", default=utc_now())
|
||||
args = parser.parse_args()
|
||||
|
||||
skill_dir = Path(args.skill_dir).resolve()
|
||||
report = build_report(skill_dir, args.generated_at, [Path(item) for item in args.daily_json])
|
||||
output_json = resolve_output(skill_dir, args.output_json) if args.output_json else default_weekly_path(skill_dir, args.generated_at, "json")
|
||||
output_md = resolve_output(skill_dir, args.output_md) if args.output_md else default_weekly_path(skill_dir, args.generated_at, "md")
|
||||
report["artifacts"] = {
|
||||
"json": display_path(output_json, skill_dir),
|
||||
"markdown": display_path(output_md, skill_dir),
|
||||
}
|
||||
write_json(output_json, report)
|
||||
write_text(output_md, render_markdown(report))
|
||||
print(json.dumps(report, ensure_ascii=False, indent=2))
|
||||
if not report["ok"]:
|
||||
raise SystemExit(2)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
+7
-1
@@ -10,7 +10,13 @@ from yao_cli_config import (
|
||||
resolve_promotion_target,
|
||||
resolve_target,
|
||||
)
|
||||
from yao_cli_adaptation_commands import command_adapt_apply, command_adapt_propose, command_adapt_scan, command_daily_skillops
|
||||
from yao_cli_adaptation_commands import (
|
||||
command_adapt_apply,
|
||||
command_adapt_propose,
|
||||
command_adapt_scan,
|
||||
command_daily_skillops,
|
||||
command_weekly_curator,
|
||||
)
|
||||
from yao_cli_create_commands import command_init, command_quickstart
|
||||
from yao_cli_distribution_commands import (
|
||||
command_compile_skill,
|
||||
|
||||
@@ -103,3 +103,19 @@ def command_daily_skillops(args: argparse.Namespace) -> int:
|
||||
result = run_script("render_daily_skillops_report.py", cmd)
|
||||
print(json.dumps(result["payload"] if result["payload"] is not None else result, ensure_ascii=False, indent=2))
|
||||
return 0 if result["ok"] else 2
|
||||
|
||||
|
||||
def command_weekly_curator(args: argparse.Namespace) -> int:
|
||||
skill_dir = str(Path(args.skill_dir).resolve())
|
||||
cmd = [skill_dir]
|
||||
for path in args.daily_json:
|
||||
cmd.extend(["--daily-json", path])
|
||||
if args.output_json:
|
||||
cmd.extend(["--output-json", args.output_json])
|
||||
if args.output_md:
|
||||
cmd.extend(["--output-md", args.output_md])
|
||||
if args.generated_at:
|
||||
cmd.extend(["--generated-at", args.generated_at])
|
||||
result = run_script("render_weekly_curator_report.py", cmd)
|
||||
print(json.dumps(result["payload"] if result["payload"] is not None else result, ensure_ascii=False, indent=2))
|
||||
return 0 if result["ok"] else 2
|
||||
|
||||
@@ -475,6 +475,17 @@ def build_parser(command_handlers: dict[str, Callable[[argparse.Namespace], int]
|
||||
daily_skillops_cmd.add_argument("--no-refresh-source-reports", action="store_true")
|
||||
daily_skillops_cmd.set_defaults(func=_handler(command_handlers, "command_daily_skillops"))
|
||||
|
||||
weekly_curator_cmd = subparsers.add_parser(
|
||||
"weekly-curator",
|
||||
help="Render a weekly SkillOps curator report from generated daily reports and portfolio evidence.",
|
||||
)
|
||||
weekly_curator_cmd.add_argument("skill_dir", nargs="?", default=".")
|
||||
weekly_curator_cmd.add_argument("--daily-json", action="append", default=[])
|
||||
weekly_curator_cmd.add_argument("--output-json")
|
||||
weekly_curator_cmd.add_argument("--output-md")
|
||||
weekly_curator_cmd.add_argument("--generated-at")
|
||||
weekly_curator_cmd.set_defaults(func=_handler(command_handlers, "command_weekly_curator"))
|
||||
|
||||
adoption_drift_cmd = subparsers.add_parser(
|
||||
"adoption-drift",
|
||||
help="Render local-first metadata-only adoption and drift telemetry for a skill package.",
|
||||
|
||||
@@ -551,10 +551,10 @@ def main() -> None:
|
||||
if full_payload["data"]["skill_os2_coverage"]:
|
||||
assert full_payload["data"]["skill_os2_coverage"]["summary"]["local_blueprint_ready"] is True, full_payload["data"]["skill_os2_coverage"]
|
||||
assert full_payload["data"]["skill_os2_coverage"]["summary"]["public_world_class_ready"] is False, full_payload["data"]["skill_os2_coverage"]
|
||||
assert full_payload["data"]["skill_os2_coverage"]["summary"]["extension_track_count"] == 3, full_payload["data"]["skill_os2_coverage"]
|
||||
assert full_payload["data"]["skill_os2_coverage"]["summary"]["extension_track_count"] == 4, full_payload["data"]["skill_os2_coverage"]
|
||||
assert full_payload["data"]["skill_os2_coverage"]["summary"]["extension_partial_count"] == 0, full_payload["data"]["skill_os2_coverage"]
|
||||
assert full_payload["data"]["skill_os2_coverage"]["summary"]["extension_planned_count"] == 0, full_payload["data"]["skill_os2_coverage"]
|
||||
assert full_payload["data"]["skill_os2_coverage"]["summary"]["extension_covered_count"] == 3, full_payload["data"]["skill_os2_coverage"]
|
||||
assert full_payload["data"]["skill_os2_coverage"]["summary"]["extension_covered_count"] == 4, full_payload["data"]["skill_os2_coverage"]
|
||||
assert full_payload["data"]["skill_os2_coverage"]["summary"]["adaptive_extension_ready"] is True, full_payload["data"]["skill_os2_coverage"]
|
||||
extension_tracks = {
|
||||
item["key"]: item
|
||||
@@ -563,6 +563,7 @@ def main() -> None:
|
||||
assert extension_tracks["skill-interpretation-report"]["status"] == "covered", extension_tracks
|
||||
assert extension_tracks["adaptive-self-iteration"]["status"] == "covered", extension_tracks
|
||||
assert extension_tracks["daily-skillops-report"]["status"] == "covered", extension_tracks
|
||||
assert extension_tracks["weekly-curator-report"]["status"] == "covered", extension_tracks
|
||||
world_class_entries = full_payload["data"]["world_class_evidence_ledger"]["entries"]
|
||||
assert len(world_class_entries) == 4, world_class_entries
|
||||
assert {item["key"] for item in world_class_entries} == {
|
||||
@@ -673,7 +674,7 @@ def main() -> None:
|
||||
assert "Extension Track Count" in html, html
|
||||
assert "Adaptive Extension Ready" in html, html
|
||||
assert "<dt>Extension Partial Count</dt><dd>0</dd>" in html, html
|
||||
assert "<dt>Extension Covered Count</dt><dd>3</dd>" in html, html
|
||||
assert "<dt>Extension Covered Count</dt><dd>4</dd>" in html, html
|
||||
assert "<dt>Extension Planned Count</dt><dd>0</dd>" in html, html
|
||||
assert "Adaptive Extension Ready" in html, html
|
||||
assert "本地蓝图" in html, html
|
||||
|
||||
@@ -44,10 +44,10 @@ def main() -> None:
|
||||
assert summary["pass_count"] == 21, summary
|
||||
assert summary["warn_count"] == 0, summary
|
||||
assert summary["missing_count"] == 0, summary
|
||||
assert summary["extension_track_count"] == 3, summary
|
||||
assert summary["extension_track_count"] == 4, summary
|
||||
assert summary["extension_partial_count"] == 0, summary
|
||||
assert summary["extension_planned_count"] == 0, summary
|
||||
assert summary["extension_covered_count"] == 3, summary
|
||||
assert summary["extension_covered_count"] == 4, summary
|
||||
assert summary["adaptive_extension_ready"] is True, summary
|
||||
assert summary["local_blueprint_ready"] is True, summary
|
||||
assert summary["public_world_class_ready"] is False, summary
|
||||
@@ -88,11 +88,12 @@ def main() -> None:
|
||||
assert any(entry["path"] == "reports/benchmark_reproducibility.json" and entry["exists"] for entry in prs["benchmark-methodology"]["evidence"])
|
||||
assert payload["source_blueprint"]["core_module_count"] == 8, payload
|
||||
assert payload["source_blueprint"]["recommended_pr_count"] == 13, payload
|
||||
assert payload["source_blueprint"]["reference_extension_count"] == 3, payload
|
||||
assert payload["source_blueprint"]["reference_extension_count"] == 4, payload
|
||||
extension_tracks = {item["key"]: item for item in payload["reference_extension_tracks"]}
|
||||
assert extension_tracks["skill-interpretation-report"]["status"] == "covered", extension_tracks
|
||||
assert extension_tracks["adaptive-self-iteration"]["status"] == "covered", extension_tracks
|
||||
assert extension_tracks["daily-skillops-report"]["status"] == "covered", extension_tracks
|
||||
assert extension_tracks["weekly-curator-report"]["status"] == "covered", extension_tracks
|
||||
assert any(
|
||||
entry["path"] == "reports/skill-overview.html" and entry["exists"]
|
||||
for entry in extension_tracks["skill-interpretation-report"]["evidence"]
|
||||
@@ -141,6 +142,26 @@ def main() -> None:
|
||||
and entry["exists"]
|
||||
for entry in extension_tracks["daily-skillops-report"]["evidence"]
|
||||
), extension_tracks["daily-skillops-report"]
|
||||
assert any(
|
||||
entry["path"] == "scripts/render_weekly_curator_report.py" and entry["exists"]
|
||||
for entry in extension_tracks["weekly-curator-report"]["evidence"]
|
||||
), extension_tracks["weekly-curator-report"]
|
||||
assert any(
|
||||
entry["path"] == "tests/verify_weekly_curator.py" and entry["exists"]
|
||||
for entry in extension_tracks["weekly-curator-report"]["evidence"]
|
||||
), extension_tracks["weekly-curator-report"]
|
||||
assert any(
|
||||
entry["path"].startswith("reports/skillops/weekly/")
|
||||
and entry["path"].endswith(".json")
|
||||
and entry["exists"]
|
||||
for entry in extension_tracks["weekly-curator-report"]["evidence"]
|
||||
), extension_tracks["weekly-curator-report"]
|
||||
assert any(
|
||||
entry["path"].startswith("reports/skillops/weekly/")
|
||||
and entry["path"].endswith(".md")
|
||||
and entry["exists"]
|
||||
for entry in extension_tracks["weekly-curator-report"]["evidence"]
|
||||
), extension_tracks["weekly-curator-report"]
|
||||
assert "Close the four world-class evidence ledger entries" in payload["next_highest_leverage"][0], payload
|
||||
assert "skill interpretation report" in " ".join(payload["next_highest_leverage"]), payload
|
||||
assert "Daily SkillOps" in " ".join(payload["next_highest_leverage"]), payload
|
||||
@@ -148,7 +169,7 @@ def main() -> None:
|
||||
assert "Skill OS 2.0 Blueprint Coverage" in markdown, markdown
|
||||
assert "local blueprint ready: `true`" in markdown, markdown
|
||||
assert "public world-class ready: `false`" in markdown, markdown
|
||||
assert "extension covered: `3`" in markdown, markdown
|
||||
assert "extension covered: `4`" in markdown, markdown
|
||||
assert "extension partial: `0`" in markdown, markdown
|
||||
assert "## Core Modules" in markdown, markdown
|
||||
assert "## Recommended PR Coverage" in markdown, markdown
|
||||
@@ -157,6 +178,7 @@ def main() -> None:
|
||||
assert "Skill Interpretation Report" in markdown, markdown
|
||||
assert "Adaptive Self-Iteration" in markdown, markdown
|
||||
assert "Daily SkillOps Report" in markdown, markdown
|
||||
assert "Weekly Curator Report" in markdown, markdown
|
||||
assert "user-supplied 2.0 reference plan" in markdown, markdown
|
||||
assert "`agent-skills-conformance`" not in markdown, markdown
|
||||
assert "Agent Skills Conformance" in markdown, markdown
|
||||
|
||||
@@ -0,0 +1,201 @@
|
||||
#!/usr/bin/env python3
|
||||
import json
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
ROOT = Path(__file__).resolve().parent.parent
|
||||
SCRIPT = ROOT / "scripts" / "render_weekly_curator_report.py"
|
||||
CLI = ROOT / "scripts" / "yao.py"
|
||||
TMP = ROOT / "tests" / "tmp_weekly_curator"
|
||||
|
||||
|
||||
def run_command(*args: str) -> subprocess.CompletedProcess[str]:
|
||||
return subprocess.run(
|
||||
[sys.executable, *args],
|
||||
cwd=ROOT,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
)
|
||||
|
||||
|
||||
def write_json(path: Path, payload: dict) -> None:
|
||||
path.parent.mkdir(parents=True, exist_ok=True)
|
||||
path.write_text(json.dumps(payload, ensure_ascii=False, indent=2) + "\n", encoding="utf-8")
|
||||
|
||||
|
||||
def seed_reports(skill_dir: Path) -> None:
|
||||
reports = skill_dir / "reports"
|
||||
write_json(
|
||||
reports / "skillops" / "daily" / "2026-06-16.json",
|
||||
{
|
||||
"ok": True,
|
||||
"generated_at": "2026-06-16T08:00:00Z",
|
||||
"opportunity_summary": {"opportunity_count": 3},
|
||||
"opportunities": [
|
||||
{
|
||||
"opportunity_id": "skillops-aaaaaaaaaa",
|
||||
"proposal_id": "adapt-a",
|
||||
"pattern_id": "report_ui",
|
||||
"title": "Improve report layout",
|
||||
"opportunity_type": "artifact-quality",
|
||||
"action_type": "patch_existing_skill",
|
||||
"decision": "ready_for_approval_review",
|
||||
"priority": "high",
|
||||
"score": 92,
|
||||
"risk_level": "medium",
|
||||
"requires_approval": True,
|
||||
"write_allowed_without_approval": False,
|
||||
"evidence_count": 5,
|
||||
"target_files": ["scripts/render_skill_overview.py"],
|
||||
"verification_commands": ["python3 tests/verify_skill_overview.py"],
|
||||
"policy_reason": "Report layout feedback maps to renderer changes.",
|
||||
},
|
||||
{
|
||||
"opportunity_id": "skillops-bbbbbbbbbb",
|
||||
"proposal_id": "adapt-b",
|
||||
"pattern_id": "approval_safety",
|
||||
"title": "Keep adaptive changes approval-gated",
|
||||
"opportunity_type": "governance",
|
||||
"action_type": "agents_update",
|
||||
"decision": "proposal_review",
|
||||
"priority": "medium",
|
||||
"score": 78,
|
||||
"risk_level": "low",
|
||||
"requires_approval": True,
|
||||
"write_allowed_without_approval": False,
|
||||
"evidence_count": 2,
|
||||
"target_files": ["AGENTS.md"],
|
||||
"verification_commands": ["python3 tests/verify_adaptation_safety.py"],
|
||||
"policy_reason": "Governance feedback maps to durable guidance.",
|
||||
},
|
||||
{
|
||||
"opportunity_id": "skillops-cccccccccc",
|
||||
"proposal_id": "adapt-c",
|
||||
"pattern_id": "evidence_testing",
|
||||
"title": "Add evidence regression",
|
||||
"opportunity_type": "quality-gate",
|
||||
"action_type": "add_eval",
|
||||
"decision": "proposal_review",
|
||||
"priority": "medium",
|
||||
"score": 72,
|
||||
"risk_level": "medium",
|
||||
"requires_approval": True,
|
||||
"write_allowed_without_approval": False,
|
||||
"evidence_count": 2,
|
||||
"target_files": ["tests/verify_daily_skillops.py"],
|
||||
"verification_commands": ["python3 tests/verify_daily_skillops.py"],
|
||||
"policy_reason": "Verification feedback maps to focused checks.",
|
||||
},
|
||||
],
|
||||
},
|
||||
)
|
||||
write_json(
|
||||
reports / "skill_atlas.json",
|
||||
{
|
||||
"ok": True,
|
||||
"summary": {
|
||||
"skill_count": 4,
|
||||
"route_collision_count": 2,
|
||||
"actionable_route_collision_count": 1,
|
||||
"owner_gap_count": 1,
|
||||
"actionable_owner_gap_count": 0,
|
||||
"stale_count": 1,
|
||||
"actionable_stale_count": 0,
|
||||
"drift_signal_count": 1,
|
||||
"actionable_drift_signal_count": 0,
|
||||
"no_route_opportunity_count": 1,
|
||||
},
|
||||
},
|
||||
)
|
||||
write_json(reports / "benchmark_reproducibility.json", {"ok": True, "summary": {"release_lock_ready": True}})
|
||||
write_json(reports / "evidence_consistency.json", {"ok": True, "summary": {"decision": "consistent"}})
|
||||
write_json(
|
||||
reports / "world_class_evidence_ledger.json",
|
||||
{"ok": True, "summary": {"pending_count": 4, "ready_to_claim_world_class": False}},
|
||||
)
|
||||
|
||||
|
||||
def assert_contract(payload: dict) -> None:
|
||||
assert payload["schema_version"] == "1.0", payload
|
||||
assert payload["ok"] is True, payload
|
||||
assert payload["report_contract"]["contract"] == "weekly-skillops-curator-report", payload
|
||||
assert payload["curator_contract"]["writes_source_files"] is False, payload
|
||||
assert payload["curator_contract"]["auto_patch_enabled"] is False, payload
|
||||
assert payload["curator_contract"]["approval_required_for_writes"] is True, payload
|
||||
assert payload["curator_contract"]["counts_as_world_class_evidence"] is False, payload
|
||||
for field in payload["report_contract"]["summary_fields"]:
|
||||
assert payload[field] == payload["summary"][field], field
|
||||
|
||||
|
||||
def main() -> None:
|
||||
shutil.rmtree(TMP, ignore_errors=True)
|
||||
skill_dir = TMP / "weekly-curator-demo"
|
||||
skill_dir.mkdir(parents=True)
|
||||
seed_reports(skill_dir)
|
||||
output_json = skill_dir / "reports" / "skillops" / "weekly" / "2026-W25.json"
|
||||
output_md = skill_dir / "reports" / "skillops" / "weekly" / "2026-W25.md"
|
||||
|
||||
proc = run_command(
|
||||
str(SCRIPT),
|
||||
str(skill_dir),
|
||||
"--output-json",
|
||||
str(output_json),
|
||||
"--output-md",
|
||||
str(output_md),
|
||||
"--generated-at",
|
||||
"2026-06-16T08:00:00Z",
|
||||
)
|
||||
assert proc.returncode == 0, proc.stderr
|
||||
payload = json.loads(proc.stdout)
|
||||
assert_contract(payload)
|
||||
assert payload["summary"]["week_id"] == "2026-W25", payload
|
||||
assert payload["summary"]["daily_report_count"] == 1, payload
|
||||
assert payload["summary"]["unique_opportunity_count"] == 3, payload
|
||||
assert payload["summary"]["ready_for_approval_review_count"] == 1, payload
|
||||
assert payload["summary"]["proposal_review_count"] == 2, payload
|
||||
assert payload["summary"]["top_score"] == 92, payload
|
||||
assert payload["summary"]["skill_count"] == 4, payload
|
||||
assert payload["summary"]["actionable_portfolio_issue_count"] == 2, payload
|
||||
assert payload["summary"]["release_lock_ready"] is True, payload
|
||||
assert payload["summary"]["evidence_consistency_ok"] is True, payload
|
||||
assert payload["summary"]["public_world_class_ready"] is False, payload
|
||||
assert payload["summary"]["world_class_pending_count"] == 4, payload
|
||||
assert payload["opportunity_summary"]["action_type_counts"]["patch_existing_skill"] == 1, payload
|
||||
assert payload["opportunity_summary"]["action_type_counts"]["agents_update"] == 1, payload
|
||||
assert payload["opportunity_summary"]["action_type_counts"]["add_eval"] == 1, payload
|
||||
assert all(item["write_allowed_without_approval"] is False for item in payload["curator_queue"]), payload
|
||||
action_keys = {item["key"] for item in payload["actions"]}
|
||||
assert {"review-ready-opportunities", "triage-skill-library", "close-world-class-evidence"} <= action_keys, payload
|
||||
markdown = output_md.read_text(encoding="utf-8")
|
||||
assert "Weekly SkillOps Curator Report" in markdown, markdown
|
||||
assert "## Curator Queue" in markdown, markdown
|
||||
assert "counts_as_world_class_evidence: `false`" in markdown, markdown
|
||||
|
||||
cli_output_json = skill_dir / "reports" / "skillops" / "weekly" / "cli.json"
|
||||
cli_output_md = skill_dir / "reports" / "skillops" / "weekly" / "cli.md"
|
||||
cli_proc = run_command(
|
||||
str(CLI),
|
||||
"weekly-curator",
|
||||
str(skill_dir),
|
||||
"--output-json",
|
||||
str(cli_output_json),
|
||||
"--output-md",
|
||||
str(cli_output_md),
|
||||
"--generated-at",
|
||||
"2026-06-16T08:00:00Z",
|
||||
)
|
||||
assert cli_proc.returncode == 0, cli_proc.stderr
|
||||
cli_payload = json.loads(cli_proc.stdout)
|
||||
assert_contract(cli_payload)
|
||||
assert cli_payload["summary"]["unique_opportunity_count"] == 3, cli_payload
|
||||
assert cli_output_json.exists(), cli_output_json
|
||||
assert cli_output_md.exists(), cli_output_md
|
||||
|
||||
print(json.dumps({"ok": True}, ensure_ascii=False, indent=2))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user