Add first-class skill interpretation report

This commit is contained in:
yaojingang
2026-06-15 21:34:45 +08:00
parent 5495734e7e
commit 038891715d
58 changed files with 4255 additions and 613 deletions
+1
View File
@@ -34,6 +34,7 @@ DEFAULT_TARGETS = [
"architecture-maintainability-check",
"yao-cli-check",
"skill-overview-check",
"skill-interpretation-check",
"skill-report-metrics-check",
"skill-report-charts-check",
"html-rendering-check",
+25 -16
View File
@@ -21,6 +21,7 @@ from render_reference_scan import parse_reference, render_reference_scan
from render_reference_synthesis import render_reference_synthesis
from render_review_studio import render_review_studio
from render_review_viewer import render_review_viewer
from render_skill_interpretation import render_skill_interpretation
from render_skill_overview import render_skill_overview
from render_system_model import render_system_model
@@ -73,19 +74,20 @@ README_TEMPLATE = """# {title}
4. Review `reports/intent-confidence.md` to see whether the real job, inputs, outputs, and exclusions are clear enough yet.
5. Open `reports/reference-synthesis.md` to see the GitHub benchmarks plus curated official, research, and principle tracks in one place.
6. Follow the workflow steps in `SKILL.md`.
7. Check `reports/skill-overview.html` for the generated bilingual HTML skill audit report: overview, metrics, capability profile, principle, contract, quality, risk, assets, and iteration roadmap. It defaults to Simplified Chinese and includes an English switch in the top right.
8. Open `reports/review-studio.html` for the one-page Review Studio 2.0 gate view.
9. Record source-line reviewer comments in `reports/review_annotations.md` when review needs follow-up.
10. Open `reports/review-viewer.html` for a compact visual review of the package.
11. Check `reports/output-risk-profile.md` to see likely output mistakes and self-repair checks.
12. Check `reports/artifact-design-profile.md` to see the intended artifact direction, layout patterns, visual quality gates, and anti-patterns.
13. Check `reports/prompt-quality-profile.md` to see the need model, RTF-to-skill mapping, complexity, and prompt-facing quality matrix.
14. Review `reports/skill-ir.json` for the platform-neutral Skill IR contract before platform-specific packaging.
15. Review `reports/compiled_targets.md` to see how Skill IR compiles into OpenAI, Claude, generic, and Agent Skills compatible target contracts.
16. Review `reports/iteration-directions.md` for the three most valuable next moves.
17. Review `reports/system-model.md` to understand the boundary, feedback loops, drift watch, failure map, and highest-leverage next changes.
18. Review `reports/adoption_drift_report.md` to see local-first metadata-only adoption and drift signals.
19. Review `reports/review_waivers.md` to see human reviewer risk approvals and expiry dates.
7. Open `reports/skill-interpretation.html` first for the first-class bilingual interpretation report: role, principle, scenarios, trigger, inputs, outputs, highlights, risks, assets, and upgrade directions. It defaults to Simplified Chinese and includes an English switch in the top right.
8. Check `reports/skill-overview.html` for the generated bilingual HTML skill audit report: overview, metrics, capability profile, principle, contract, quality, risk, assets, and iteration roadmap.
9. Open `reports/review-studio.html` for the one-page Review Studio 2.0 gate view.
10. Record source-line reviewer comments in `reports/review_annotations.md` when review needs follow-up.
11. Open `reports/review-viewer.html` for a compact visual review of the package.
12. Check `reports/output-risk-profile.md` to see likely output mistakes and self-repair checks.
13. Check `reports/artifact-design-profile.md` to see the intended artifact direction, layout patterns, visual quality gates, and anti-patterns.
14. Check `reports/prompt-quality-profile.md` to see the need model, RTF-to-skill mapping, complexity, and prompt-facing quality matrix.
15. Review `reports/skill-ir.json` for the platform-neutral Skill IR contract before platform-specific packaging.
16. Review `reports/compiled_targets.md` to see how Skill IR compiles into OpenAI, Claude, generic, and Agent Skills compatible target contracts.
17. Review `reports/iteration-directions.md` for the three most valuable next moves.
18. Review `reports/system-model.md` to understand the boundary, feedback loops, drift watch, failure map, and highest-leverage next changes.
19. Review `reports/adoption_drift_report.md` to see local-first metadata-only adoption and drift signals.
20. Review `reports/review_waivers.md` to see human reviewer risk approvals and expiry dates.
## Honest Boundaries
@@ -109,6 +111,7 @@ README_TEMPLATE = """# {title}
- `reports/system-model.md`: systems-thinking model for boundary, feedback loops, drift, failure patterns, and leverage points
- `reports/skill-ir.json`: platform-neutral 2.0 Skill IR contract for trigger, workflow, resources, evals, risk, and governance
- `reports/compiled_targets.md`: target compiler report showing generated contracts, adapter modes, preserved semantics, warnings, and unsupported features
- `reports/skill-interpretation.html`: first-class bilingual interpretation report for role, principle, scenarios, trigger, inputs, outputs, quality evidence, risks, assets, highlights, and upgrade directions
- `reports/skill-overview.html`: white-background bilingual HTML skill audit report with sticky four-character Chinese navigation, a top-right language switch, metrics, SVG charts, contract boundary, quality review, risk governance, assets, and iteration roadmap
- `reports/review-studio.html`: Review Studio 2.0 gate page for intent, trigger, output eval, context, runtime conformance, trust, atlas, and release readiness
- `reports/review-viewer.html`: compact review page for architecture, usage, feedback, and next steps
@@ -228,23 +231,26 @@ def build_manifest(name: str, mode: str, archetype: str) -> dict:
def build_report_view(artifacts: dict) -> dict:
html_report = artifacts.get("skill_overview_html", "")
json_report = artifacts.get("skill_overview_json", "")
interpretation_report = artifacts.get("skill_interpretation_html", "")
system_model = artifacts.get("system_model_md", "")
review_studio = artifacts.get("review_studio_html", "")
return {
"title": "Skill 总结报告",
"html_report": html_report,
"json_report": json_report,
"interpretation_report": interpretation_report,
"system_model": system_model,
"review_studio": review_studio,
"message": (
f"Skill 已创建完成。建议先打开总结报告:{html_report}"
"它会展示这个 Skill 的概述、指标、原理、触发边界、输入输出、目标编译、质量评估、风险治理、包体资产和升级路线"
f"Skill 已创建完成。建议先打开解读报告:{interpretation_report};再查看总结报告:{html_report}"
"解读报告会用中文简体默认展示这个 Skill 的作用、原理、使用场景、触发方式、输入输出、亮点和后续升级方向"
"总结报告会展示概述、指标、原理、触发边界、输入输出、目标编译、质量评估、风险治理、包体资产和升级路线;"
f"然后打开 Review Studio 2.0{review_studio},检查意图、触发、输出评测、运行一致性、信任和发布闸门。"
"后续 reviewer 的文件级或行级意见可以记录到 reports/review_annotations.md。"
"如需审查平台适配细节,请打开 reports/compiled_targets.md。"
"报告默认使用中文简体,右上角可以切换英文版。"
),
"next_action": "Open reports/skill-overview.html before editing more files.",
"next_action": "Open reports/skill-interpretation.html before editing more files.",
}
@@ -359,6 +365,7 @@ def initialize_skill(
review_waivers = render_review_waivers(root)
review_annotations = render_review_annotations(root)
overview = render_skill_overview(root)
interpretation = render_skill_interpretation(root)
review_viewer = render_review_viewer(root)
review_studio = render_review_studio(root)
artifacts = {
@@ -369,6 +376,8 @@ def initialize_skill(
"intent_context_json": intent_confidence["artifacts"]["context_json"],
"skill_overview_html": overview["artifacts"]["html"],
"skill_overview_json": overview["artifacts"]["json"],
"skill_interpretation_html": interpretation["artifacts"]["html"],
"skill_interpretation_json": interpretation["artifacts"]["json"],
"intent_dialogue_md": intent_dialogue["artifacts"]["markdown"],
"intent_dialogue_json": intent_dialogue["artifacts"]["json"],
"reference_scan_md": reference_scan["artifacts"]["markdown"],
+1
View File
@@ -248,6 +248,7 @@ def render_html(report: dict[str, Any]) -> str:
"warn_count",
"missing_count",
"extension_track_count",
"extension_covered_count",
"extension_partial_count",
"extension_planned_count",
"adaptive_extension_ready",
+108
View File
@@ -0,0 +1,108 @@
#!/usr/bin/env python3
import argparse
import json
from pathlib import Path
from render_skill_overview import render_html
from skill_report_model import build_report_model
SCRIPT_INTERFACE = "cli"
SCRIPT_INTERFACE_REASON = "Renders the first-class skill interpretation report while reusing the Skill Overview v2 model and layout."
def build_interpretation_model(skill_dir: Path) -> dict:
summary = build_report_model(skill_dir)
contract = dict(summary.get("report_contract", {}))
contract.update(
{
"schema_version": "2.0",
"report_kind": "skill-interpretation",
"canonical_overview_report": "reports/skill-overview.html",
"html_report": "reports/skill-interpretation.html",
"json_report": "reports/skill-interpretation.json",
"layout": "kami-white-audit-v2",
"default_language": "zh-CN",
"languages": ["zh-CN", "en"],
"purpose": "Explain the generated skill's role, principles, usage scenarios, trigger contract, inputs, outputs, quality evidence, risks, assets, highlights, and next upgrade directions.",
}
)
summary["report_contract"] = contract
summary["interpretation_contract"] = {
"schema_version": "2.0",
"source_model": "skill-overview-v2",
"source_model_reused": True,
"overview_report": "reports/skill-overview.html",
"html_report": "reports/skill-interpretation.html",
"json_report": "reports/skill-interpretation.json",
"default_language": "zh-CN",
"languages": ["zh-CN", "en"],
"includes": [
"skill role",
"principles",
"usage scenarios",
"trigger contract",
"inputs and outputs",
"quality evidence",
"risk governance",
"package assets",
"highlights",
"upgrade roadmap",
],
}
deliverables = summary.get("skill_summary", {}).get("deliverables", [])
for artifact in ["reports/skill-interpretation.html", "reports/skill-interpretation.json"]:
if artifact not in deliverables:
deliverables.append(artifact)
if "skill_summary" in summary:
summary["skill_summary"]["deliverables"] = deliverables
return summary
def render_skill_interpretation(skill_dir: Path, output_html: Path | None = None, output_json: Path | None = None) -> dict:
skill_dir = skill_dir.resolve()
reports_dir = skill_dir / "reports"
reports_dir.mkdir(parents=True, exist_ok=True)
output_html = output_html or reports_dir / "skill-interpretation.html"
output_json = output_json or reports_dir / "skill-interpretation.json"
summary = build_interpretation_model(skill_dir)
output_html.write_text(render_html(summary), encoding="utf-8")
output_json.write_text(json.dumps(summary, ensure_ascii=False, indent=2), encoding="utf-8")
return {
"ok": True,
"skill_dir": str(skill_dir),
"artifacts": {
"html": str(output_html),
"json": str(output_json),
"overview_html": str(skill_dir / "reports" / "skill-overview.html"),
},
"summary": {
"name": summary.get("name"),
"report_kind": summary.get("report_contract", {}).get("report_kind"),
"default_language": summary.get("report_contract", {}).get("default_language"),
"section_count": len(summary.get("report_contract", {}).get("nav_labels", [])),
"source_model_reused": summary.get("interpretation_contract", {}).get("source_model_reused"),
},
}
def main() -> None:
parser = argparse.ArgumentParser(description="Render the first-class HTML skill interpretation report for a skill package.")
parser.add_argument("skill_dir", nargs="?", default=".")
parser.add_argument("--output-html")
parser.add_argument("--output-json")
args = parser.parse_args()
result = render_skill_interpretation(
Path(args.skill_dir),
Path(args.output_html).resolve() if args.output_html else None,
Path(args.output_json).resolve() if args.output_json else None,
)
print(json.dumps(result, ensure_ascii=False, indent=2))
if __name__ == "__main__":
main()
+26 -12
View File
@@ -301,23 +301,36 @@ def build_coverage(skill_dir: Path, generated_at: str) -> dict[str, Any]:
for key, path_a, path_b, path_c, condition, current in recommended_prs
]
interpretation_paths = [
"reports/skill-overview.html",
"reports/skill-overview.json",
"scripts/render_skill_overview.py",
"scripts/render_skill_interpretation.py",
"schemas/skill-interpretation.schema.json",
"tests/verify_skill_interpretation.py",
]
interpretation_ready = paths_exist(skill_dir, interpretation_paths)
interpretation_status = "covered" if interpretation_ready else "partial"
interpretation_current = (
"Skill Overview v2 is canonical and mirrored as first-class skill-interpretation HTML/JSON with schema and tests."
if interpretation_ready
else "Skill Overview v2 already covers much of the explainer experience, but dedicated skill-interpretation JSON/HTML artifacts are not first-class yet."
)
interpretation_next_action = (
"Keep overview and interpretation contracts in lockstep when report sections, metrics, or layout semantics change."
if interpretation_ready
else "Decide whether overview v2 is the canonical interpretation surface; if not, add a dedicated schema, renderer, and CJK/path-safety tests."
)
extension_tracks = [
build_extension_track(
key="skill-interpretation-report",
label="Skill Interpretation Report",
status="partial",
status=interpretation_status,
objective="User-facing deep interpretation report explains use cases, triggers, inputs, outputs, workflow, principles, boundaries, quality gates, examples, and next iterations.",
current="Skill Overview v2 already covers much of the explainer experience, but dedicated skill-interpretation JSON/MD/HTML artifacts are not first-class yet.",
current=interpretation_current,
target="Either keep skill-overview as the canonical interpretation report with an explicit contract, or split a dedicated reports/skill-interpretation.* renderer and tests.",
artifact_paths=[
"reports/skill-overview.html",
"reports/skill-overview.json",
"scripts/render_skill_overview.py",
"scripts/render_skill_interpretation.py",
"schemas/skill-interpretation.schema.json",
"tests/verify_skill_interpretation.py",
],
next_action="Decide whether overview v2 is the canonical interpretation surface; if not, add a dedicated schema, renderer, and CJK/path-safety tests.",
artifact_paths=interpretation_paths,
next_action=interpretation_next_action,
skill_dir=skill_dir,
),
]
@@ -412,7 +425,7 @@ def build_coverage(skill_dir: Path, generated_at: str) -> dict[str, Any]:
"reference_extension_tracks": extension_tracks,
"next_highest_leverage": [
"Close the four world-class evidence ledger entries with accepted human or external evidence.",
"Clarify whether Skill Overview v2 is the canonical interpretation report or split a dedicated skill-interpretation renderer.",
"Keep the first-class skill interpretation report and Skill Overview v2 contract synchronized as the report model evolves.",
"Start adaptive self-iteration as explicit-source, proposal-only, approval-gated work; do not scan private logs by default.",
"Keep the blueprint coverage report in CI so 2.0 plan drift is visible.",
],
@@ -468,6 +481,7 @@ def render_markdown(report: dict[str, Any]) -> str:
f"- missing: `{summary['missing_count']}`",
f"- warn: `{summary['warn_count']}`",
f"- reference extensions: `{summary['extension_track_count']}`",
f"- extension covered: `{summary['extension_covered_count']}`",
f"- extension partial: `{summary['extension_partial_count']}`",
f"- extension planned: `{summary['extension_planned_count']}`",
f"- adaptive extension ready: `{str(summary['adaptive_extension_ready']).lower()}`",
+4 -1
View File
@@ -254,6 +254,9 @@ def render_html(summary: dict) -> str:
output_execution_summary = output_execution.get("summary", {})
output_review = summary.get("output_review_adjudication", {})
output_review_summary = output_review.get("summary", {})
report_contract = summary.get("report_contract", {})
html_report_path = str(report_contract.get("html_report") or "reports/skill-overview.html")
open_report_message = f"创建完成后建议先打开 {html_report_path},再继续扩展包体。"
hero_meta = [
(f"技能名称:{summary['name']}", f"Skill name: {summary['name']}"),
(f"成熟度:{mode_zh(metadata.get('maturity_tier', 'scaffold'))}", f"Maturity: {metadata.get('maturity_tier', 'scaffold')}"),
@@ -340,7 +343,7 @@ def render_html(summary: dict) -> str:
</div>
<aside class="hero-card">
<h3>{bi_span("核心判断", "Core reading")}</h3>
{render_list([skill.get("core_value", ""), skill.get("audience", ""), "创建完成后建议先打开 reports/skill-overview.html,再继续扩展包体。"])}
{render_list([skill.get("core_value", ""), skill.get("audience", ""), open_report_message])}
</aside>
</div>
<div class="score-strip" aria-label="报告关键指标">{score_strip}</div>
+3
View File
@@ -261,6 +261,9 @@ def en_for(text: str) -> str:
return TEXT_EN[value]
if value in METRIC_LABEL_EN:
return METRIC_LABEL_EN[value]
if value.startswith("创建完成后建议先打开 ") and value.endswith(",再继续扩展包体。"):
path = value.removeprefix("创建完成后建议先打开 ").removesuffix(",再继续扩展包体。")
return f"After creation, open {path} before expanding the package further."
if value.startswith("交付结果:"):
return "Deliverables: " + value.removeprefix("交付结果:")
if value.startswith("能力类型:"):
+10 -7
View File
@@ -387,7 +387,7 @@ def skill_overview_css() -> str:
}
.metrics-primary {
display: grid;
grid-template-columns: minmax(420px, 1fr) minmax(360px, 0.88fr);
grid-template-columns: minmax(0, 1.2fr) minmax(320px, 0.8fr);
gap: 22px;
align-items: start;
}
@@ -455,7 +455,7 @@ def skill_overview_css() -> str:
margin-top: 2px;
}
.metric-detail-grid {
grid-template-columns: repeat(2, minmax(0, 1fr));
grid-template-columns: repeat(auto-fit, minmax(min(100%, 340px), 1fr));
align-items: stretch;
}
.list, .compact-list, .step-list {
@@ -485,18 +485,20 @@ def skill_overview_css() -> str:
}
.metric-card {
display: grid;
grid-template-columns: minmax(96px, 118px) minmax(0, 1fr);
gap: 18px;
grid-template-columns: 1fr;
gap: 14px;
align-content: start;
min-height: 0;
}
.metric-card-head {
display: grid;
align-content: start;
display: flex;
gap: 14px;
align-items: flex-start;
justify-content: space-between;
}
.metric-card strong {
display: block;
margin: 8px 0 10px;
margin: 0;
color: var(--brand);
font-family: var(--mono);
font-size: 2rem;
@@ -507,6 +509,7 @@ def skill_overview_css() -> str:
.metric-label {
color: var(--muted);
font-size: 13px;
line-height: 1.45;
}
.metric-card-body {
min-width: 0;
+1
View File
@@ -544,6 +544,7 @@ def build_report_model(skill_dir: Path) -> dict:
"reports/review_waivers.md",
"reports/review_annotations.md",
"reports/review-studio.html",
"reports/skill-interpretation.html",
"reports/skill-overview.html",
]
if (skill_dir / "reports" / "runtime_permission_probes.md").exists():
+4
View File
@@ -29,6 +29,7 @@ from yao_cli_report_commands import (
command_review_viewer,
command_skill_os2_audit,
command_skill_os2_coverage,
command_skill_interpretation,
command_skill_report,
command_system_model,
command_world_class_claim_guard,
@@ -184,6 +185,7 @@ def command_report(args: argparse.Namespace) -> int:
run_script("render_skill_os2_coverage.py", [str(ROOT)]),
run_script("render_benchmark_reproducibility.py", [str(ROOT)]),
run_script("render_skill_overview.py", [str(ROOT)]),
run_script("render_skill_interpretation.py", [str(ROOT)]),
run_script("render_review_viewer.py", [str(ROOT)]),
]
)
@@ -224,6 +226,8 @@ def command_report(args: argparse.Namespace) -> int:
"skill_os2_coverage": "reports/skill_os2_coverage.json",
"benchmark_reproducibility": "reports/benchmark_reproducibility.json",
"skill_overview": "reports/skill-overview.json",
"skill_interpretation": "reports/skill-interpretation.json",
"skill_interpretation_html": "reports/skill-interpretation.html",
"review_viewer": "reports/review-viewer.json",
"review_viewer_html": "reports/review-viewer.html",
},
+4
View File
@@ -264,8 +264,11 @@ def command_quickstart(args: argparse.Namespace) -> int:
sys.stderr.write("I will keep the underlying benchmark evidence in the reviewer reports and move ahead with this recommendation.\n")
if payload.get("report_view", {}).get("html_report"):
sys.stderr.write(f"Skill report: {payload['report_view']['html_report']}\n")
if payload.get("report_view", {}).get("interpretation_report"):
sys.stderr.write(f"Skill interpretation: {payload['report_view']['interpretation_report']}\n")
next_steps = [
"Open reports/skill-interpretation.html to review the generated Skill interpretation report.",
"Open reports/skill-overview.html to review the generated Skill audit report.",
"Open reports/intent-dialogue.md and tighten the real job, outputs, and exclusions.",
"Open reports/review-studio.html to inspect the Review Studio 2.0 gate view before release.",
@@ -303,6 +306,7 @@ def command_quickstart(args: argparse.Namespace) -> int:
"artifact_design_profile": payload.get("artifacts", {}).get("artifact_design_profile_md"),
"prompt_quality_profile": payload.get("artifacts", {}).get("prompt_quality_profile_md"),
"system_model": payload.get("artifacts", {}).get("system_model_md"),
"skill_interpretation": payload.get("artifacts", {}).get("skill_interpretation_html"),
"review_studio": payload.get("artifacts", {}).get("review_studio_html"),
"review_viewer": payload.get("artifacts", {}).get("review_viewer_html"),
},
+9
View File
@@ -144,6 +144,15 @@ def build_parser(command_handlers: dict[str, Callable[[argparse.Namespace], int]
skill_report_cmd.add_argument("--output-json")
skill_report_cmd.set_defaults(func=_handler(command_handlers, "command_skill_report"))
skill_interpretation_cmd = subparsers.add_parser(
"skill-interpretation",
help="Render the first-class skill interpretation report for a skill package.",
)
skill_interpretation_cmd.add_argument("skill_dir", nargs="?", default=".")
skill_interpretation_cmd.add_argument("--output-html")
skill_interpretation_cmd.add_argument("--output-json")
skill_interpretation_cmd.set_defaults(func=_handler(command_handlers, "command_skill_interpretation"))
review_viewer_cmd = subparsers.add_parser("review-viewer", help="Render a compact HTML review page for a skill package.")
review_viewer_cmd.add_argument("skill_dir", nargs="?", default=".")
review_viewer_cmd.add_argument("--output-html")
+4
View File
@@ -41,6 +41,10 @@ def command_skill_report(args: argparse.Namespace) -> int:
return render_skill_report_command(args, "render_skill_overview.py", markdown=False)
def command_skill_interpretation(args: argparse.Namespace) -> int:
return render_skill_report_command(args, "render_skill_interpretation.py", markdown=False)
def command_review_viewer(args: argparse.Namespace) -> int:
return render_skill_report_command(args, "render_review_viewer.py", markdown=False)