Tighten report layout and gate contract evidence

This commit is contained in:
yaojingang
2026-06-16 15:12:32 +08:00
parent 538d7ed401
commit e23f3ffdcf
45 changed files with 499 additions and 351 deletions
+23 -2
View File
@@ -8,7 +8,7 @@ from typing import Any
from review_studio_actions import build_review_actions, render_review_actions
from review_studio_data import evidence_paths, insight_cards, load_review_data
from review_studio_formatting import registry_package_summary, render_kv_grid
from review_studio_gates import add_blockers_from_gate, build_gates, status_label, weighted_score
from review_studio_gates import add_blockers_from_gate, build_gates, gate_contract, status_label, weighted_score
from review_studio_layout import render_review_nav, review_studio_css
from review_studio_output_review import render_output_review_section
from review_studio_skillops import render_skillops_section
@@ -123,6 +123,19 @@ def render_html(report: dict[str, Any]) -> str:
description = overview.get("description") or frontmatter.get("description", "")
nav_html = render_review_nav()
gates_html = render_gate_list(gates)
gate_contract_panel = render_kv_grid(
report.get("gate_contract", {}),
[
"ok",
"expected_gate_count",
"actual_gate_count",
"missing_gate_keys",
"unknown_gate_keys",
"duplicate_gate_keys",
"unweighted_gate_keys",
],
"gate contract missing",
)
metrics_html = render_insights(insights)
blockers_html = render_issue_list("阻断事项", blockers)
warnings_html = render_issue_list("关注事项", warnings)
@@ -413,6 +426,11 @@ def render_html(report: dict[str, Any]) -> str:
<div class="gates">{gates_html}</div>
</section>
<section>
<h2>闸门契约</h2>
<div class="panel">{gate_contract_panel}</div>
</section>
<div class="twocol">
{blockers_html}
{warnings_html}
@@ -584,6 +602,7 @@ def render_review_studio(skill_dir: Path, output_html: Path | None = None, outpu
output_json = output_json or reports_dir / "review-studio.json"
data = load_review_data(skill_dir)
gates = build_gates(skill_dir, output_html, data)
contract = gate_contract(gates)
blockers, warnings = add_blockers_from_gate(gates)
review_actions = build_review_actions(gates, skill_dir, output_html, data)
score = weighted_score(gates)
@@ -593,12 +612,13 @@ def render_review_studio(skill_dir: Path, output_html: Path | None = None, outpu
decision = "blocked" if blockers or open_annotation_blockers else ("review" if warnings or open_annotation_warnings else "ready")
report = {
"schema_version": "2.0",
"ok": True,
"ok": contract["ok"],
"skill_dir": display_path(skill_dir, skill_dir),
"summary": {
"decision": decision,
"world_class_score": score,
"gate_count": len(gates),
"gate_contract_ok": contract["ok"],
"blocker_count": len(blockers),
"warning_count": len(warnings),
"action_count": len(review_actions),
@@ -608,6 +628,7 @@ def render_review_studio(skill_dir: Path, output_html: Path | None = None, outpu
"open_annotation_warning_count": open_annotation_warnings,
},
"gates": gates,
"gate_contract": contract,
"blockers": blockers,
"warnings": warnings,
"review_actions": review_actions,
+7
View File
@@ -19,6 +19,7 @@ LABELS = {
"archive_entry_count": "Zip 条目",
"archive_present": "归档存在",
"archive_sha256": "归档哈希",
"actual_gate_count": "实际 Gate",
"answer_revealed_count": "答案揭示",
"baseline_pass_rate": "Baseline",
"breaking_change_count": "破坏变更",
@@ -31,7 +32,9 @@ LABELS = {
"declared_bump": "声明版本",
"decision": "决策",
"delta": "增益",
"duplicate_gate_keys": "重复 Gate",
"event_count": "事件数",
"expected_gate_count": "期望 Gate",
"failure_count": "失败数",
"file_count": "文件数",
"fstring_311_violation_count": "F-string 3.11",
@@ -56,6 +59,7 @@ LABELS = {
"metadata_fallback_count": "Metadata fallback",
"missed_trigger_count": "漏触发",
"missing_count": "缺失数",
"missing_gate_keys": "缺失 Gate",
"module_count": "模块数",
"model_executed_count": "模型执行",
"name": "名称",
@@ -85,6 +89,7 @@ LABELS = {
"recommended_pr_count": "建议 PR",
"recommended_bump": "建议版本",
"release_lock_ready": "发布锁",
"rendered_gate_keys": "渲染 Gate",
"residual_risk_count": "残余风险",
"risk_band": "风险带",
"route_collision_count": "路由冲突",
@@ -103,6 +108,8 @@ LABELS = {
"token_estimated_count": "估算 Token",
"token_observed_count": "真实 Token",
"trust_level": "信任级别",
"unknown_gate_keys": "未知 Gate",
"unweighted_gate_keys": "未加权 Gate",
"unique_opportunity_count": "唯一机会",
"variant_run_count": "运行数",
"valid_submission_count": "有效提交",
+22
View File
@@ -3,6 +3,7 @@
import json
import os
from collections import Counter
from pathlib import Path
from typing import Any
@@ -80,6 +81,27 @@ def add_blockers_from_gate(gates: list[dict[str, str]]) -> tuple[list[dict[str,
return blockers, warnings
def gate_contract(gates: list[dict[str, str]]) -> dict[str, Any]:
rendered_gate_keys = [str(item.get("key", "")) for item in gates]
rendered_gate_set = set(rendered_gate_keys)
expected_gate_set = set(REVIEW_STUDIO_GATE_KEYS)
duplicate_gate_keys = sorted(key for key, count in Counter(rendered_gate_keys).items() if count > 1)
missing_gate_keys = sorted(expected_gate_set - rendered_gate_set)
unknown_gate_keys = sorted(rendered_gate_set - expected_gate_set)
unweighted_gate_keys = sorted(rendered_gate_set - set(GATE_WEIGHTS))
return {
"ok": not (missing_gate_keys or unknown_gate_keys or duplicate_gate_keys or unweighted_gate_keys),
"expected_gate_count": len(expected_gate_set),
"actual_gate_count": len(rendered_gate_keys),
"expected_gate_keys": sorted(expected_gate_set),
"rendered_gate_keys": rendered_gate_keys,
"missing_gate_keys": missing_gate_keys,
"unknown_gate_keys": unknown_gate_keys,
"duplicate_gate_keys": duplicate_gate_keys,
"unweighted_gate_keys": unweighted_gate_keys,
}
def target_maturity(skill_dir: Path, overview: dict[str, Any]) -> str:
manifest = _load_json(skill_dir / "manifest.json")
if manifest.get("maturity_tier"):