chore: modularize meta skill report surfaces

This commit is contained in:
yaojingang
2026-06-13 19:01:44 +08:00
parent 3fb08802e9
commit 5ba1c93a09
34 changed files with 1960 additions and 1258 deletions
+107 -229
View File
@@ -18,6 +18,9 @@ except ImportError: # pragma: no cover
compute_permission_governance_status = None
trust_script_inventory = None
from review_studio_formatting import registry_package_summary, render_kv_grid
from review_studio_layout import render_review_nav, review_studio_css
ROOT = Path(__file__).resolve().parent.parent
@@ -1076,24 +1079,7 @@ def render_html(report: dict[str, Any]) -> str:
frontmatter = report["data"]["frontmatter"]
title = overview.get("display_name") or overview.get("title") or frontmatter.get("name") or manifest.get("name") or "Skill"
description = overview.get("description") or frontmatter.get("description", "")
nav = [
("#overview", "审查总览"),
("#intent", "意图画布"),
("#trigger", "触发实验"),
("#output", "输出实验"),
("#actions", "修复动作"),
("#annotations", "审查批注"),
("#runtime", "运行矩阵"),
("#trust", "信任报告"),
("#permissions", "权限批准"),
("#permission-probes", "权限探针"),
("#atlas", "组合治理"),
("#telemetry", "运营回路"),
("#waivers", "人工批准"),
("#registry", "注册审计"),
("#release", "发布路线"),
]
nav_html = "".join(f"<a href='{href}'>{label}</a>" for href, label in nav)
nav_html = render_review_nav()
gates_html = render_gate_list(gates)
metrics_html = render_insights(insights)
blockers_html = render_issue_list("阻断事项", blockers)
@@ -1119,6 +1105,95 @@ def render_html(report: dict[str, Any]) -> str:
)
registry_package = report["data"]["registry"].get("package", {})
package_summary = report["data"]["package_verification"].get("summary", {})
atlas_panel = render_kv_grid(
atlas_summary,
[
"skill_count",
"actionable_skill_count",
"actionable_route_collision_count",
"actionable_owner_gap_count",
"actionable_stale_count",
"non_actionable_issue_count",
],
"skill atlas summary missing",
)
output_panel = render_kv_grid(
output_summary,
["case_count", "with_skill_pass_rate", "baseline_pass_rate", "delta", "gate_pass", "failure_count"],
"output eval scorecard missing",
)
execution_panel = render_kv_grid(
output_execution_summary,
[
"variant_run_count",
"command_executed_count",
"model_executed_count",
"recorded_fixture_count",
"timing_observed_count",
"token_estimated_count",
],
"output execution report missing",
)
blind_panel = render_kv_grid(
output_blind_summary,
["pair_count", "answer_key_separate", "with_skill_hidden_count"],
"blind A/B review pack missing",
)
review_panel = render_kv_grid(
output_review_summary,
["pair_count", "judgment_count", "pending_count", "agreement_count", "disagreement_count", "invalid_decision_count"],
"review adjudication report missing",
)
conformance_panel = render_kv_grid(
conformance_summary,
["target_count", "pass_count", "fail_count", "warning_count", "failure_count"],
"runtime conformance matrix missing",
)
compiled_panel = render_kv_grid(
compiled_summary,
["target_count", "pass_count", "warn_count", "block_count", "failure_count"],
"compiled target report missing",
)
trust_panel = render_kv_grid(
trust_summary,
["secret_findings", "script_count", "network_script_count", "help_smoke_failed_count", "package_sha256"],
"security trust report missing",
)
runtime_boundary_panel = render_kv_grid(
runtime_permissions_summary,
["target_count", "pass_count", "native_enforcement_count", "metadata_fallback_count", "residual_risk_count", "failure_count"],
"runtime permission probe summary missing",
)
adoption_panel = render_kv_grid(
adoption_summary,
["event_count", "adoption_rate", "missed_trigger_count", "bad_output_count", "risk_band"],
"no adoption drift summary",
)
waiver_panel = render_kv_grid(
waiver_summary,
["waiver_count", "active_count", "expired_count", "invalid_count", "covered_gate_count"],
"no review waiver summary",
)
registry_panel = render_kv_grid(
registry_package_summary(registry_package),
[
"name",
"version",
"maturity",
"owner",
"license",
"trust_level",
"targets",
"compatibility_pass_count",
"archive_sha256",
],
"registry package metadata missing",
)
package_panel = render_kv_grid(
package_summary,
["target_count", "adapter_count", "archive_present", "archive_entry_count", "failure_count", "warning_count", "archive_sha256"],
"package verification missing",
)
evidence_html = "".join(
f"<li><strong>{html.escape(key)}</strong><span>{html.escape(value)}</span></li>"
for key, value in report["evidence_paths"].items()
@@ -1130,204 +1205,7 @@ def render_html(report: dict[str, Any]) -> str:
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>{html.escape(str(title))} Review Studio 2.0</title>
<style>
:root {{
--ink: #1B365D;
--text: #24201d;
--muted: #746d66;
--line: #e7ded2;
--soft: #faf8f5;
--pass: #1e6b52;
--warn: #9a6718;
--block: #9b2c2c;
}}
* {{ box-sizing: border-box; }}
html {{ scroll-behavior: smooth; }}
body {{
margin: 0;
background: #ffffff;
color: var(--text);
font-family: Georgia, "Times New Roman", "Songti SC", serif;
line-height: 1.58;
}}
nav {{
position: sticky;
top: 0;
z-index: 10;
display: flex;
gap: 4px;
justify-content: center;
flex-wrap: wrap;
padding: 10px 16px;
background: rgba(255,255,255,0.94);
border-bottom: 1px solid var(--line);
backdrop-filter: blur(10px);
}}
nav a {{
color: var(--ink);
text-decoration: none;
font-size: 14px;
padding: 7px 10px;
border-radius: 6px;
}}
nav a:hover {{ background: var(--soft); }}
main {{ max-width: 1180px; margin: 0 auto; padding: 44px 28px 76px; }}
header {{ border-bottom: 1px solid var(--line); padding-bottom: 28px; margin-bottom: 28px; }}
.eyebrow {{ color: var(--ink); font-size: 14px; letter-spacing: .08em; text-transform: uppercase; }}
h1, h2, h3 {{ color: var(--text); font-weight: 500; margin: 0; letter-spacing: 0; }}
h1 {{ font-size: clamp(34px, 5vw, 64px); line-height: 1.03; max-width: 920px; margin-top: 12px; }}
h2 {{ font-size: 30px; margin-bottom: 14px; }}
h3 {{ font-size: 19px; }}
p {{ margin: 0; }}
.lede {{ max-width: 820px; color: var(--muted); font-size: 20px; margin-top: 18px; }}
.decision {{
display: inline-flex;
align-items: baseline;
gap: 12px;
margin-top: 24px;
padding: 12px 16px;
border: 1px solid var(--line);
border-radius: 8px;
color: var(--ink);
background: var(--soft);
}}
.decision strong {{ font-size: 28px; }}
section {{ padding: 30px 0; border-bottom: 1px solid var(--line); scroll-margin-top: 76px; }}
.metrics, .gates {{
display: grid;
grid-template-columns: repeat(5, minmax(0, 1fr));
gap: 14px;
}}
.gates {{ grid-template-columns: repeat(4, minmax(0, 1fr)); }}
.metric, .gate {{
border: 1px solid var(--line);
border-radius: 8px;
padding: 16px;
background: #fff;
min-width: 0;
}}
.metric span, .gate span {{ display: block; color: var(--muted); font-size: 13px; }}
.metric strong {{ display: block; color: var(--ink); font-size: 34px; line-height: 1.1; margin: 8px 0; }}
.metric p, .gate p, .gate footer, .issues span, .evidence span {{ color: var(--muted); font-size: 14px; overflow-wrap: anywhere; }}
.gate {{ display: flex; flex-direction: column; gap: 10px; }}
.gate.pass {{ border-top: 4px solid var(--pass); }}
.gate.warn {{ border-top: 4px solid var(--warn); }}
.gate.block {{ border-top: 4px solid var(--block); }}
.gate footer {{ border-top: 1px solid var(--line); padding-top: 10px; }}
a {{ color: var(--ink); }}
.twocol {{
display: grid;
grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
gap: 22px;
align-items: start;
}}
.panel {{
border: 1px solid var(--line);
border-radius: 8px;
padding: 18px;
background: #fff;
}}
.panel p {{ color: var(--muted); }}
.issues, .evidence {{
list-style: none;
padding: 0;
margin: 0;
display: grid;
gap: 12px;
}}
.issues li, .evidence li {{
border-left: 3px solid var(--line);
padding-left: 12px;
display: grid;
gap: 3px;
}}
.muted {{ color: var(--muted); }}
.actions-grid {{
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 16px;
}}
.annotations-grid {{
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 16px;
}}
.action-card {{
border: 1px solid var(--line);
border-radius: 8px;
padding: 18px;
background: #fff;
display: grid;
gap: 10px;
min-width: 0;
}}
.action-card.warn {{ border-left: 4px solid var(--warn); }}
.action-card.block {{ border-left: 4px solid var(--block); }}
.annotation-card {{
border: 1px solid var(--line);
border-radius: 8px;
padding: 18px;
background: #fff;
display: grid;
gap: 10px;
min-width: 0;
}}
.annotation-card.warning {{ border-left: 4px solid var(--warn); }}
.annotation-card.blocker {{ border-left: 4px solid var(--block); }}
.annotation-card.resolved {{ opacity: .72; }}
.action-card span,
.annotation-card span,
.action-card small,
.annotation-card small,
.action-card footer,
.annotation-card footer,
.action-card dd {{
color: var(--muted);
font-size: 14px;
overflow-wrap: anywhere;
}}
.annotation-card dd {{ color: var(--muted); font-size: 14px; overflow-wrap: anywhere; }}
.action-card dl, .annotation-card dl {{
display: grid;
grid-template-columns: 80px minmax(0, 1fr);
gap: 6px 10px;
margin: 0;
}}
.action-card dt, .annotation-card dt {{ color: var(--ink); font-size: 14px; }}
.action-card dd, .annotation-card dd {{ margin: 0; }}
.source-ref-list {{
list-style: none;
padding: 0;
margin: 0;
display: grid;
gap: 6px;
}}
.source-ref-list li {{
display: grid;
gap: 2px;
min-width: 0;
padding: 8px 0 0;
border-top: 1px solid var(--line);
}}
.source-ref-list a,
.source-ref-list span {{
overflow-wrap: anywhere;
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
font-size: 13px;
}}
.source-ref-list small {{
font-size: 12px;
color: var(--muted);
}}
code {{
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
font-size: 13px;
}}
@media (max-width: 980px) {{
.metrics, .gates, .twocol, .actions-grid, .annotations-grid {{ grid-template-columns: 1fr; }}
main {{ padding: 32px 18px 60px; }}
nav {{ justify-content: flex-start; overflow-x: auto; flex-wrap: nowrap; }}
nav a {{ flex: 0 0 auto; }}
}}
{review_studio_css()}
</style>
</head>
<body>
@@ -1383,17 +1261,17 @@ def render_html(report: dict[str, Any]) -> str:
<section id="trigger" class="twocol">
<div class="panel"><h2>触发实验</h2><p>{html.escape(gates[1]['detail'])}</p></div>
<div class="panel"><h2>组合治理</h2><p>{html.escape(str(atlas_summary))}</p></div>
<div class="panel"><h2>组合治理</h2>{atlas_panel}</div>
</section>
<section id="output" class="twocol">
<div class="panel"><h2>输出实验</h2><p>{html.escape(str(output_summary))}</p></div>
<div class="panel"><h2>执行证据</h2><p>{html.escape(str(output_execution_summary or 'output execution report missing'))}</p></div>
<div class="panel"><h2>输出实验</h2>{output_panel}</div>
<div class="panel"><h2>执行证据</h2>{execution_panel}</div>
</section>
<section class="twocol">
<div class="panel"><h2>盲评包</h2><p>{html.escape(str(output_blind_summary or 'blind A/B review pack missing'))}</p></div>
<div class="panel"><h2>审定报告</h2><p>{html.escape(str(output_review_summary or 'review adjudication report missing'))}</p></div>
<div class="panel"><h2>盲评包</h2>{blind_panel}</div>
<div class="panel"><h2>审定报告</h2>{review_panel}</div>
</section>
<section class="twocol">
@@ -1407,8 +1285,8 @@ def render_html(report: dict[str, Any]) -> str:
</section>
<section id="runtime" class="twocol">
<div class="panel"><h2>运行矩阵</h2><p>{html.escape(str(conformance_summary))}</p></div>
<div class="panel"><h2>目标编译</h2><p>{html.escape(str(compiled_summary or 'compiled target report missing'))}</p></div>
<div class="panel"><h2>运行矩阵</h2>{conformance_panel}</div>
<div class="panel"><h2>目标编译</h2>{compiled_panel}</div>
</section>
<section class="twocol">
@@ -1417,7 +1295,7 @@ def render_html(report: dict[str, Any]) -> str:
</section>
<section id="trust" class="twocol">
<div class="panel"><h2>信任报告</h2><p>{html.escape(str(trust_summary))}</p></div>
<div class="panel"><h2>信任报告</h2>{trust_panel}</div>
<div class="panel"><h2>安全边界</h2><p>高风险 secret、远程 inline execution、缺失依赖策略或无法解释的脚本接口应阻断 governed release。</p></div>
</section>
@@ -1428,7 +1306,7 @@ def render_html(report: dict[str, Any]) -> str:
<section id="permission-probes" class="twocol">
<div class="panel"><h2>权限探针</h2><p>{html.escape(gate_details.get('permission-runtime', 'runtime permission probes missing'))}</p></div>
<div class="panel"><h2>运行边界</h2><p>{html.escape(str(runtime_permissions_summary or 'runtime permission probe summary missing'))}</p></div>
<div class="panel"><h2>运行边界</h2>{runtime_boundary_panel}</div>
</section>
<section id="atlas" class="twocol">
@@ -1438,22 +1316,22 @@ def render_html(report: dict[str, Any]) -> str:
<section id="telemetry" class="twocol">
<div class="panel"><h2>运营回路</h2><p>{html.escape(gate_details.get('operations-loop', 'adoption drift report missing'))}</p></div>
<div class="panel"><h2>漂移信号</h2><p>{html.escape(str(adoption_summary or 'no adoption drift summary'))}</p></div>
<div class="panel"><h2>漂移信号</h2>{adoption_panel}</div>
</section>
<section id="waivers" class="twocol">
<div class="panel"><h2>人工批准</h2><p>{html.escape(gate_details.get('review-waivers', 'review waiver ledger missing'))}</p></div>
<div class="panel"><h2>批准台账</h2><p>{html.escape(str(waiver_summary or 'no review waiver summary'))}</p></div>
<div class="panel"><h2>批准台账</h2>{waiver_panel}</div>
</section>
<section id="registry" class="twocol">
<div class="panel"><h2>注册审计</h2><p>{html.escape(gate_details.get('registry-audit', 'registry audit missing'))}</p></div>
<div class="panel"><h2>包体元数据</h2><p>{html.escape(str(registry_package))}</p></div>
<div class="panel"><h2>包体元数据</h2>{registry_panel}</div>
</section>
<section id="release" class="twocol">
<div class="panel"><h2>发布路线</h2><p>{html.escape(gate_details.get('release-notes', 'release notes missing'))}</p></div>
<div class="panel"><h2>包体验证</h2><p>{html.escape(str(package_summary or 'package verification missing'))}</p></div>
<div class="panel"><h2>包体验证</h2>{package_panel}</div>
</section>
</main>
</body>
+5 -620
View File
@@ -5,6 +5,7 @@ import json
from pathlib import Path
from skill_report_charts import render_chart_set
from skill_report_layout import render_language_switch, render_report_nav, skill_overview_css, skill_overview_script
from skill_report_model import REPORT_NAV_V2, build_report_model
@@ -279,15 +280,8 @@ def render_roadmap(items: list[dict]) -> str:
def render_html(summary: dict) -> str:
charts = render_chart_set(summary)
nav_html = "".join(
f"<a href=\"#{item['href']}\">{bi_span(item['label'], item['label_en'])}</a>" for item in REPORT_NAV_V2
)
language_switch = (
'<div class="language-switch" aria-label="语言切换">'
'<button type="button" data-set-lang="zh-CN" aria-pressed="true">简体</button>'
'<button type="button" data-set-lang="en" aria-pressed="false">EN</button>'
"</div>"
)
nav_html = render_report_nav(REPORT_NAV_V2)
language_switch = render_language_switch()
skill = summary.get("skill_summary", {})
metadata = summary.get("metadata", {})
scorecard = summary.get("scorecard", {})
@@ -359,580 +353,7 @@ def render_html(summary: dict) -> str:
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>{html.escape(summary['name'])} Skill 生成审计报告</title>
<style>
:root {{
--paper: #ffffff;
--wash: #f8fafc;
--wash-strong: #f2f5f8;
--line: #e6e0d4;
--line-soft: #eee9df;
--brand: #1B365D;
--brand-soft: #EEF3F8;
--brand-mid: #315982;
--ink: #151515;
--text: #2f2d29;
--muted: #68625a;
--faint: #8b857b;
--success: #2f6f5e;
--warn: #8a5a19;
--serif: "TsangerJinKai02", "Source Han Serif SC", "Noto Serif CJK SC", "Songti SC", "STSong", Charter, Georgia, serif;
--mono: "JetBrains Mono", "SF Mono", ui-monospace, Menlo, Consolas, monospace;
--shadow-soft: 0 1px 2px rgba(27, 54, 93, 0.06), 0 16px 44px rgba(27, 54, 93, 0.08);
}}
* {{ box-sizing: border-box; }}
html {{ scroll-behavior: smooth; }}
body {{
margin: 0;
background: #ffffff;
color: var(--ink);
font-family: var(--serif);
line-height: 1.62;
letter-spacing: 0;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-rendering: optimizeLegibility;
}}
body[data-report-lang="zh-CN"] [data-lang="en"],
body[data-report-lang="en"] [data-lang="zh-CN"] {{ display: none !important; }}
.skip-link {{
position: fixed;
left: 18px;
top: 10px;
z-index: 40;
transform: translateY(-140%);
padding: 8px 12px;
border-radius: 8px;
background: var(--brand);
color: #fff;
text-decoration: none;
transition: transform 160ms cubic-bezier(0.16, 1, 0.3, 1);
}}
.skip-link:focus-visible {{ transform: translateY(0); outline: 2px solid var(--brand-mid); outline-offset: 2px; }}
.topbar {{
position: sticky;
top: 0;
z-index: 20;
background: rgba(255, 255, 255, 0.96);
border-bottom: 1px solid var(--line);
}}
.progress-track {{
height: 2px;
background: transparent;
}}
.progress-bar {{
display: block;
width: 100%;
height: 100%;
background: var(--brand);
transition: transform 160ms cubic-bezier(0.16, 1, 0.3, 1);
transform-origin: left center;
transform: scaleX(0);
}}
.topbar-inner {{
max-width: 1240px;
margin: 0 auto;
padding: 9px 28px;
display: grid;
grid-template-columns: minmax(0, 1fr) auto;
gap: 18px;
align-items: center;
}}
.nav-shell {{
display: grid;
grid-template-columns: auto minmax(0, 1fr);
gap: 18px;
align-items: center;
min-width: 0;
}}
.report-mark {{
color: var(--brand);
font-family: var(--mono);
font-size: 11px;
line-height: 1;
text-transform: uppercase;
white-space: nowrap;
}}
.report-nav {{
display: flex;
gap: 4px;
overflow-x: auto;
scrollbar-width: none;
min-width: 0;
}}
.report-nav::-webkit-scrollbar {{ display: none; }}
.report-nav a {{
flex: 0 0 auto;
min-width: 76px;
min-height: 40px;
display: inline-flex;
align-items: center;
justify-content: center;
padding: 0 10px;
color: var(--brand);
text-decoration: none;
text-align: center;
font-size: 13px;
border-radius: 8px;
white-space: nowrap;
transition-property: background-color, color, transform;
transition-duration: 160ms;
transition-timing-function: cubic-bezier(0.16, 1, 0.3, 1);
}}
@media (hover: hover) {{
.report-nav a:hover {{ background: var(--brand-soft); }}
}}
.report-nav a:focus-visible {{
outline: 2px solid var(--brand-mid);
outline-offset: 2px;
background: var(--brand-soft);
}}
.report-nav a[aria-current="true"] {{
background: var(--brand);
color: #ffffff;
}}
.report-nav a[aria-current="true"] span {{ color: #ffffff; }}
.language-switch {{
display: inline-flex;
gap: 3px;
padding: 3px;
border: 1px solid var(--line);
border-radius: 8px;
background: var(--paper);
box-shadow: 0 1px 2px rgba(27, 54, 93, 0.05);
}}
.language-switch button {{
appearance: none;
min-width: 42px;
min-height: 34px;
border: 0;
border-radius: 6px;
padding: 0 10px;
background: transparent;
color: var(--muted);
font: inherit;
font-size: 13px;
cursor: pointer;
transition-property: background-color, color, transform;
transition-duration: 160ms;
transition-timing-function: cubic-bezier(0.16, 1, 0.3, 1);
}}
.language-switch button:active {{ transform: scale(0.96); }}
.language-switch button:focus-visible {{ outline: 2px solid var(--brand-mid); outline-offset: 2px; }}
.language-switch button[aria-pressed="true"] {{
background: var(--brand-soft);
color: var(--brand);
}}
.wrap {{
max-width: 1240px;
margin: 0 auto;
padding: 58px 28px 92px;
}}
.hero {{
padding: 16px 0 34px;
}}
.hero-grid {{
display: grid;
grid-template-columns: minmax(0, 1fr) 360px;
gap: 44px;
align-items: end;
}}
.eyebrow, .report-mark {{
letter-spacing: 0;
}}
.eyebrow {{
margin: 0 0 12px;
color: var(--brand);
font-family: var(--mono);
font-size: 12px;
text-transform: uppercase;
}}
.slug {{
margin: 0 0 18px;
color: var(--faint);
font-family: var(--mono);
font-size: 13px;
overflow-wrap: anywhere;
}}
h1, h2, h3 {{
margin: 0;
font-weight: 500;
letter-spacing: 0;
text-wrap: balance;
}}
h1 {{
max-width: 8em;
color: var(--ink);
font-size: 4rem;
line-height: 1.02;
}}
.lead {{
max-width: 760px;
margin: 20px 0 0;
color: var(--text);
font-size: 1.08rem;
text-wrap: pretty;
}}
.hero-meta, .badges {{
display: flex;
flex-wrap: wrap;
gap: 8px;
margin-top: 20px;
}}
.hero-meta span, .badges span, .tag {{
display: inline-flex;
align-items: center;
min-height: 30px;
padding: 5px 10px;
border-radius: 6px;
background: var(--brand-soft);
color: var(--brand);
font-size: 13px;
font-variant-numeric: tabular-nums;
}}
.hero-card {{
position: relative;
padding: 22px 22px 24px;
border-radius: 8px;
background: linear-gradient(180deg, #ffffff 0%, #fbfaf7 100%);
box-shadow: var(--shadow-soft);
border: 1px solid var(--line-soft);
}}
.hero-card::before {{
content: "";
position: absolute;
top: 18px;
right: 18px;
width: 38px;
height: 2px;
background: var(--brand);
}}
.score-strip {{
display: grid;
grid-template-columns: repeat(4, minmax(0, 1fr));
gap: 10px;
margin-top: 32px;
padding-top: 20px;
border-top: 1px solid var(--line);
}}
.score-chip {{
padding: 14px 14px 12px;
border-radius: 8px;
background: var(--wash);
border: 1px solid var(--line-soft);
}}
.score-chip span {{
display: block;
color: var(--muted);
font-size: 12px;
}}
.score-chip strong {{
display: block;
margin: 5px 0 8px;
color: var(--brand);
font-family: var(--mono);
font-size: 1.65rem;
font-weight: 500;
line-height: 1;
font-variant-numeric: tabular-nums;
}}
.score-chip i {{
display: block;
height: 3px;
border-radius: 999px;
background: linear-gradient(90deg, var(--brand) var(--score), #dfe6ee var(--score));
}}
.score-chip small {{
display: block;
margin-top: 8px;
color: var(--muted);
font-size: 12px;
line-height: 1.45;
}}
section {{
scroll-margin-top: 78px;
padding-top: 44px;
margin-top: 44px;
border-top: 1px solid var(--line);
}}
section.hero {{
scroll-margin-top: 0;
padding-top: 16px;
margin-top: 0;
border-top: 0;
}}
.section-head {{
display: grid;
grid-template-columns: minmax(0, 246px) minmax(0, 1fr);
gap: 36px;
align-items: start;
}}
h2 {{
color: var(--ink);
font-size: 1.5rem;
line-height: 1.18;
}}
h2::before {{
content: "";
display: block;
width: 32px;
height: 2px;
margin-bottom: 12px;
background: var(--brand);
}}
h3 {{
color: var(--ink);
font-size: 1.02rem;
line-height: 1.3;
margin-bottom: 10px;
}}
.section-head p {{
margin: 12px 0 0;
color: var(--muted);
max-width: 43ch;
text-wrap: pretty;
}}
.two-col, .metric-grid, .chart-grid {{
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 16px;
align-items: stretch;
}}
.quality-panels {{
margin-top: 16px;
}}
.metrics-stack {{
display: grid;
gap: 18px;
}}
.metrics-lead {{
display: grid;
grid-template-columns: minmax(420px, 1.15fr) minmax(300px, 0.85fr);
gap: 18px;
align-items: stretch;
}}
.metrics-note {{
display: grid;
align-content: start;
gap: 16px;
}}
.metrics-note p {{
margin: 0;
max-width: none;
color: var(--text);
}}
.metric-summary-list {{
margin: 0;
padding: 0;
list-style: none;
display: grid;
gap: 10px;
}}
.metric-summary-list li {{
display: grid;
grid-template-columns: auto minmax(0, 1fr) auto;
gap: 8px 10px;
align-items: baseline;
padding: 10px 0;
border-bottom: 1px solid var(--line-soft);
}}
.metric-summary-list li:last-child {{ border-bottom: 0; }}
.metric-summary-list b {{
color: var(--ink);
font-weight: 500;
}}
.metric-summary-list em {{
color: var(--brand);
font-family: var(--mono);
font-style: normal;
font-variant-numeric: tabular-nums;
}}
.metric-summary-list small {{
grid-column: 2 / 4;
color: var(--muted);
line-height: 1.5;
}}
.metric-status {{
display: inline-flex;
align-items: center;
min-height: 24px;
padding: 2px 7px;
border-radius: 6px;
background: var(--brand-soft);
color: var(--brand);
font-size: 12px;
}}
.metric-grid {{
grid-template-columns: repeat(2, minmax(0, 1fr));
margin-top: 2px;
}}
.list, .compact-list, .step-list {{
margin: 0;
padding-left: 1.15em;
display: grid;
gap: 8px;
}}
.list li::marker, .compact-list li::marker, .step-list li::marker {{ color: var(--brand); }}
.compact-list {{
gap: 6px;
font-size: 13px;
color: var(--muted);
}}
.panel, .metric-card, .roadmap-item {{
background: #ffffff;
border: 1px solid var(--line-soft);
border-radius: 8px;
padding: 22px;
box-shadow: 0 1px 2px rgba(27, 54, 93, 0.04);
}}
.metric-card {{
display: grid;
grid-template-columns: 92px minmax(0, 1fr);
gap: 18px;
align-content: start;
min-height: 0;
}}
.metric-card-head {{
display: grid;
align-content: start;
}}
.metric-card strong {{
display: block;
margin: 8px 0 10px;
color: var(--brand);
font-family: var(--mono);
font-size: 2rem;
font-weight: 500;
line-height: 1;
font-variant-numeric: tabular-nums;
}}
.metric-label {{
color: var(--muted);
font-size: 13px;
}}
.metric-card-body {{
min-width: 0;
}}
.chart-figure {{
margin: 0;
padding: 18px;
border: 1px solid var(--line-soft);
border-radius: 8px;
background: #ffffff;
box-shadow: 0 1px 2px rgba(27, 54, 93, 0.04);
}}
.chart-figure svg {{
width: 100%;
height: auto;
display: block;
overflow: visible;
}}
.chart-figure text {{
fill: var(--ink);
font-family: var(--serif);
font-size: 13px;
}}
.chart-title {{
fill: var(--brand);
font-size: 16px;
font-weight: 500;
}}
.chart-line {{
fill: none;
stroke: var(--brand);
stroke-width: 2;
}}
figcaption {{
margin-top: 12px;
padding-top: 10px;
border-top: 1px solid var(--line-soft);
color: var(--muted);
font-size: 13px;
line-height: 1.5;
text-wrap: pretty;
}}
table {{
width: 100%;
border-collapse: collapse;
font-size: 14px;
}}
th, td {{
padding: 12px 10px;
text-align: left;
border-bottom: 1px solid var(--line-soft);
vertical-align: top;
}}
th {{
color: var(--brand);
font-weight: 500;
font-size: 12px;
}}
td:first-child, th:first-child {{ width: 96px; }}
.roadmap {{
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 16px;
}}
.step {{
display: inline-flex;
margin-bottom: 12px;
min-height: 28px;
align-items: center;
padding: 3px 8px;
border-radius: 6px;
background: var(--brand-soft);
color: var(--brand);
font-size: 12px;
}}
.unlock {{
margin-top: 14px;
color: var(--muted);
font-size: 13px;
}}
@media (max-width: 980px) {{
.topbar-inner {{
grid-template-columns: minmax(0, 1fr) auto;
padding: 8px 16px;
}}
.nav-shell {{ grid-template-columns: 1fr; gap: 6px; }}
.report-mark {{ display: none; }}
.report-nav a {{ min-width: 72px; }}
.hero-grid, .section-head {{ grid-template-columns: 1fr; }}
.hero-grid {{ gap: 24px; }}
.score-strip {{ grid-template-columns: repeat(2, minmax(0, 1fr)); }}
.metrics-lead, .two-col, .metric-grid, .chart-grid, .roadmap {{ grid-template-columns: 1fr; }}
.metric-card {{ grid-template-columns: 86px minmax(0, 1fr); }}
h1 {{ font-size: 2.75rem; }}
}}
@media (max-width: 540px) {{
.wrap {{ padding: 34px 16px 72px; }}
.topbar-inner {{ gap: 10px; }}
.report-nav {{
display: flex;
gap: 2px;
}}
.report-nav a {{
min-width: 66px;
min-height: 38px;
padding: 0 8px;
font-size: 12px;
}}
.language-switch button {{ min-width: 38px; min-height: 32px; padding: 0 8px; }}
.hero {{ padding-top: 8px; }}
h1 {{ max-width: 8em; font-size: 2.35rem; }}
.lead {{ font-size: 1rem; }}
.hero-meta span, .badges span {{ font-size: 12px; }}
.score-strip {{ grid-template-columns: 1fr; }}
section {{ margin-top: 34px; padding-top: 34px; }}
.panel, .metric-card, .roadmap-item, .chart-figure, .hero-card {{ padding: 18px; }}
.metric-card {{ grid-template-columns: 1fr; gap: 10px; }}
.metric-card strong {{ margin-bottom: 2px; }}
.metric-summary-list li {{ grid-template-columns: auto minmax(0, 1fr) auto; }}
table {{ font-size: 13px; }}
th, td {{ padding: 10px 7px; }}
}}
@media (prefers-reduced-motion: reduce) {{
html {{ scroll-behavior: auto; }}
*, *::before, *::after {{ transition-duration: 0.01ms !important; }}
}}
{skill_overview_css()}
</style>
</head>
<body data-report-lang="zh-CN">
@@ -1148,43 +569,7 @@ def render_html(summary: dict) -> str:
</section>
</main>
<script>
(function () {{
var buttons = Array.prototype.slice.call(document.querySelectorAll("[data-set-lang]"));
var navLinks = Array.prototype.slice.call(document.querySelectorAll(".report-nav a"));
var sections = navLinks
.map(function (link) {{ return document.querySelector(link.getAttribute("href")); }})
.filter(Boolean);
var progressBar = document.querySelector(".progress-bar");
function setLanguage(lang) {{
document.body.setAttribute("data-report-lang", lang);
document.documentElement.setAttribute("lang", lang);
buttons.forEach(function (button) {{
button.setAttribute("aria-pressed", button.getAttribute("data-set-lang") === lang ? "true" : "false");
}});
}}
function updateProgress() {{
var scrollTop = window.scrollY || document.documentElement.scrollTop;
var height = Math.max(1, document.documentElement.scrollHeight - window.innerHeight);
var pct = Math.min(100, Math.max(0, (scrollTop / height) * 100));
if (progressBar) progressBar.style.transform = "scaleX(" + pct / 100 + ")";
var active = sections[0];
sections.forEach(function (section) {{
if (section.getBoundingClientRect().top <= 110) active = section;
}});
navLinks.forEach(function (link) {{
link.setAttribute("aria-current", link.getAttribute("href") === "#" + active.id ? "true" : "false");
}});
}}
buttons.forEach(function (button) {{
button.addEventListener("click", function () {{
setLanguage(button.getAttribute("data-set-lang"));
}});
}});
window.addEventListener("scroll", updateProgress, {{ passive: true }});
window.addEventListener("resize", updateProgress);
setLanguage("zh-CN");
updateProgress();
}})();
{skill_overview_script()}
</script>
</body>
</html>
+133
View File
@@ -0,0 +1,133 @@
#!/usr/bin/env python3
"""Formatting helpers for Review Studio panels."""
import html
from typing import Any
SCRIPT_INTERFACE = "internal-module"
SCRIPT_INTERFACE_REASON = "Imported by render_review_studio.py to format report dictionaries as audit UI panels."
LABELS = {
"actionable_owner_gap_count": "待处理 owner",
"actionable_route_collision_count": "待处理冲突",
"actionable_skill_count": "纳入审查",
"actionable_stale_count": "待处理过期",
"adoption_rate": "采用率",
"adapter_count": "Adapter",
"archive_entry_count": "Zip 条目",
"archive_present": "归档存在",
"archive_sha256": "归档哈希",
"baseline_pass_rate": "Baseline",
"breaking_change_count": "破坏变更",
"case_count": "案例数",
"command_executed_count": "命令执行",
"compatibility_pass_count": "兼容通过",
"covered_gate_count": "覆盖 Gate",
"declared_bump": "声明版本",
"delta": "增益",
"event_count": "事件数",
"failure_count": "失败数",
"gate_pass": "Gate",
"help_smoke_failed_count": "Help 失败",
"install_simulated": "安装模拟",
"license": "License",
"metadata_fallback_count": "Metadata fallback",
"missed_trigger_count": "漏触发",
"model_executed_count": "模型执行",
"name": "名称",
"native_enforcement_count": "原生执行",
"network_script_count": "网络脚本",
"non_actionable_issue_count": "非行动项",
"open_blocker_count": "阻断批注",
"open_count": "开放批注",
"owner": "Owner",
"package_sha256": "包体哈希",
"pass_count": "通过数",
"pending_count": "待审",
"recorded_fixture_count": "记录样本",
"recommended_bump": "建议版本",
"residual_risk_count": "残余风险",
"risk_band": "风险带",
"route_collision_count": "路由冲突",
"script_count": "脚本数",
"secret_findings": "Secret",
"skill_count": "Skill 数",
"target_count": "目标数",
"targets": "目标平台",
"timing_observed_count": "计时样本",
"token_estimated_count": "估算 Token",
"token_observed_count": "真实 Token",
"trust_level": "信任级别",
"variant_run_count": "运行数",
"version": "版本",
"warning_count": "警告数",
"with_skill_pass_rate": "With Skill",
}
def label_for_key(key: str) -> str:
return LABELS.get(key, key.replace("_", " ").title())
def value_text(value: Any) -> str:
if value is None:
return "n/a"
if isinstance(value, bool):
return "" if value else ""
if isinstance(value, float):
return str(round(value, 3)).rstrip("0").rstrip(".")
if isinstance(value, list):
return ", ".join(value_text(item) for item in value) if value else ""
if isinstance(value, dict):
parts = []
for key, nested_value in list(value.items())[:6]:
parts.append(f"{label_for_key(str(key))}: {value_text(nested_value)}")
return "".join(parts) if parts else ""
return str(value)
def render_kv_grid(
payload: dict[str, Any],
keys: list[str],
empty: str,
) -> str:
if not payload:
return f"<p class='muted'>{html.escape(empty)}</p>"
rows = []
for key in keys:
if key not in payload:
continue
value = value_text(payload.get(key))
value_html = html.escape(value)
if "sha256" in key or "hash" in key or "checksum" in key:
value_html = f"<code>{value_html}</code>"
rows.append(
"<div>"
f"<dt>{html.escape(label_for_key(key))}</dt>"
f"<dd>{value_html}</dd>"
"</div>"
)
if not rows:
return f"<p class='muted'>{html.escape(empty)}</p>"
return "<dl class='kv-grid'>" + "".join(rows) + "</dl>"
def registry_package_summary(package: dict[str, Any]) -> dict[str, Any]:
if not package:
return {}
compatibility = package.get("compatibility", {}) if isinstance(package.get("compatibility"), dict) else {}
pass_count = sum(1 for status in compatibility.values() if status == "pass")
checksums = package.get("checksums", {}) if isinstance(package.get("checksums"), dict) else {}
return {
"name": package.get("name", ""),
"version": package.get("version", ""),
"maturity": package.get("maturity", ""),
"owner": package.get("owner", ""),
"license": package.get("license", ""),
"trust_level": package.get("trust_level", ""),
"targets": package.get("targets", []),
"compatibility_pass_count": f"{pass_count}/{len(compatibility)}",
"archive_sha256": checksums.get("archive_sha256", ""),
}
+259
View File
@@ -0,0 +1,259 @@
#!/usr/bin/env python3
"""Static layout contract for Review Studio HTML."""
import html
SCRIPT_INTERFACE = "internal-module"
SCRIPT_INTERFACE_REASON = "Imported by render_review_studio.py to keep Review Studio layout and CSS out of gate logic."
REVIEW_STUDIO_NAV = [
("#overview", "审查总览"),
("#intent", "意图画布"),
("#trigger", "触发实验"),
("#output", "输出实验"),
("#actions", "修复动作"),
("#annotations", "审查批注"),
("#runtime", "运行矩阵"),
("#trust", "信任报告"),
("#permissions", "权限批准"),
("#permission-probes", "权限探针"),
("#atlas", "组合治理"),
("#telemetry", "运营回路"),
("#waivers", "人工批准"),
("#registry", "注册审计"),
("#release", "发布路线"),
]
def render_review_nav(nav_items: list[tuple[str, str]] | None = None) -> str:
items = REVIEW_STUDIO_NAV if nav_items is None else nav_items
return "".join(
f"<a href='{html.escape(href)}'>{html.escape(label)}</a>"
for href, label in items
)
def review_studio_css() -> str:
return """
:root {
--ink: #1B365D;
--text: #24201d;
--muted: #746d66;
--line: #e7ded2;
--soft: #faf8f5;
--pass: #1e6b52;
--warn: #9a6718;
--block: #9b2c2c;
}
* { box-sizing: border-box; }
html { scroll-behavior: smooth; }
body {
margin: 0;
background: #ffffff;
color: var(--text);
font-family: Georgia, "Times New Roman", "Songti SC", serif;
line-height: 1.58;
}
nav {
position: sticky;
top: 0;
z-index: 10;
display: flex;
gap: 4px;
justify-content: center;
flex-wrap: wrap;
padding: 10px 16px;
background: rgba(255,255,255,0.94);
border-bottom: 1px solid var(--line);
backdrop-filter: blur(10px);
}
nav a {
color: var(--ink);
text-decoration: none;
font-size: 14px;
padding: 7px 10px;
border-radius: 6px;
}
nav a:hover { background: var(--soft); }
main { max-width: 1180px; margin: 0 auto; padding: 44px 28px 76px; }
header { border-bottom: 1px solid var(--line); padding-bottom: 28px; margin-bottom: 28px; }
.eyebrow { color: var(--ink); font-size: 14px; letter-spacing: .08em; text-transform: uppercase; }
h1, h2, h3 { color: var(--text); font-weight: 500; margin: 0; letter-spacing: 0; }
h1 { font-size: clamp(34px, 5vw, 64px); line-height: 1.03; max-width: 920px; margin-top: 12px; }
h2 { font-size: 30px; margin-bottom: 14px; }
h3 { font-size: 19px; }
p { margin: 0; }
.lede { max-width: 820px; color: var(--muted); font-size: 20px; margin-top: 18px; }
.decision {
display: inline-flex;
align-items: baseline;
gap: 12px;
margin-top: 24px;
padding: 12px 16px;
border: 1px solid var(--line);
border-radius: 8px;
color: var(--ink);
background: var(--soft);
}
.decision strong { font-size: 28px; }
section { padding: 30px 0; border-bottom: 1px solid var(--line); scroll-margin-top: 76px; }
.metrics, .gates {
display: grid;
grid-template-columns: repeat(5, minmax(0, 1fr));
gap: 14px;
}
.gates { grid-template-columns: repeat(4, minmax(0, 1fr)); }
.metric, .gate {
border: 1px solid var(--line);
border-radius: 8px;
padding: 16px;
background: #fff;
min-width: 0;
}
.metric span, .gate span { display: block; color: var(--muted); font-size: 13px; }
.metric strong { display: block; color: var(--ink); font-size: 34px; line-height: 1.1; margin: 8px 0; }
.metric p, .gate p, .gate footer, .issues span, .evidence span { color: var(--muted); font-size: 14px; overflow-wrap: anywhere; }
.gate { display: flex; flex-direction: column; gap: 10px; }
.gate.pass { border-top: 4px solid var(--pass); }
.gate.warn { border-top: 4px solid var(--warn); }
.gate.block { border-top: 4px solid var(--block); }
.gate footer { border-top: 1px solid var(--line); padding-top: 10px; }
a { color: var(--ink); }
.twocol {
display: grid;
grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
gap: 22px;
align-items: start;
}
.panel {
border: 1px solid var(--line);
border-radius: 8px;
padding: 18px;
background: #fff;
}
.panel p { color: var(--muted); }
.kv-grid {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 10px 12px;
margin: 2px 0 0;
}
.kv-grid div {
min-width: 0;
padding: 9px 0 0;
border-top: 1px solid var(--line);
}
.kv-grid dt {
color: var(--muted);
font-size: 13px;
}
.kv-grid dd {
margin: 2px 0 0;
color: var(--ink);
font-size: 15px;
overflow-wrap: anywhere;
}
.issues, .evidence {
list-style: none;
padding: 0;
margin: 0;
display: grid;
gap: 12px;
}
.issues li, .evidence li {
border-left: 3px solid var(--line);
padding-left: 12px;
display: grid;
gap: 3px;
}
.muted { color: var(--muted); }
.actions-grid {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 16px;
}
.annotations-grid {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 16px;
}
.action-card {
border: 1px solid var(--line);
border-radius: 8px;
padding: 18px;
background: #fff;
display: grid;
gap: 10px;
min-width: 0;
}
.action-card.warn { border-left: 4px solid var(--warn); }
.action-card.block { border-left: 4px solid var(--block); }
.annotation-card {
border: 1px solid var(--line);
border-radius: 8px;
padding: 18px;
background: #fff;
display: grid;
gap: 10px;
min-width: 0;
}
.annotation-card.warning { border-left: 4px solid var(--warn); }
.annotation-card.blocker { border-left: 4px solid var(--block); }
.annotation-card.resolved { opacity: .72; }
.action-card span,
.annotation-card span,
.action-card small,
.annotation-card small,
.action-card footer,
.annotation-card footer,
.action-card dd {
color: var(--muted);
font-size: 14px;
overflow-wrap: anywhere;
}
.annotation-card dd { color: var(--muted); font-size: 14px; overflow-wrap: anywhere; }
.action-card dl, .annotation-card dl {
display: grid;
grid-template-columns: 80px minmax(0, 1fr);
gap: 6px 10px;
margin: 0;
}
.action-card dt, .annotation-card dt { color: var(--ink); font-size: 14px; }
.action-card dd, .annotation-card dd { margin: 0; }
.source-ref-list {
list-style: none;
padding: 0;
margin: 0;
display: grid;
gap: 6px;
}
.source-ref-list li {
display: grid;
gap: 2px;
min-width: 0;
padding: 8px 0 0;
border-top: 1px solid var(--line);
}
.source-ref-list a,
.source-ref-list span {
overflow-wrap: anywhere;
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
font-size: 13px;
}
.source-ref-list small {
font-size: 12px;
color: var(--muted);
}
code {
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
font-size: 13px;
}
@media (max-width: 980px) {
.metrics, .gates, .twocol, .actions-grid, .annotations-grid, .kv-grid { grid-template-columns: 1fr; }
main { padding: 32px 18px 60px; }
nav { justify-content: flex-start; overflow-x: auto; flex-wrap: nowrap; }
nav a { flex: 0 0 auto; }
}
""".strip()
+653
View File
@@ -0,0 +1,653 @@
#!/usr/bin/env python3
"""Static layout contract for skill overview report HTML."""
import html
from typing import Any
SCRIPT_INTERFACE = "internal-module"
SCRIPT_INTERFACE_REASON = "Imported by render_skill_overview.py to keep overview report layout and CSS out of data rendering."
def bi_span(zh: str, en: str) -> str:
return (
f'<span data-lang="zh-CN">{html.escape(str(zh))}</span>'
f'<span data-lang="en">{html.escape(str(en))}</span>'
)
def render_report_nav(nav_items: list[dict[str, Any]]) -> str:
return "".join(
f"<a href=\"#{html.escape(str(item['href']))}\">{bi_span(str(item['label']), str(item['label_en']))}</a>"
for item in nav_items
)
def render_language_switch() -> str:
return (
'<div class="language-switch" aria-label="语言切换">'
'<button type="button" data-set-lang="zh-CN" aria-pressed="true">简体</button>'
'<button type="button" data-set-lang="en" aria-pressed="false">EN</button>'
"</div>"
)
def skill_overview_css() -> str:
return """
:root {
--paper: #ffffff;
--wash: #f8fafc;
--wash-strong: #f2f5f8;
--line: #e6e0d4;
--line-soft: #eee9df;
--brand: #1B365D;
--brand-soft: #EEF3F8;
--brand-mid: #315982;
--ink: #151515;
--text: #2f2d29;
--muted: #68625a;
--faint: #8b857b;
--success: #2f6f5e;
--warn: #8a5a19;
--serif: "TsangerJinKai02", "Source Han Serif SC", "Noto Serif CJK SC", "Songti SC", "STSong", Charter, Georgia, serif;
--mono: "JetBrains Mono", "SF Mono", ui-monospace, Menlo, Consolas, monospace;
--shadow-soft: 0 1px 2px rgba(27, 54, 93, 0.06), 0 16px 44px rgba(27, 54, 93, 0.08);
}
* { box-sizing: border-box; }
html { scroll-behavior: smooth; }
body {
margin: 0;
background: #ffffff;
color: var(--ink);
font-family: var(--serif);
line-height: 1.62;
letter-spacing: 0;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-rendering: optimizeLegibility;
}
body[data-report-lang="zh-CN"] [data-lang="en"],
body[data-report-lang="en"] [data-lang="zh-CN"] { display: none !important; }
.skip-link {
position: fixed;
left: 18px;
top: 10px;
z-index: 40;
transform: translateY(-140%);
padding: 8px 12px;
border-radius: 8px;
background: var(--brand);
color: #fff;
text-decoration: none;
transition: transform 160ms cubic-bezier(0.16, 1, 0.3, 1);
}
.skip-link:focus-visible { transform: translateY(0); outline: 2px solid var(--brand-mid); outline-offset: 2px; }
.topbar {
position: sticky;
top: 0;
z-index: 20;
background: rgba(255, 255, 255, 0.96);
border-bottom: 1px solid var(--line);
}
.progress-track {
height: 2px;
background: transparent;
}
.progress-bar {
display: block;
width: 100%;
height: 100%;
background: var(--brand);
transition: transform 160ms cubic-bezier(0.16, 1, 0.3, 1);
transform-origin: left center;
transform: scaleX(0);
}
.topbar-inner {
max-width: 1240px;
margin: 0 auto;
padding: 9px 28px;
display: grid;
grid-template-columns: minmax(0, 1fr) auto;
gap: 18px;
align-items: center;
}
.nav-shell {
display: grid;
grid-template-columns: auto minmax(0, 1fr);
gap: 18px;
align-items: center;
min-width: 0;
}
.report-mark {
color: var(--brand);
font-family: var(--mono);
font-size: 11px;
line-height: 1;
text-transform: uppercase;
white-space: nowrap;
}
.report-nav {
display: flex;
gap: 4px;
overflow-x: auto;
scrollbar-width: none;
min-width: 0;
}
.report-nav::-webkit-scrollbar { display: none; }
.report-nav a {
flex: 0 0 auto;
min-width: 76px;
min-height: 40px;
display: inline-flex;
align-items: center;
justify-content: center;
padding: 0 10px;
color: var(--brand);
text-decoration: none;
text-align: center;
font-size: 13px;
border-radius: 8px;
white-space: nowrap;
transition-property: background-color, color, transform;
transition-duration: 160ms;
transition-timing-function: cubic-bezier(0.16, 1, 0.3, 1);
}
@media (hover: hover) {
.report-nav a:hover { background: var(--brand-soft); }
}
.report-nav a:focus-visible {
outline: 2px solid var(--brand-mid);
outline-offset: 2px;
background: var(--brand-soft);
}
.report-nav a[aria-current="true"] {
background: var(--brand);
color: #ffffff;
}
.report-nav a[aria-current="true"] span { color: #ffffff; }
.language-switch {
display: inline-flex;
gap: 3px;
padding: 3px;
border: 1px solid var(--line);
border-radius: 8px;
background: var(--paper);
box-shadow: 0 1px 2px rgba(27, 54, 93, 0.05);
}
.language-switch button {
appearance: none;
min-width: 42px;
min-height: 34px;
border: 0;
border-radius: 6px;
padding: 0 10px;
background: transparent;
color: var(--muted);
font: inherit;
font-size: 13px;
cursor: pointer;
transition-property: background-color, color, transform;
transition-duration: 160ms;
transition-timing-function: cubic-bezier(0.16, 1, 0.3, 1);
}
.language-switch button:active { transform: scale(0.96); }
.language-switch button:focus-visible { outline: 2px solid var(--brand-mid); outline-offset: 2px; }
.language-switch button[aria-pressed="true"] {
background: var(--brand-soft);
color: var(--brand);
}
.wrap {
max-width: 1240px;
margin: 0 auto;
padding: 58px 28px 92px;
}
.hero {
padding: 16px 0 34px;
}
.hero-grid {
display: grid;
grid-template-columns: minmax(0, 1fr) 360px;
gap: 44px;
align-items: end;
}
.eyebrow, .report-mark {
letter-spacing: 0;
}
.eyebrow {
margin: 0 0 12px;
color: var(--brand);
font-family: var(--mono);
font-size: 12px;
text-transform: uppercase;
}
.slug {
margin: 0 0 18px;
color: var(--faint);
font-family: var(--mono);
font-size: 13px;
overflow-wrap: anywhere;
}
h1, h2, h3 {
margin: 0;
font-weight: 500;
letter-spacing: 0;
text-wrap: balance;
}
h1 {
max-width: 8em;
color: var(--ink);
font-size: 4rem;
line-height: 1.02;
}
.lead {
max-width: 760px;
margin: 20px 0 0;
color: var(--text);
font-size: 1.08rem;
text-wrap: pretty;
}
.hero-meta, .badges {
display: flex;
flex-wrap: wrap;
gap: 8px;
margin-top: 20px;
}
.hero-meta span, .badges span, .tag {
display: inline-flex;
align-items: center;
min-height: 30px;
padding: 5px 10px;
border-radius: 6px;
background: var(--brand-soft);
color: var(--brand);
font-size: 13px;
font-variant-numeric: tabular-nums;
}
.hero-card {
position: relative;
padding: 22px 22px 24px;
border-radius: 8px;
background: linear-gradient(180deg, #ffffff 0%, #fbfaf7 100%);
box-shadow: var(--shadow-soft);
border: 1px solid var(--line-soft);
}
.hero-card::before {
content: "";
position: absolute;
top: 18px;
right: 18px;
width: 38px;
height: 2px;
background: var(--brand);
}
.score-strip {
display: grid;
grid-template-columns: repeat(4, minmax(0, 1fr));
gap: 10px;
margin-top: 32px;
padding-top: 20px;
border-top: 1px solid var(--line);
}
.score-chip {
padding: 14px 14px 12px;
border-radius: 8px;
background: var(--wash);
border: 1px solid var(--line-soft);
}
.score-chip span {
display: block;
color: var(--muted);
font-size: 12px;
}
.score-chip strong {
display: block;
margin: 5px 0 8px;
color: var(--brand);
font-family: var(--mono);
font-size: 1.65rem;
font-weight: 500;
line-height: 1;
font-variant-numeric: tabular-nums;
}
.score-chip i {
display: block;
height: 3px;
border-radius: 999px;
background: linear-gradient(90deg, var(--brand) var(--score), #dfe6ee var(--score));
}
.score-chip small {
display: block;
margin-top: 8px;
color: var(--muted);
font-size: 12px;
line-height: 1.45;
}
section {
scroll-margin-top: 78px;
padding-top: 44px;
margin-top: 44px;
border-top: 1px solid var(--line);
}
section.hero {
scroll-margin-top: 0;
padding-top: 16px;
margin-top: 0;
border-top: 0;
}
.section-head {
display: grid;
grid-template-columns: minmax(0, 246px) minmax(0, 1fr);
gap: 36px;
align-items: start;
}
h2 {
color: var(--ink);
font-size: 1.5rem;
line-height: 1.18;
}
h2::before {
content: "";
display: block;
width: 32px;
height: 2px;
margin-bottom: 12px;
background: var(--brand);
}
h3 {
color: var(--ink);
font-size: 1.02rem;
line-height: 1.3;
margin-bottom: 10px;
}
.section-head p {
margin: 12px 0 0;
color: var(--muted);
max-width: 43ch;
text-wrap: pretty;
}
.two-col, .metric-grid, .chart-grid {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 16px;
align-items: stretch;
}
.quality-panels {
margin-top: 16px;
}
.metrics-stack {
display: grid;
gap: 18px;
}
.metrics-lead {
display: grid;
grid-template-columns: minmax(420px, 1.15fr) minmax(300px, 0.85fr);
gap: 18px;
align-items: stretch;
}
.metrics-note {
display: grid;
align-content: start;
gap: 16px;
}
.metrics-note p {
margin: 0;
max-width: none;
color: var(--text);
}
.metric-summary-list {
margin: 0;
padding: 0;
list-style: none;
display: grid;
gap: 10px;
}
.metric-summary-list li {
display: grid;
grid-template-columns: auto minmax(0, 1fr) auto;
gap: 8px 10px;
align-items: baseline;
padding: 10px 0;
border-bottom: 1px solid var(--line-soft);
}
.metric-summary-list li:last-child { border-bottom: 0; }
.metric-summary-list b {
color: var(--ink);
font-weight: 500;
}
.metric-summary-list em {
color: var(--brand);
font-family: var(--mono);
font-style: normal;
font-variant-numeric: tabular-nums;
}
.metric-summary-list small {
grid-column: 2 / 4;
color: var(--muted);
line-height: 1.5;
}
.metric-status {
display: inline-flex;
align-items: center;
min-height: 24px;
padding: 2px 7px;
border-radius: 6px;
background: var(--brand-soft);
color: var(--brand);
font-size: 12px;
}
.metric-grid {
grid-template-columns: repeat(2, minmax(0, 1fr));
margin-top: 2px;
}
.list, .compact-list, .step-list {
margin: 0;
padding-left: 1.15em;
display: grid;
gap: 8px;
}
.list li::marker, .compact-list li::marker, .step-list li::marker { color: var(--brand); }
.compact-list {
gap: 6px;
font-size: 13px;
color: var(--muted);
}
.panel, .metric-card, .roadmap-item {
background: #ffffff;
border: 1px solid var(--line-soft);
border-radius: 8px;
padding: 22px;
box-shadow: 0 1px 2px rgba(27, 54, 93, 0.04);
}
.metric-card {
display: grid;
grid-template-columns: 92px minmax(0, 1fr);
gap: 18px;
align-content: start;
min-height: 0;
}
.metric-card-head {
display: grid;
align-content: start;
}
.metric-card strong {
display: block;
margin: 8px 0 10px;
color: var(--brand);
font-family: var(--mono);
font-size: 2rem;
font-weight: 500;
line-height: 1;
font-variant-numeric: tabular-nums;
}
.metric-label {
color: var(--muted);
font-size: 13px;
}
.metric-card-body {
min-width: 0;
}
.chart-figure {
margin: 0;
padding: 18px;
border: 1px solid var(--line-soft);
border-radius: 8px;
background: #ffffff;
box-shadow: 0 1px 2px rgba(27, 54, 93, 0.04);
}
.chart-figure svg {
width: 100%;
height: auto;
display: block;
overflow: visible;
}
.chart-figure text {
fill: var(--ink);
font-family: var(--serif);
font-size: 13px;
}
.chart-title {
fill: var(--brand);
font-size: 16px;
font-weight: 500;
}
.chart-line {
fill: none;
stroke: var(--brand);
stroke-width: 2;
}
figcaption {
margin-top: 12px;
padding-top: 10px;
border-top: 1px solid var(--line-soft);
color: var(--muted);
font-size: 13px;
line-height: 1.5;
text-wrap: pretty;
}
table {
width: 100%;
border-collapse: collapse;
font-size: 14px;
}
th, td {
padding: 12px 10px;
text-align: left;
border-bottom: 1px solid var(--line-soft);
vertical-align: top;
}
th {
color: var(--brand);
font-weight: 500;
font-size: 12px;
}
td:first-child, th:first-child { width: 96px; }
.roadmap {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 16px;
}
.step {
display: inline-flex;
margin-bottom: 12px;
min-height: 28px;
align-items: center;
padding: 3px 8px;
border-radius: 6px;
background: var(--brand-soft);
color: var(--brand);
font-size: 12px;
}
.unlock {
margin-top: 14px;
color: var(--muted);
font-size: 13px;
}
@media (max-width: 980px) {
.topbar-inner {
grid-template-columns: minmax(0, 1fr) auto;
padding: 8px 16px;
}
.nav-shell { grid-template-columns: 1fr; gap: 6px; }
.report-mark { display: none; }
.report-nav a { min-width: 72px; }
.hero-grid, .section-head { grid-template-columns: 1fr; }
.hero-grid { gap: 24px; }
.score-strip { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.metrics-lead, .two-col, .metric-grid, .chart-grid, .roadmap { grid-template-columns: 1fr; }
.metric-card { grid-template-columns: 86px minmax(0, 1fr); }
h1 { font-size: 2.75rem; }
}
@media (max-width: 540px) {
.wrap { padding: 34px 16px 72px; }
.topbar-inner { gap: 10px; }
.report-nav {
display: flex;
gap: 2px;
}
.report-nav a {
min-width: 66px;
min-height: 38px;
padding: 0 8px;
font-size: 12px;
}
.language-switch button { min-width: 38px; min-height: 32px; padding: 0 8px; }
.hero { padding-top: 8px; }
h1 { max-width: 8em; font-size: 2.35rem; }
.lead { font-size: 1rem; }
.hero-meta span, .badges span { font-size: 12px; }
.score-strip { grid-template-columns: 1fr; }
section { margin-top: 34px; padding-top: 34px; }
.panel, .metric-card, .roadmap-item, .chart-figure, .hero-card { padding: 18px; }
.metric-card { grid-template-columns: 1fr; gap: 10px; }
.metric-card strong { margin-bottom: 2px; }
.metric-summary-list li { grid-template-columns: auto minmax(0, 1fr) auto; }
table { font-size: 13px; }
th, td { padding: 10px 7px; }
}
@media (prefers-reduced-motion: reduce) {
html { scroll-behavior: auto; }
*, *::before, *::after { transition-duration: 0.01ms !important; }
}
""".strip()
def skill_overview_script() -> str:
return """
(function () {
var buttons = Array.prototype.slice.call(document.querySelectorAll("[data-set-lang]"));
var navLinks = Array.prototype.slice.call(document.querySelectorAll(".report-nav a"));
var sections = navLinks
.map(function (link) { return document.querySelector(link.getAttribute("href")); })
.filter(Boolean);
var progressBar = document.querySelector(".progress-bar");
function setLanguage(lang) {
document.body.setAttribute("data-report-lang", lang);
document.documentElement.setAttribute("lang", lang);
buttons.forEach(function (button) {
button.setAttribute("aria-pressed", button.getAttribute("data-set-lang") === lang ? "true" : "false");
});
}
function updateProgress() {
var scrollTop = window.scrollY || document.documentElement.scrollTop;
var height = Math.max(1, document.documentElement.scrollHeight - window.innerHeight);
var pct = Math.min(100, Math.max(0, (scrollTop / height) * 100));
if (progressBar) progressBar.style.transform = "scaleX(" + pct / 100 + ")";
var active = sections[0];
sections.forEach(function (section) {
if (section.getBoundingClientRect().top <= 110) active = section;
});
navLinks.forEach(function (link) {
link.setAttribute("aria-current", link.getAttribute("href") === "#" + active.id ? "true" : "false");
});
}
buttons.forEach(function (button) {
button.addEventListener("click", function () {
setLanguage(button.getAttribute("data-set-lang"));
});
});
window.addEventListener("scroll", updateProgress, { passive: true });
window.addEventListener("resize", updateProgress);
setLanguage("zh-CN");
updateProgress();
})();
""".strip()
+14 -225
View File
@@ -7,65 +7,29 @@ from pathlib import Path
from github_benchmark_scan import build_query
from render_intent_confidence import assess_intent_confidence
from yao_cli_config import (
ARCHETYPE_MODE,
archetype_guidance,
baseline_compare_args,
diagnose_skill_candidates,
diagnosis_note,
discovery_summary,
infer_archetype,
local_output_runner_command,
recommendation_from_synthesis,
reference_visibility,
resolve_promotion_target,
resolve_target,
)
ROOT = Path(__file__).resolve().parent.parent
SCRIPTS = ROOT / "scripts"
TARGETS = {
"root": {
"description_file": ROOT / "SKILL.md",
"baseline_description_file": ROOT / "evals" / "baseline_description.txt",
"semantic_config": ROOT / "evals" / "semantic_config.json",
"dev_cases": ROOT / "evals" / "dev" / "trigger_cases.json",
"holdout_cases": ROOT / "evals" / "holdout" / "trigger_cases.json",
"blind_holdout_cases": ROOT / "evals" / "blind_holdout" / "trigger_cases.json",
"adversarial_cases": ROOT / "evals" / "adversarial" / "trigger_cases.json",
"output_json": ROOT / "reports" / "description_optimization.json",
"output_md": ROOT / "reports" / "description_optimization.md",
"title": "Root Description Optimization",
},
"team-frontend-review": {
"description_file": ROOT / "examples" / "team-frontend-review" / "generated-skill" / "SKILL.md",
"baseline_description_file": ROOT / "examples" / "team-frontend-review" / "optimization" / "baseline_description.txt",
"semantic_config": ROOT / "examples" / "team-frontend-review" / "optimization" / "semantic_config.json",
"dev_cases": ROOT / "examples" / "team-frontend-review" / "optimization" / "dev" / "trigger_cases.json",
"holdout_cases": ROOT / "examples" / "team-frontend-review" / "optimization" / "holdout" / "trigger_cases.json",
"blind_holdout_cases": ROOT / "examples" / "team-frontend-review" / "optimization" / "blind_holdout" / "trigger_cases.json",
"adversarial_cases": ROOT / "examples" / "team-frontend-review" / "optimization" / "adversarial" / "trigger_cases.json",
"output_json": ROOT / "examples" / "team-frontend-review" / "optimization" / "reports" / "description_optimization.json",
"output_md": ROOT / "examples" / "team-frontend-review" / "optimization" / "reports" / "description_optimization.md",
"title": "Frontend Review Description Optimization",
},
"governed-incident-command": {
"description_file": ROOT / "examples" / "governed-incident-command" / "generated-skill" / "SKILL.md",
"baseline_description_file": ROOT / "examples" / "governed-incident-command" / "optimization" / "baseline_description.txt",
"semantic_config": ROOT / "examples" / "governed-incident-command" / "optimization" / "semantic_config.json",
"dev_cases": ROOT / "examples" / "governed-incident-command" / "optimization" / "dev" / "trigger_cases.json",
"holdout_cases": ROOT / "examples" / "governed-incident-command" / "optimization" / "holdout" / "trigger_cases.json",
"blind_holdout_cases": ROOT / "examples" / "governed-incident-command" / "optimization" / "blind_holdout" / "trigger_cases.json",
"adversarial_cases": ROOT / "examples" / "governed-incident-command" / "optimization" / "adversarial" / "trigger_cases.json",
"output_json": ROOT / "examples" / "governed-incident-command" / "optimization" / "reports" / "description_optimization.json",
"output_md": ROOT / "examples" / "governed-incident-command" / "optimization" / "reports" / "description_optimization.md",
"title": "Governed Incident Description Optimization",
},
}
PROMOTION_TARGETS = {
"root": "yao-meta-skill",
"team-frontend-review": "team-frontend-review",
"governed-incident-command": "governed-incident-command",
}
def script_path(name: str) -> str:
return str(SCRIPTS / name)
def local_output_runner_command() -> str:
return json.dumps(["python3", "scripts/local_output_eval_runner.py"])
def load_json_maybe(text: str) -> dict | None:
text = text.strip()
if not text:
@@ -94,33 +58,6 @@ def run_script(name: str, args: list[str], cwd: Path | None = None) -> dict:
}
def resolve_target(name: str) -> dict:
if name not in TARGETS:
raise KeyError(f"Unknown target: {name}")
return TARGETS[name]
def resolve_promotion_target(name: str) -> str:
if name not in PROMOTION_TARGETS:
raise KeyError(f"Unknown promotion target: {name}")
return PROMOTION_TARGETS[name]
def baseline_compare_args() -> list[str]:
args = []
for label, target in TARGETS.items():
args.extend(["--entry", f"{label}::{target['output_json']}"])
args.extend(
[
"--output-json",
str(ROOT / "reports" / "baseline-compare.json"),
"--output-md",
str(ROOT / "reports" / "baseline-compare.md"),
]
)
return args
def prompt_with_default(label: str, default: str) -> str:
sys.stderr.write(f"{label} [{default}]: ")
sys.stderr.flush()
@@ -165,154 +102,6 @@ def intent_confidence_note(summary: dict) -> str:
return "\n".join(lines) + "\n"
ARCHETYPE_MODE = {
"scaffold": "scaffold",
"production": "production",
"library": "library",
"governed": "governed",
}
def infer_archetype(job: str, description: str) -> tuple[str, str]:
text = f"{job} {description}".lower()
if any(token in text for token in ("incident", "compliance", "security", "release", "govern", "audit", "policy")):
return "governed", "The request looks operationally sensitive, so governed is the safest default."
if any(token in text for token in ("shared", "cross-team", "library", "portable", "platform", "reusable across")):
return "library", "The request signals multi-team reuse or portability, so library is the better fit."
if any(token in text for token in ("review", "checklist", "team", "workflow", "process", "standardize")):
return "production", "The request looks team-reused and repeatable, so production fits better than scaffold."
return "scaffold", "The request still looks exploratory or lightweight, so scaffold keeps the first package lean."
def archetype_guidance(archetype: str) -> dict:
mapping = {
"scaffold": {
"first_gate": "trigger and exclusions",
"focus": "keep the first package small and avoid governance overhead",
},
"production": {
"first_gate": "trigger plus one execution or eval asset",
"focus": "make the package reliable for team reuse",
},
"library": {
"first_gate": "trigger, portability, and packaging semantics",
"focus": "treat the package as a shared capability with visible evidence",
},
"governed": {
"first_gate": "trigger, governance, and review cadence",
"focus": "treat the package as a high-trust asset from the start",
},
}
return mapping.get(archetype, mapping["scaffold"])
def discovery_summary(job: str, primary_output: str, archetype: str, guidance: dict) -> str:
return (
"\nHere's the shape I'm hearing so far:\n"
f"- Repeated job: {job}\n"
f"- Desired hand-back: {primary_output}\n"
f"- Best starting archetype: {archetype}\n"
f"- First gate: {guidance['first_gate']}\n"
f"- Current focus: {guidance['focus']}\n"
)
def explicit_skill_request(job: str, description: str) -> bool:
text = f"{job} {description}".lower()
return any(token in text for token in ("skill", "workflow", "checklist", "package", "automate", "standardize"))
def diagnose_skill_candidates(job: str, primary_output: str, archetype: str, confidence: dict) -> dict:
fuzzy = not explicit_skill_request(job, primary_output) or confidence.get("score", 0) < 75
candidates = [
{
"shape": archetype,
"recommendation": "recommended",
"why_it_fits": "This is the lightest shape that matches the current recurring job signal.",
"limitation": "It should not deepen until the concrete output and exclusion boundary are clear.",
"first_pass": "Create one routeable skill with honest boundaries, one review report, and one next-step direction.",
}
]
if archetype != "scaffold":
candidates.append(
{
"shape": "scaffold",
"recommendation": "fallback",
"why_it_fits": "Use this if the idea is still exploratory or personal.",
"limitation": "It may under-serve team reuse, portability, or governance needs.",
"first_pass": "Ship only SKILL.md, interface metadata, intent confidence, and review viewer.",
}
)
if archetype not in {"production", "governed"}:
candidates.append(
{
"shape": "production",
"recommendation": "upgrade path",
"why_it_fits": "Use this when the workflow will be repeated by a team or needs consistent outputs.",
"limitation": "It adds validation and review cost that a personal scaffold may not need.",
"first_pass": "Add one practical eval or execution check after the trigger boundary is stable.",
}
)
if archetype != "governed" and any(token in f"{job} {primary_output}".lower() for token in ("risk", "audit", "release", "policy", "security", "compliance")):
candidates.append(
{
"shape": "governed",
"recommendation": "risk path",
"why_it_fits": "Use this if the skill affects operational, compliance, security, or release decisions.",
"limitation": "It is too heavy unless ownership and review cadence are real.",
"first_pass": "Add owner, review cadence, lifecycle metadata, and reviewer-visible evidence.",
}
)
return {
"mode": "fuzzy-problem-diagnosis" if fuzzy else "direct-skill-shaping",
"fuzzy": fuzzy,
"candidates": candidates[:3],
}
def diagnosis_note(diagnosis: dict) -> str:
lines = ["\nProblem-to-skill diagnosis:"]
for candidate in diagnosis["candidates"]:
lines.append(
f"- {candidate['shape']} ({candidate['recommendation']}): {candidate['why_it_fits']} "
f"First pass: {candidate['first_pass']}"
)
return "\n".join(lines) + "\n"
def reference_visibility(reference_synthesis: dict) -> dict:
synthesis = reference_synthesis.get("synthesis", {}) if isinstance(reference_synthesis, dict) else {}
visibility = synthesis.get("visibility", {}) if isinstance(synthesis, dict) else {}
reasons = list(visibility.get("reasons", []))
mode = visibility.get("mode", "explicit" if reasons else "silent")
return {
"mode": mode,
"user_decision_required": mode == "explicit",
"reasons": reasons,
"conflicts": synthesis.get("conflicts", []),
}
def recommendation_from_synthesis(reference_synthesis: dict, visibility: dict) -> dict:
synthesis = reference_synthesis.get("synthesis", {}) if isinstance(reference_synthesis, dict) else {}
recommendation = synthesis.get("recommendation", {}) if isinstance(synthesis, dict) else {}
borrow_now = recommendation.get("borrow_now") or synthesis.get("borrow_now", [])
avoid_now = recommendation.get("avoid_for_now") or synthesis.get("avoid_now", [])
summary = recommendation.get("summary") or (
f"Start with {borrow_now[0]} Avoid {avoid_now[0]} for the first pass."
if borrow_now and avoid_now
else "Start with the smallest high-confidence pattern and keep the first pass light."
)
why = recommendation.get("why") or "This recommendation comes from the benchmark synthesis and current intent confidence."
return {
"summary": summary,
"borrow_now": borrow_now[:2],
"avoid_for_now": avoid_now[:2],
"why": why,
"user_decision_required": visibility["user_decision_required"],
}
def maybe_emit_update_notice(args: argparse.Namespace) -> None:
if getattr(args, "no_update_check", False):
return
+235
View File
@@ -0,0 +1,235 @@
#!/usr/bin/env python3
"""Pure configuration and shaping helpers for the Yao CLI."""
import json
from pathlib import Path
SCRIPT_INTERFACE = "internal-module"
SCRIPT_INTERFACE_REASON = "Imported by yao.py for CLI target maps and side-effect-free shaping helpers."
ROOT = Path(__file__).resolve().parent.parent
TARGETS = {
"root": {
"description_file": ROOT / "SKILL.md",
"baseline_description_file": ROOT / "evals" / "baseline_description.txt",
"semantic_config": ROOT / "evals" / "semantic_config.json",
"dev_cases": ROOT / "evals" / "dev" / "trigger_cases.json",
"holdout_cases": ROOT / "evals" / "holdout" / "trigger_cases.json",
"blind_holdout_cases": ROOT / "evals" / "blind_holdout" / "trigger_cases.json",
"adversarial_cases": ROOT / "evals" / "adversarial" / "trigger_cases.json",
"output_json": ROOT / "reports" / "description_optimization.json",
"output_md": ROOT / "reports" / "description_optimization.md",
"title": "Root Description Optimization",
},
"team-frontend-review": {
"description_file": ROOT / "examples" / "team-frontend-review" / "generated-skill" / "SKILL.md",
"baseline_description_file": ROOT / "examples" / "team-frontend-review" / "optimization" / "baseline_description.txt",
"semantic_config": ROOT / "examples" / "team-frontend-review" / "optimization" / "semantic_config.json",
"dev_cases": ROOT / "examples" / "team-frontend-review" / "optimization" / "dev" / "trigger_cases.json",
"holdout_cases": ROOT / "examples" / "team-frontend-review" / "optimization" / "holdout" / "trigger_cases.json",
"blind_holdout_cases": ROOT / "examples" / "team-frontend-review" / "optimization" / "blind_holdout" / "trigger_cases.json",
"adversarial_cases": ROOT / "examples" / "team-frontend-review" / "optimization" / "adversarial" / "trigger_cases.json",
"output_json": ROOT / "examples" / "team-frontend-review" / "optimization" / "reports" / "description_optimization.json",
"output_md": ROOT / "examples" / "team-frontend-review" / "optimization" / "reports" / "description_optimization.md",
"title": "Frontend Review Description Optimization",
},
"governed-incident-command": {
"description_file": ROOT / "examples" / "governed-incident-command" / "generated-skill" / "SKILL.md",
"baseline_description_file": ROOT / "examples" / "governed-incident-command" / "optimization" / "baseline_description.txt",
"semantic_config": ROOT / "examples" / "governed-incident-command" / "optimization" / "semantic_config.json",
"dev_cases": ROOT / "examples" / "governed-incident-command" / "optimization" / "dev" / "trigger_cases.json",
"holdout_cases": ROOT / "examples" / "governed-incident-command" / "optimization" / "holdout" / "trigger_cases.json",
"blind_holdout_cases": ROOT / "examples" / "governed-incident-command" / "optimization" / "blind_holdout" / "trigger_cases.json",
"adversarial_cases": ROOT / "examples" / "governed-incident-command" / "optimization" / "adversarial" / "trigger_cases.json",
"output_json": ROOT / "examples" / "governed-incident-command" / "optimization" / "reports" / "description_optimization.json",
"output_md": ROOT / "examples" / "governed-incident-command" / "optimization" / "reports" / "description_optimization.md",
"title": "Governed Incident Description Optimization",
},
}
PROMOTION_TARGETS = {
"root": "yao-meta-skill",
"team-frontend-review": "team-frontend-review",
"governed-incident-command": "governed-incident-command",
}
ARCHETYPE_MODE = {
"scaffold": "scaffold",
"production": "production",
"library": "library",
"governed": "governed",
}
def local_output_runner_command() -> str:
return json.dumps(["python3", "scripts/local_output_eval_runner.py"])
def resolve_target(name: str) -> dict:
if name not in TARGETS:
raise KeyError(f"Unknown target: {name}")
return TARGETS[name]
def resolve_promotion_target(name: str) -> str:
if name not in PROMOTION_TARGETS:
raise KeyError(f"Unknown promotion target: {name}")
return PROMOTION_TARGETS[name]
def baseline_compare_args() -> list[str]:
args = []
for label, target in TARGETS.items():
args.extend(["--entry", f"{label}::{target['output_json']}"])
args.extend(
[
"--output-json",
str(ROOT / "reports" / "baseline-compare.json"),
"--output-md",
str(ROOT / "reports" / "baseline-compare.md"),
]
)
return args
def infer_archetype(job: str, description: str) -> tuple[str, str]:
text = f"{job} {description}".lower()
if any(token in text for token in ("incident", "compliance", "security", "release", "govern", "audit", "policy")):
return "governed", "The request looks operationally sensitive, so governed is the safest default."
if any(token in text for token in ("shared", "cross-team", "library", "portable", "platform", "reusable across")):
return "library", "The request signals multi-team reuse or portability, so library is the better fit."
if any(token in text for token in ("review", "checklist", "team", "workflow", "process", "standardize")):
return "production", "The request looks team-reused and repeatable, so production fits better than scaffold."
return "scaffold", "The request still looks exploratory or lightweight, so scaffold keeps the first package lean."
def archetype_guidance(archetype: str) -> dict:
mapping = {
"scaffold": {
"first_gate": "trigger and exclusions",
"focus": "keep the first package small and avoid governance overhead",
},
"production": {
"first_gate": "trigger plus one execution or eval asset",
"focus": "make the package reliable for team reuse",
},
"library": {
"first_gate": "trigger, portability, and packaging semantics",
"focus": "treat the package as a shared capability with visible evidence",
},
"governed": {
"first_gate": "trigger, governance, and review cadence",
"focus": "treat the package as a high-trust asset from the start",
},
}
return mapping.get(archetype, mapping["scaffold"])
def discovery_summary(job: str, primary_output: str, archetype: str, guidance: dict) -> str:
return (
"\nHere's the shape I'm hearing so far:\n"
f"- Repeated job: {job}\n"
f"- Desired hand-back: {primary_output}\n"
f"- Best starting archetype: {archetype}\n"
f"- First gate: {guidance['first_gate']}\n"
f"- Current focus: {guidance['focus']}\n"
)
def explicit_skill_request(job: str, description: str) -> bool:
text = f"{job} {description}".lower()
return any(token in text for token in ("skill", "workflow", "checklist", "package", "automate", "standardize"))
def diagnose_skill_candidates(job: str, primary_output: str, archetype: str, confidence: dict) -> dict:
fuzzy = not explicit_skill_request(job, primary_output) or confidence.get("score", 0) < 75
candidates = [
{
"shape": archetype,
"recommendation": "recommended",
"why_it_fits": "This is the lightest shape that matches the current recurring job signal.",
"limitation": "It should not deepen until the concrete output and exclusion boundary are clear.",
"first_pass": "Create one routeable skill with honest boundaries, one review report, and one next-step direction.",
}
]
if archetype != "scaffold":
candidates.append(
{
"shape": "scaffold",
"recommendation": "fallback",
"why_it_fits": "Use this if the idea is still exploratory or personal.",
"limitation": "It may under-serve team reuse, portability, or governance needs.",
"first_pass": "Ship only SKILL.md, interface metadata, intent confidence, and review viewer.",
}
)
if archetype not in {"production", "governed"}:
candidates.append(
{
"shape": "production",
"recommendation": "upgrade path",
"why_it_fits": "Use this when the workflow will be repeated by a team or needs consistent outputs.",
"limitation": "It adds validation and review cost that a personal scaffold may not need.",
"first_pass": "Add one practical eval or execution check after the trigger boundary is stable.",
}
)
if archetype != "governed" and any(token in f"{job} {primary_output}".lower() for token in ("risk", "audit", "release", "policy", "security", "compliance")):
candidates.append(
{
"shape": "governed",
"recommendation": "risk path",
"why_it_fits": "Use this if the skill affects operational, compliance, security, or release decisions.",
"limitation": "It is too heavy unless ownership and review cadence are real.",
"first_pass": "Add owner, review cadence, lifecycle metadata, and reviewer-visible evidence.",
}
)
return {
"mode": "fuzzy-problem-diagnosis" if fuzzy else "direct-skill-shaping",
"fuzzy": fuzzy,
"candidates": candidates[:3],
}
def diagnosis_note(diagnosis: dict) -> str:
lines = ["\nProblem-to-skill diagnosis:"]
for candidate in diagnosis["candidates"]:
lines.append(
f"- {candidate['shape']} ({candidate['recommendation']}): {candidate['why_it_fits']} "
f"First pass: {candidate['first_pass']}"
)
return "\n".join(lines) + "\n"
def reference_visibility(reference_synthesis: dict) -> dict:
synthesis = reference_synthesis.get("synthesis", {}) if isinstance(reference_synthesis, dict) else {}
visibility = synthesis.get("visibility", {}) if isinstance(synthesis, dict) else {}
reasons = list(visibility.get("reasons", []))
mode = visibility.get("mode", "explicit" if reasons else "silent")
return {
"mode": mode,
"user_decision_required": mode == "explicit",
"reasons": reasons,
"conflicts": synthesis.get("conflicts", []),
}
def recommendation_from_synthesis(reference_synthesis: dict, visibility: dict) -> dict:
synthesis = reference_synthesis.get("synthesis", {}) if isinstance(reference_synthesis, dict) else {}
recommendation = synthesis.get("recommendation", {}) if isinstance(synthesis, dict) else {}
borrow_now = recommendation.get("borrow_now") or synthesis.get("borrow_now", [])
avoid_now = recommendation.get("avoid_for_now") or synthesis.get("avoid_now", [])
summary = recommendation.get("summary") or (
f"Start with {borrow_now[0]} Avoid {avoid_now[0]} for the first pass."
if borrow_now and avoid_now
else "Start with the smallest high-confidence pattern and keep the first pass light."
)
why = recommendation.get("why") or "This recommendation comes from the benchmark synthesis and current intent confidence."
return {
"summary": summary,
"borrow_now": borrow_now[:2],
"avoid_for_now": avoid_now[:2],
"why": why,
"user_decision_required": visibility["user_decision_required"],
}