31ce04c655
Merge the beta-ready Yao Meta Skill architecture, report, evidence gate, and release-boundary updates.\n\nRelease boundary: beta/public testing is allowed; formal world-class, fully reviewed, or superiority claims remain blocked until the pending evidence gates are accepted.
485 lines
21 KiB
Python
485 lines
21 KiB
Python
#!/usr/bin/env python3
|
|
import argparse
|
|
import json
|
|
from datetime import date, datetime, timezone
|
|
from pathlib import Path
|
|
from tempfile import TemporaryDirectory
|
|
from typing import Any
|
|
|
|
from propose_adaptation import build_report as build_proposal_report
|
|
from propose_adaptation import render_markdown as render_proposals_markdown
|
|
from skillops_opportunity import build_opportunities, decision_policy_contract, summarize_opportunities
|
|
from summarize_user_signals import build_report as build_pattern_report
|
|
from summarize_user_signals import render_markdown as render_patterns_markdown
|
|
|
|
|
|
ROOT = Path(__file__).resolve().parent.parent
|
|
SCRIPT_INTERFACE = "cli"
|
|
SCRIPT_INTERFACE_REASON = "Renders a Daily SkillOps report that summarizes explicit-source patterns, proposals, approval state, and release evidence without scanning private logs or applying patches."
|
|
|
|
SUMMARY_FIELDS = [
|
|
"decision",
|
|
"source_supplied",
|
|
"pattern_count",
|
|
"proposal_count",
|
|
"approval_count",
|
|
"pending_review_count",
|
|
"applied_count",
|
|
"rollback_count",
|
|
"local_blueprint_ready",
|
|
"public_world_class_ready",
|
|
"world_class_pending_count",
|
|
"release_lock_ready",
|
|
"evidence_consistency_ok",
|
|
"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 report_date(generated_at: str) -> str:
|
|
if len(generated_at) >= 10:
|
|
candidate = generated_at[:10]
|
|
try:
|
|
date.fromisoformat(candidate)
|
|
return candidate
|
|
except ValueError:
|
|
pass
|
|
return date.today().isoformat()
|
|
|
|
|
|
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_daily_path(skill_dir: Path, generated_at: str, suffix: str) -> Path:
|
|
return skill_dir / "reports" / "skillops" / "daily" / f"{report_date(generated_at)}.{suffix}"
|
|
|
|
|
|
def source_summary(patterns: dict[str, Any]) -> dict[str, Any]:
|
|
source = patterns.get("source", {}) if isinstance(patterns.get("source"), dict) else {}
|
|
privacy = patterns.get("privacy_contract", {}) if isinstance(patterns.get("privacy_contract"), dict) else {}
|
|
return {
|
|
"path": source.get("path", ""),
|
|
"fingerprint_sha256": source.get("fingerprint_sha256", ""),
|
|
"record_count": source.get("record_count", 0),
|
|
"explicit_source": privacy.get("explicit_source_required") is True,
|
|
"raw_content_stored": privacy.get("raw_content_stored") is True,
|
|
"redacted_excerpts_only": privacy.get("redacted_excerpts_only") is True,
|
|
}
|
|
|
|
|
|
def compact_proposals(proposals: dict[str, Any]) -> list[dict[str, Any]]:
|
|
rows = []
|
|
for item in proposals.get("proposals", []):
|
|
if not isinstance(item, dict):
|
|
continue
|
|
rows.append(
|
|
{
|
|
"proposal_id": item.get("proposal_id", ""),
|
|
"pattern_id": item.get("pattern_id", ""),
|
|
"title": item.get("title", ""),
|
|
"risk_level": item.get("risk_level", ""),
|
|
"status": item.get("status", ""),
|
|
"requires_approval": item.get("requires_approval") is True,
|
|
"target_files": item.get("target_files", []),
|
|
"verification_commands": item.get("verification_commands", []),
|
|
}
|
|
)
|
|
return rows
|
|
|
|
|
|
def build_actions(summary: dict[str, Any], proposal_rows: list[dict[str, Any]]) -> list[dict[str, str]]:
|
|
actions: list[dict[str, str]] = []
|
|
if summary["source_supplied"] is False and summary["pattern_count"] == 0:
|
|
actions.append(
|
|
{
|
|
"key": "provide-explicit-source",
|
|
"priority": "medium",
|
|
"action": "Run daily-skillops with --source pointing to a curated JSONL or Markdown conversation summary.",
|
|
}
|
|
)
|
|
if proposal_rows:
|
|
actions.append(
|
|
{
|
|
"key": "review-adaptation-proposals",
|
|
"priority": "high",
|
|
"action": "Review proposal-only adaptation items before preparing any approval ledger entry.",
|
|
}
|
|
)
|
|
if summary["pending_review_count"]:
|
|
actions.append(
|
|
{
|
|
"key": "resolve-pending-approvals",
|
|
"priority": "high",
|
|
"action": "Approve, reject, or expire pending adaptive approval ledger entries before applying patches.",
|
|
}
|
|
)
|
|
if summary["world_class_pending_count"]:
|
|
actions.append(
|
|
{
|
|
"key": "close-world-class-evidence",
|
|
"priority": "high",
|
|
"action": "Collect accepted external or human evidence for the pending world-class ledger entries.",
|
|
}
|
|
)
|
|
if summary["evidence_consistency_ok"] is not True:
|
|
actions.append(
|
|
{
|
|
"key": "refresh-evidence-consistency",
|
|
"priority": "high",
|
|
"action": "Regenerate evidence-consistency before using this report for release decisions.",
|
|
}
|
|
)
|
|
if not actions:
|
|
actions.append(
|
|
{
|
|
"key": "monitor",
|
|
"priority": "low",
|
|
"action": "No action required beyond routine daily monitoring.",
|
|
}
|
|
)
|
|
return actions
|
|
|
|
|
|
def build_report(
|
|
skill_dir: Path,
|
|
generated_at: str,
|
|
source: Path | None = None,
|
|
min_support: int = 2,
|
|
allow_history_source: bool = False,
|
|
patterns_json: Path | None = None,
|
|
proposals_json: Path | None = None,
|
|
write_source_reports: bool = True,
|
|
) -> dict[str, Any]:
|
|
skill_dir = skill_dir.resolve()
|
|
reports = skill_dir / "reports"
|
|
patterns_path = resolve_output(skill_dir, str(patterns_json or "reports/user_patterns.json"))
|
|
proposals_path = resolve_output(skill_dir, str(proposals_json or "reports/adaptation_proposals.json"))
|
|
failures: list[str] = []
|
|
|
|
if source is not None:
|
|
pattern_report = build_pattern_report(
|
|
skill_dir,
|
|
source,
|
|
min_support=max(2, min_support),
|
|
generated_at=generated_at,
|
|
allow_history_source=allow_history_source,
|
|
)
|
|
if pattern_report.get("ok") is True and write_source_reports:
|
|
pattern_report["artifacts"] = {
|
|
"json": display_path(patterns_path, skill_dir),
|
|
"markdown": display_path(patterns_path.with_suffix(".md"), skill_dir),
|
|
}
|
|
write_json(patterns_path, pattern_report)
|
|
write_text(patterns_path.with_suffix(".md"), render_patterns_markdown(pattern_report))
|
|
else:
|
|
failures.extend(pattern_report.get("failures", []))
|
|
else:
|
|
pattern_report = load_json(patterns_path)
|
|
|
|
if pattern_report and pattern_report.get("ok") is True:
|
|
proposal_source_path = patterns_path
|
|
with TemporaryDirectory() as temp_dir:
|
|
if source is not None and not write_source_reports:
|
|
proposal_source_path = Path(temp_dir) / "user_patterns.json"
|
|
write_json(proposal_source_path, pattern_report)
|
|
proposal_report = build_proposal_report(skill_dir, proposal_source_path, generated_at)
|
|
if proposal_report.get("ok") is True and write_source_reports:
|
|
proposal_report["artifacts"] = {
|
|
"json": display_path(proposals_path, skill_dir),
|
|
"markdown": display_path(proposals_path.with_suffix(".md"), skill_dir),
|
|
}
|
|
write_json(proposals_path, proposal_report)
|
|
write_text(proposals_path.with_suffix(".md"), render_proposals_markdown(proposal_report))
|
|
elif proposal_report.get("ok") is not True:
|
|
failures.extend(proposal_report.get("failures", []))
|
|
else:
|
|
proposal_report = load_json(proposals_path)
|
|
if source is not None and not pattern_report:
|
|
failures.append("Pattern report could not be built from the explicit source.")
|
|
|
|
approval = load_json(reports / "adaptation_approval_ledger.json")
|
|
regression = load_json(reports / "adaptation_regression_report.json")
|
|
coverage = load_json(reports / "skill_os2_coverage.json")
|
|
ledger = load_json(reports / "world_class_evidence_ledger.json")
|
|
consistency = load_json(reports / "evidence_consistency.json")
|
|
benchmark = load_json(reports / "benchmark_reproducibility.json")
|
|
|
|
pattern_summary = pattern_report.get("summary", {}) if isinstance(pattern_report.get("summary"), dict) else {}
|
|
proposal_summary = proposal_report.get("summary", {}) if isinstance(proposal_report.get("summary"), dict) else {}
|
|
approval_summary = approval.get("summary", {}) if isinstance(approval.get("summary"), dict) else {}
|
|
regression_summary = regression.get("summary", {}) if isinstance(regression.get("summary"), dict) else {}
|
|
coverage_summary = coverage.get("summary", {}) if isinstance(coverage.get("summary"), dict) else {}
|
|
ledger_summary = ledger.get("summary", {}) if isinstance(ledger.get("summary"), dict) else {}
|
|
benchmark_summary = benchmark.get("summary", {}) if isinstance(benchmark.get("summary"), dict) else {}
|
|
proposal_contract = proposal_report.get("proposal_contract", {}) if isinstance(proposal_report.get("proposal_contract"), dict) else {}
|
|
|
|
proposal_rows = compact_proposals(proposal_report)
|
|
pattern_rows = pattern_report.get("patterns", []) if isinstance(pattern_report.get("patterns"), list) else []
|
|
opportunities = build_opportunities(pattern_rows, proposal_rows)
|
|
opportunity_summary = summarize_opportunities(opportunities)
|
|
failure_count = len(failures)
|
|
summary = {
|
|
"decision": "blocked" if failure_count else "proposal-review" if proposal_rows else "monitor",
|
|
"source_supplied": source is not None,
|
|
"pattern_count": int(pattern_summary.get("pattern_count", 0) or 0),
|
|
"proposal_count": int(proposal_summary.get("proposal_count", 0) or len(proposal_rows)),
|
|
"approval_count": int(approval_summary.get("approval_count", 0) or 0),
|
|
"pending_review_count": int(approval_summary.get("pending_review_count", 0) or 0),
|
|
"applied_count": int(approval_summary.get("applied_count", 0) or regression_summary.get("applied_count", 0) or 0),
|
|
"rollback_count": int(approval_summary.get("rollback_count", 0) or regression_summary.get("rollback_count", 0) or 0),
|
|
"local_blueprint_ready": coverage_summary.get("local_blueprint_ready") is True,
|
|
"public_world_class_ready": coverage_summary.get("public_world_class_ready") is True,
|
|
"world_class_pending_count": int(ledger_summary.get("pending_count", coverage_summary.get("world_class_evidence_pending_count", 0)) or 0),
|
|
"release_lock_ready": benchmark_summary.get("release_lock_ready") is True,
|
|
"evidence_consistency_ok": consistency.get("ok") is True,
|
|
"writes_source_files": False,
|
|
"auto_patch_enabled": False,
|
|
"failure_count": failure_count,
|
|
}
|
|
actions = build_actions(summary, proposal_rows)
|
|
operations_contract = {
|
|
"schema_version": "1.0",
|
|
"contract": "daily-skillops-report",
|
|
"explicit_source_required_for_scan": True,
|
|
"implicit_private_log_scan": False,
|
|
"raw_content_stored": False,
|
|
"redacted_excerpts_only": True,
|
|
"proposal_only": proposal_contract.get("proposal_only") is not False,
|
|
"approval_required_for_writes": True,
|
|
"writes_source_files": False,
|
|
"auto_patch_enabled": False,
|
|
"daily_report_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,
|
|
"operations_contract": operations_contract,
|
|
"report_contract": {
|
|
"schema_version": "1.0",
|
|
"contract": "daily-skillops-report",
|
|
"top_level_mirrors_summary": True,
|
|
"summary_fields": SUMMARY_FIELDS,
|
|
"source_of_truth": ["summary", "operations_contract"],
|
|
},
|
|
"source": source_summary(pattern_report) if pattern_report else {},
|
|
"patterns": pattern_report.get("patterns", []) if isinstance(pattern_report.get("patterns"), list) else [],
|
|
"proposals": proposal_rows,
|
|
"opportunity_summary": opportunity_summary,
|
|
"opportunities": opportunities,
|
|
"decision_policy": decision_policy_contract(),
|
|
"approval": {
|
|
"approval_count": summary["approval_count"],
|
|
"pending_review_count": summary["pending_review_count"],
|
|
"applied_count": summary["applied_count"],
|
|
"rollback_count": summary["rollback_count"],
|
|
},
|
|
"release_state": {
|
|
"local_blueprint_ready": summary["local_blueprint_ready"],
|
|
"public_world_class_ready": summary["public_world_class_ready"],
|
|
"world_class_pending_count": summary["world_class_pending_count"],
|
|
"release_lock_ready": summary["release_lock_ready"],
|
|
"evidence_consistency_ok": summary["evidence_consistency_ok"],
|
|
},
|
|
"actions": actions,
|
|
"failures": failures,
|
|
"source_reports": {
|
|
"patterns": display_path(patterns_path, skill_dir),
|
|
"proposals": display_path(proposals_path, skill_dir),
|
|
"approval_ledger": "reports/adaptation_approval_ledger.json",
|
|
"regression": "reports/adaptation_regression_report.json",
|
|
"skill_os2_coverage": "reports/skill_os2_coverage.json",
|
|
"world_class_ledger": "reports/world_class_evidence_ledger.json",
|
|
"evidence_consistency": "reports/evidence_consistency.json",
|
|
"benchmark_reproducibility": "reports/benchmark_reproducibility.json",
|
|
},
|
|
"artifacts": {
|
|
"json": str(default_daily_path(skill_dir, generated_at, "json").relative_to(skill_dir)),
|
|
"markdown": str(default_daily_path(skill_dir, generated_at, "md").relative_to(skill_dir)),
|
|
},
|
|
}
|
|
return report
|
|
|
|
|
|
def render_markdown(report: dict[str, Any]) -> str:
|
|
summary = report["summary"]
|
|
lines = [
|
|
"# Daily SkillOps Report",
|
|
"",
|
|
f"Generated at: `{report['generated_at']}`",
|
|
"",
|
|
"## Summary",
|
|
"",
|
|
f"- decision: `{summary['decision']}`",
|
|
f"- source supplied: `{str(summary['source_supplied']).lower()}`",
|
|
f"- patterns: `{summary['pattern_count']}`",
|
|
f"- proposals: `{summary['proposal_count']}`",
|
|
f"- pending approvals: `{summary['pending_review_count']}`",
|
|
f"- applied patches: `{summary['applied_count']}`",
|
|
f"- rollbacks: `{summary['rollback_count']}`",
|
|
f"- local blueprint ready: `{str(summary['local_blueprint_ready']).lower()}`",
|
|
f"- public world-class ready: `{str(summary['public_world_class_ready']).lower()}`",
|
|
f"- world-class pending: `{summary['world_class_pending_count']}`",
|
|
f"- release lock ready: `{str(summary['release_lock_ready']).lower()}`",
|
|
f"- evidence consistency ok: `{str(summary['evidence_consistency_ok']).lower()}`",
|
|
"",
|
|
"This report is an operations cockpit for explicit-source SkillOps. It does not scan private logs, write source files, apply patches, or count as world-class external or human evidence.",
|
|
"",
|
|
"## Privacy Boundary",
|
|
"",
|
|
]
|
|
contract = report["operations_contract"]
|
|
for key in [
|
|
"explicit_source_required_for_scan",
|
|
"implicit_private_log_scan",
|
|
"raw_content_stored",
|
|
"redacted_excerpts_only",
|
|
"proposal_only",
|
|
"approval_required_for_writes",
|
|
"writes_source_files",
|
|
"auto_patch_enabled",
|
|
"daily_report_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(["", "## Opportunities", ""])
|
|
opportunity_summary = report.get("opportunity_summary", {})
|
|
lines.extend(
|
|
[
|
|
f"- count: `{opportunity_summary.get('opportunity_count', 0)}`",
|
|
f"- top score: `{opportunity_summary.get('top_score', 0)}`",
|
|
f"- ready for approval review: `{opportunity_summary.get('ready_for_approval_review_count', 0)}`",
|
|
]
|
|
)
|
|
for opportunity in report.get("opportunities", []):
|
|
lines.extend(
|
|
[
|
|
f"### {opportunity.get('title', '')}",
|
|
"",
|
|
f"- ID: `{opportunity.get('opportunity_id', '')}`",
|
|
f"- Action: `{opportunity.get('action_type', '')}`",
|
|
f"- Decision: `{opportunity.get('decision', '')}`",
|
|
f"- Score: `{opportunity.get('score', 0)}`",
|
|
f"- Risk: `{opportunity.get('risk_level', '')}`",
|
|
f"- Policy: {opportunity.get('policy_reason', '')}",
|
|
]
|
|
)
|
|
lines.extend(["", "## Patterns", ""])
|
|
patterns = report.get("patterns", [])
|
|
if not patterns:
|
|
lines.append("- No repeated pattern met the support threshold.")
|
|
for pattern in patterns:
|
|
lines.append(
|
|
f"- `{pattern.get('pattern_id', '')}`: {pattern.get('label', '')} "
|
|
f"(support `{pattern.get('support_count', 0)}`, confidence `{pattern.get('confidence', '')}`)"
|
|
)
|
|
lines.extend(["", "## Proposals", ""])
|
|
proposals = report.get("proposals", [])
|
|
if not proposals:
|
|
lines.append("- No adaptation proposals are waiting for review.")
|
|
for proposal in proposals:
|
|
lines.extend(
|
|
[
|
|
f"### {proposal['title']}",
|
|
"",
|
|
f"- ID: `{proposal['proposal_id']}`",
|
|
f"- Pattern: `{proposal['pattern_id']}`",
|
|
f"- Status: `{proposal['status']}`",
|
|
f"- Risk: `{proposal['risk_level']}`",
|
|
f"- Requires approval: `{str(proposal['requires_approval']).lower()}`",
|
|
"- Target files:",
|
|
]
|
|
)
|
|
lines.extend(f" - `{path}`" for path in proposal.get("target_files", []))
|
|
lines.append("- Verification:")
|
|
lines.extend(f" - `{command}`" for command in proposal.get("verification_commands", []))
|
|
lines.append("")
|
|
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 Daily SkillOps report from explicit-source adaptive evidence.")
|
|
parser.add_argument("skill_dir", nargs="?", default=".")
|
|
parser.add_argument("--source", help="Explicit curated source file to scan before rendering the daily report.")
|
|
parser.add_argument("--patterns-json", default="reports/user_patterns.json")
|
|
parser.add_argument("--proposals-json", default="reports/adaptation_proposals.json")
|
|
parser.add_argument("--output-json")
|
|
parser.add_argument("--output-md")
|
|
parser.add_argument("--min-support", type=int, default=2)
|
|
parser.add_argument("--generated-at", default=utc_now())
|
|
parser.add_argument("--allow-history-source", action="store_true")
|
|
parser.add_argument("--no-refresh-source-reports", action="store_true")
|
|
args = parser.parse_args()
|
|
|
|
skill_dir = Path(args.skill_dir).resolve()
|
|
report = build_report(
|
|
skill_dir,
|
|
args.generated_at,
|
|
source=Path(args.source) if args.source else None,
|
|
min_support=args.min_support,
|
|
allow_history_source=args.allow_history_source,
|
|
patterns_json=Path(args.patterns_json),
|
|
proposals_json=Path(args.proposals_json),
|
|
write_source_reports=not args.no_refresh_source_reports,
|
|
)
|
|
output_json = resolve_output(skill_dir, args.output_json) if args.output_json else default_daily_path(skill_dir, args.generated_at, "json")
|
|
output_md = resolve_output(skill_dir, args.output_md) if args.output_md else default_daily_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()
|