Merge pull request #8 from yaojingang/codex/blind-human-review-evidence
Add human blind review evidence
This commit is contained in:
@@ -8,7 +8,7 @@
|
||||
[](docs/README.fr-FR.md)
|
||||
[](docs/README.ru-RU.md)
|
||||
|
||||
`YAO` stands for `Yielding AI Outcomes` — the goal is not to generate more prompt text, but to produce reusable AI assets and real operational outcomes.
|
||||
`YAO` stands for `Yielding AI Outcomes`: the goal is not to generate more prompt text, but to produce reusable AI assets and real operational outcomes.
|
||||
|
||||
`yao-meta-skill` creates, evaluates, packages, and governs reusable agent skills. The 1.0 line focused on turning repeated workflows into installable, readable, cross-platform skill packages. The 2.0 line expands that factory into a Skill OS: a governed system for modeling a skill once, compiling it for multiple targets, testing its behavior, reviewing its release evidence, and tracking the next iteration.
|
||||
|
||||
@@ -141,6 +141,8 @@ Read it in 10 seconds:
|
||||
|
||||
This benchmark is a project-level engineering review, scored from `0-10` per dimension and weighted to `100`. GitHub stars are intentionally excluded because they measure ecosystem heat, not meta-skill engineering quality.
|
||||
|
||||
The score is local engineering evidence, not a claim of world-class readiness. Public superiority claims still depend on accepted external and human evidence in the world-class ledger.
|
||||
|
||||
Weighted score formula: `sum(score / 10 * weight)`.
|
||||
|
||||
| Meta Skill | Method Depth 15 | Context Discipline 10 | Toolchain 15 | Eval/Test Rigor 20 | Governance 15 | Portability 10 | Onboarding/Review 5 | Local Reliability 10 | Weighted Score |
|
||||
@@ -155,6 +157,20 @@ Weighted score formula: `sum(score / 10 * weight)`.
|
||||
| 2 | Anthropic Skill Creator | 67.5 | Strong methodology and iteration loop, with weaker local execution reliability and governance coverage. |
|
||||
| 3 | OpenAI Skill Creator | 50.5 | Best treated as a concise skill-writing method guide rather than a full engineering system. |
|
||||
|
||||
## Human Blind A/B Review Snapshot
|
||||
|
||||
On 2026-06-29, a single human reviewer compared `yao-meta-skill` with the bundled OpenAI `skill-creator` across five realistic skill-creation scenarios: support triage, revenue reconciliation, webinar repurposing, incident postmortems, and PR review follow-up. The reviewer confirmed decisions were completed before the answer key was opened.
|
||||
|
||||
Result: `yao-meta-skill` was selected in `5/5` cases.
|
||||
|
||||
Evidence:
|
||||
|
||||
- Review entrypoint: [reports/blind-human-review-2026-06-29/index.html](reports/blind-human-review-2026-06-29/index.html)
|
||||
- Adjudication summary: [reports/blind-human-review-2026-06-29/adjudication.md](reports/blind-human-review-2026-06-29/adjudication.md)
|
||||
- Recorded decisions: [reports/blind-human-review-2026-06-29/review-decisions.recorded.json](reports/blind-human-review-2026-06-29/review-decisions.recorded.json)
|
||||
|
||||
Boundary: this is single-reviewer blind preference evidence. It is not provider-backed independent model execution evidence, and the per-case rationale fields are still empty.
|
||||
|
||||
## Best-Fit Scenarios
|
||||
|
||||
- Choose **Yao Meta Skill** when the target is a reusable team asset with explicit boundaries, trigger evaluation, governance, packaging, portability, and local execution checks.
|
||||
@@ -372,6 +388,7 @@ Full reports: [reports/eval_suite.json](reports/eval_suite.json) and [reports/fa
|
||||
- portability score: `100/100` with neutral activation, execution, trust, and degradation metadata preserved across all exported targets
|
||||
- description optimization suite: root, team frontend review, and governed incident command pass blind and adversarial holdout gates; governed incident command still carries one visible holdout miss, and adversarial calibration plus family drift are now tracked separately
|
||||
- judge-backed blind eval: root, team frontend review, and governed incident command now pass an independent rubric judge on blind holdout prompts
|
||||
- human blind A/B snapshot: a single reviewer selected `yao-meta-skill` over the bundled OpenAI `skill-creator` in `5/5` realistic skill-creation scenarios; evidence is published in [reports/blind-human-review-2026-06-29/adjudication.md](reports/blind-human-review-2026-06-29/adjudication.md)
|
||||
- packaging failure fixtures: invalid metadata, invalid YAML, and unsupported targets fail as expected
|
||||
- failure library regressions: anti-pattern families pass automated checks
|
||||
- governance and resource-boundary checks are part of the default test path
|
||||
|
||||
@@ -121,6 +121,8 @@ flowchart LR
|
||||
|
||||
下面是当前项目采用的工程质量评测模型。每个维度按 `0-10` 评分,再按权重折算到 `100` 分。GitHub stars 不计入总分,因为它反映生态热度,不直接代表元 skill 工程质量。
|
||||
|
||||
这个分数是本地工程证据,不等同于 world-class ready。公开宣称“已证明优于其他方案”仍要以 world-class ledger 中已接受的外部证据和人工证据为准。
|
||||
|
||||
加权总分公式:`sum(单项评分 / 10 * 权重)`。
|
||||
|
||||
| 元 Skill | 方法论深度 15 | 上下文纪律 10 | 工具链 15 | Eval/测试 20 | 治理 15 | 可移植 10 | 上手/评审 5 | 本地可靠性 10 | 加权总分 |
|
||||
@@ -135,6 +137,20 @@ flowchart LR
|
||||
| 2 | Anthropic Skill Creator | 67.5 | 方法论和迭代闭环强,但本地执行可靠性和治理覆盖较弱。 |
|
||||
| 3 | OpenAI Skill Creator | 50.5 | 更适合作为精简 skill 写作方法论教材,而不是完整工程系统。 |
|
||||
|
||||
## 人工盲测快照
|
||||
|
||||
2026-06-29,一位人工评审者在 5 个真实常见的 skill 创建场景里,对比了 `yao-meta-skill` 和内置的 OpenAI `skill-creator`。5 个场景分别是客服工单分诊、月度收入对账、Webinar 内容复用、故障复盘和 PR Review 跟进。评审者确认:所有选择都在揭晓来源前完成。
|
||||
|
||||
结果:`yao-meta-skill` 在 `5/5` 个案例中胜出。
|
||||
|
||||
证据:
|
||||
|
||||
- 盲测入口:[reports/blind-human-review-2026-06-29/index.html](../reports/blind-human-review-2026-06-29/index.html)
|
||||
- Adjudication 摘要:[reports/blind-human-review-2026-06-29/adjudication.md](../reports/blind-human-review-2026-06-29/adjudication.md)
|
||||
- 已记录判断:[reports/blind-human-review-2026-06-29/review-decisions.recorded.json](../reports/blind-human-review-2026-06-29/review-decisions.recorded.json)
|
||||
|
||||
边界:这是单人盲测偏好证据,不是 provider-backed 的独立模型执行证据;每个案例的逐项理由仍为空。
|
||||
|
||||
## 与其他元 Skill 的适用差异
|
||||
|
||||
- 如果你要的是**团队复用、显式边界、质量门、治理、可移植性和长期维护**,更适合 `Yao Meta Skill`。
|
||||
@@ -158,6 +174,7 @@ flowchart LR
|
||||
- 中文真实表达已经纳入触发评测,覆盖“做一个 skill”“沉淀成可复用能力”“优化已有 skill”“补 trigger 评测”等常见说法
|
||||
- registry 记录的目标平台从 OpenAI、Claude、Generic 扩展到 Agent Skills 和 VS Code 相关适配
|
||||
- Review Studio 当前汇总 16 个门禁,包体验证、安装模拟、证据一致性和发布声明边界已经进入报告链路
|
||||
- 单人盲测快照中,评审者在揭晓来源前完成判断,并在 `5/5` 个真实 skill 创建场景中选择 `yao-meta-skill`;证据见 [reports/blind-human-review-2026-06-29/adjudication.md](../reports/blind-human-review-2026-06-29/adjudication.md)
|
||||
|
||||
## 当前优势
|
||||
|
||||
|
||||
@@ -0,0 +1,149 @@
|
||||
<!doctype html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>答案钥匙 - Skill 盲测评审</title>
|
||||
<style>
|
||||
:root {
|
||||
color-scheme: light;
|
||||
--bg: #f7f8fb;
|
||||
--panel: #ffffff;
|
||||
--ink: #20242c;
|
||||
--muted: #687082;
|
||||
--line: #d9deea;
|
||||
--accent: #2563eb;
|
||||
--accent-2: #0f766e;
|
||||
--warn: #b45309;
|
||||
}
|
||||
* { box-sizing: border-box; }
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
|
||||
background: var(--bg);
|
||||
color: var(--ink);
|
||||
line-height: 1.55;
|
||||
}
|
||||
header {
|
||||
padding: 28px clamp(18px, 4vw, 52px) 18px;
|
||||
background: #ffffff;
|
||||
border-bottom: 1px solid var(--line);
|
||||
}
|
||||
main { padding: 24px clamp(18px, 4vw, 52px) 52px; }
|
||||
h1 { margin: 0 0 8px; font-size: clamp(26px, 3vw, 38px); letter-spacing: 0; }
|
||||
h2 { margin: 0 0 12px; font-size: 20px; }
|
||||
h3 { margin: 18px 0 8px; font-size: 16px; }
|
||||
p { margin: 0 0 10px; }
|
||||
a { color: var(--accent); text-decoration: none; }
|
||||
a:hover { text-decoration: underline; }
|
||||
.meta, .note { color: var(--muted); }
|
||||
.grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 18px; align-items: start; }
|
||||
.card, .panel {
|
||||
background: var(--panel);
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 8px;
|
||||
padding: 18px;
|
||||
}
|
||||
.case-list { display: grid; gap: 12px; margin-top: 18px; }
|
||||
.case-row {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr auto;
|
||||
gap: 12px;
|
||||
align-items: center;
|
||||
background: var(--panel);
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 8px;
|
||||
padding: 14px 16px;
|
||||
}
|
||||
.badge {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
min-height: 28px;
|
||||
padding: 4px 10px;
|
||||
border-radius: 999px;
|
||||
background: #e8f0ff;
|
||||
color: #1d4ed8;
|
||||
font-size: 13px;
|
||||
font-weight: 650;
|
||||
}
|
||||
.rubric { margin: 0; padding-left: 20px; }
|
||||
.rubric li { margin-bottom: 6px; }
|
||||
.variant {
|
||||
background: var(--panel);
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
}
|
||||
.variant-head {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
gap: 12px;
|
||||
align-items: center;
|
||||
padding: 12px 16px;
|
||||
border-bottom: 1px solid var(--line);
|
||||
background: #f2f5fa;
|
||||
}
|
||||
.variant-body { padding: 16px; }
|
||||
pre {
|
||||
overflow: auto;
|
||||
padding: 12px;
|
||||
border-radius: 6px;
|
||||
background: #111827;
|
||||
color: #f9fafb;
|
||||
font-size: 13px;
|
||||
}
|
||||
code { font-family: "SFMono-Regular", Consolas, monospace; }
|
||||
.review-box {
|
||||
margin-top: 18px;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 8px;
|
||||
padding: 16px;
|
||||
background: #fff;
|
||||
}
|
||||
.controls { display: flex; flex-wrap: wrap; gap: 10px; margin: 12px 0; }
|
||||
button, .button {
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 6px;
|
||||
background: #fff;
|
||||
color: var(--ink);
|
||||
min-height: 36px;
|
||||
padding: 7px 12px;
|
||||
cursor: pointer;
|
||||
font-weight: 650;
|
||||
}
|
||||
button.primary, .button.primary { background: var(--accent); border-color: var(--accent); color: #fff; }
|
||||
textarea {
|
||||
width: 100%;
|
||||
min-height: 96px;
|
||||
resize: vertical;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 6px;
|
||||
padding: 10px;
|
||||
font: inherit;
|
||||
}
|
||||
.warn { color: var(--warn); font-weight: 650; }
|
||||
.split { display: flex; flex-wrap: wrap; gap: 10px; }
|
||||
.small { font-size: 13px; }
|
||||
@media (max-width: 900px) {
|
||||
.grid { grid-template-columns: 1fr; }
|
||||
.case-row { grid-template-columns: 1fr; }
|
||||
}
|
||||
table { width:100%; border-collapse: collapse; } td, th { border:1px solid var(--line); padding:8px; text-align:left; }</style>
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<a class="button" href="index.html">返回入口</a>
|
||||
<h1>答案钥匙</h1>
|
||||
<p class="warn">请只在所有评审判断都记录完成后再打开。</p>
|
||||
</header>
|
||||
<main>
|
||||
<section class="panel">
|
||||
<table>
|
||||
<thead><tr><th>案例</th><th>方案 A 来源</th><th>方案 B 来源</th></tr></thead>
|
||||
<tbody><tr><td>case-01-support-triage</td><td>官方 skill-creator</td><td>yao-meta-skill</td></tr><tr><td>case-02-monthly-revenue-reconciliation</td><td>yao-meta-skill</td><td>官方 skill-creator</td></tr><tr><td>case-03-webinar-repurposing</td><td>官方 skill-creator</td><td>yao-meta-skill</td></tr><tr><td>case-04-incident-postmortem</td><td>yao-meta-skill</td><td>官方 skill-creator</td></tr><tr><td>case-05-pr-review-followup</td><td>官方 skill-creator</td><td>yao-meta-skill</td></tr></tbody>
|
||||
</table>
|
||||
<p class="note" style="margin-top:12px">来源路径:yao-meta-skill = /Users/laoyao/AI Coding/03-Development/Skills/yao-meta-skill/SKILL.md;官方 skill-creator = /Users/laoyao/.codex/skills/.system/skill-creator/SKILL.md。</p>
|
||||
</section>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,62 @@
|
||||
{
|
||||
"schema_version": "1.0",
|
||||
"seed": "blind-human-review-2026-06-29-v1",
|
||||
"answer_key_warning": "请只在记录完所有判断后再打开。",
|
||||
"answers": [
|
||||
{
|
||||
"case_id": "case-01-support-triage",
|
||||
"variant_a_source": "official",
|
||||
"variant_b_source": "yao",
|
||||
"variant_a_source_label": "官方 skill-creator",
|
||||
"variant_b_source_label": "yao-meta-skill",
|
||||
"source_paths": {
|
||||
"yao": "/Users/laoyao/AI Coding/03-Development/Skills/yao-meta-skill/SKILL.md",
|
||||
"official": "/Users/laoyao/.codex/skills/.system/skill-creator/SKILL.md"
|
||||
}
|
||||
},
|
||||
{
|
||||
"case_id": "case-02-monthly-revenue-reconciliation",
|
||||
"variant_a_source": "yao",
|
||||
"variant_b_source": "official",
|
||||
"variant_a_source_label": "yao-meta-skill",
|
||||
"variant_b_source_label": "官方 skill-creator",
|
||||
"source_paths": {
|
||||
"yao": "/Users/laoyao/AI Coding/03-Development/Skills/yao-meta-skill/SKILL.md",
|
||||
"official": "/Users/laoyao/.codex/skills/.system/skill-creator/SKILL.md"
|
||||
}
|
||||
},
|
||||
{
|
||||
"case_id": "case-03-webinar-repurposing",
|
||||
"variant_a_source": "official",
|
||||
"variant_b_source": "yao",
|
||||
"variant_a_source_label": "官方 skill-creator",
|
||||
"variant_b_source_label": "yao-meta-skill",
|
||||
"source_paths": {
|
||||
"yao": "/Users/laoyao/AI Coding/03-Development/Skills/yao-meta-skill/SKILL.md",
|
||||
"official": "/Users/laoyao/.codex/skills/.system/skill-creator/SKILL.md"
|
||||
}
|
||||
},
|
||||
{
|
||||
"case_id": "case-04-incident-postmortem",
|
||||
"variant_a_source": "yao",
|
||||
"variant_b_source": "official",
|
||||
"variant_a_source_label": "yao-meta-skill",
|
||||
"variant_b_source_label": "官方 skill-creator",
|
||||
"source_paths": {
|
||||
"yao": "/Users/laoyao/AI Coding/03-Development/Skills/yao-meta-skill/SKILL.md",
|
||||
"official": "/Users/laoyao/.codex/skills/.system/skill-creator/SKILL.md"
|
||||
}
|
||||
},
|
||||
{
|
||||
"case_id": "case-05-pr-review-followup",
|
||||
"variant_a_source": "official",
|
||||
"variant_b_source": "yao",
|
||||
"variant_a_source_label": "官方 skill-creator",
|
||||
"variant_b_source_label": "yao-meta-skill",
|
||||
"source_paths": {
|
||||
"yao": "/Users/laoyao/AI Coding/03-Development/Skills/yao-meta-skill/SKILL.md",
|
||||
"official": "/Users/laoyao/.codex/skills/.system/skill-creator/SKILL.md"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
# 人工盲测结果
|
||||
|
||||
这组材料记录了 2026-06-29 的单人 A/B 盲测。评审者在揭晓来源前完成了 5 个判断,结果为 `yao-meta-skill` 5 胜,官方 `skill-creator` 0 胜。
|
||||
|
||||
## 文件
|
||||
|
||||
- [index.html](index.html):盲测入口。
|
||||
- [adjudication.md](adjudication.md):揭晓后的统计摘要。
|
||||
- [review-decisions.recorded.json](review-decisions.recorded.json):评审者选择、确认和证据边界。
|
||||
- [blind-pack.json](blind-pack.json):不含答案钥匙的盲测包。
|
||||
- [DO_NOT_OPEN_answer_key.json](DO_NOT_OPEN_answer_key.json):答案钥匙,只应在评审完成后打开。
|
||||
|
||||
## 证据边界
|
||||
|
||||
这可以作为单人盲测偏好证据。它不等同于 provider-backed 的独立模型执行证据,也不等同于 world-class readiness。当前缺口是逐案理由为空、评审人数为 1,尚未形成多评审者一致性证据。
|
||||
@@ -0,0 +1,39 @@
|
||||
# 人工盲测 Adjudication
|
||||
|
||||
生成时间:`2026-06-29T03:04:34Z`
|
||||
|
||||
## 结论
|
||||
|
||||
在 5 个真实常见 skill 创建场景的单人盲测中,评审者在揭晓来源前完成判断,5/5 选择了 `yao-meta-skill` 输出。
|
||||
|
||||
| 案例 | 评审选择 | 揭晓来源 |
|
||||
| --- | --- | --- |
|
||||
| `case-01-support-triage` | B | `yao-meta-skill` |
|
||||
| `case-02-monthly-revenue-reconciliation` | A | `yao-meta-skill` |
|
||||
| `case-03-webinar-repurposing` | B | `yao-meta-skill` |
|
||||
| `case-04-incident-postmortem` | A | `yao-meta-skill` |
|
||||
| `case-05-pr-review-followup` | B | `yao-meta-skill` |
|
||||
|
||||
## 统计
|
||||
|
||||
- `yao-meta-skill`:5
|
||||
- 官方 `skill-creator`:0
|
||||
- 平局:0
|
||||
- 评审人数:1
|
||||
- 信心程度:5 个判断均为 `1.0`
|
||||
|
||||
## 盲审确认
|
||||
|
||||
评审者确认:
|
||||
|
||||
> 确认:我是在完成五个判断之后才让你打开答案钥匙的,评审前没有看来源。以上 5 个判断都是揭晓来源前完成的。
|
||||
|
||||
## 证据边界
|
||||
|
||||
这可以作为单人独立盲测偏好证据。它不等同于 provider-backed 独立模型执行证据,因为两个输出是本地按两份 skill 说明生成的。
|
||||
|
||||
当前缺口:
|
||||
|
||||
- 每个案例的 `reason` 字段为空,缺少逐案 rationale。
|
||||
- 评审人数为 1,尚未形成多评审者一致性证据。
|
||||
- 尚未加入外部冻结 holdout 任务集。
|
||||
@@ -0,0 +1,98 @@
|
||||
{
|
||||
"schema_version": "1.0",
|
||||
"seed": "blind-human-review-2026-06-29-v1",
|
||||
"generated_by": "Codex 在本地套用两份 skill 说明生成",
|
||||
"evidence_boundary": "人类盲测评审起始包;不是 provider-backed 的独立模型执行证据。",
|
||||
"cases": [
|
||||
{
|
||||
"id": "case-01-support-triage",
|
||||
"title": "客服工单分诊 Skill",
|
||||
"scenario": "一个 B2B SaaS 团队每天都要处理客户工单:判断分类、紧急程度、起草首轮回复,并把账务、安全、故障类问题升级给对应负责人。他们希望把这个重复流程做成一个给支持团队使用的 Codex skill。",
|
||||
"user_prompt": "请把我们反复使用的客服工单分诊流程做成一个团队可复用的 skill。输入包括原始工单文本、客户等级、产品模块和近期故障记录。输出需要包含问题分类、紧急程度、首轮回复草稿、升级负责人和判断依据。不要把 PII 泄露到报告里。",
|
||||
"rubric": [
|
||||
"是否有清楚的触发边界和近邻排除。",
|
||||
"是否是可复用的 skill 包结构,而不只是一个提示词。",
|
||||
"是否定义了分类、紧急程度、回复、升级和证据的输出契约。",
|
||||
"是否处理 PII 和客户内容的隐私风险。",
|
||||
"是否有能发现错误升级和泛泛回复的评测方案。"
|
||||
],
|
||||
"variants": {
|
||||
"A": "## 建议 Skill:support-triage\n\n### 目的\n创建一个简洁的 skill,帮助 Codex 对 B2B SaaS 客服工单进行分诊,并起草首轮回复。\n\n### 建议包结构\n```\nsupport-triage/\n SKILL.md\n agents/openai.yaml\n references/\n triage-taxonomy.md\n escalation-policy.md\n```\n\n### SKILL.md 草稿\n```markdown\n---\nname: support-triage\ndescription: 对 B2B SaaS 客服工单进行分诊并起草首轮回复。当用户提供原始工单文本、客户等级、产品模块、故障记录,或需要紧急程度、分类、升级建议时使用。\n---\n\n# 客服工单分诊\n\n使用这个 skill 对入站工单分类、起草合适的首轮回复,并识别是否需要升级。\n\n## 工作流\n1. 阅读工单文本、客户等级、产品模块和近期故障记录。\n2. 将工单归为一个主分类:账务、访问权限、缺陷、故障、功能请求、安全、数据/隐私、上手问题或其他。\n3. 标记紧急程度:低、普通、高、严重。\n4. 起草首轮回复:确认问题、只询问必要补充信息,并避免没有依据的承诺。\n5. 对安全、隐私、严重故障、数据丢失或企业客户影响问题进行升级。\n6. 汇报判断依据,但不要复制不必要的 PII。\n\n## 输出格式\n- 分类:\n- 紧急程度:\n- 首轮回复:\n- 升级负责人:\n- 判断依据:\n- 缺失信息:\n\n## 参考资料\n- 分类规则见 `references/triage-taxonomy.md`。\n- 升级标准见 `references/escalation-policy.md`。\n```\n\n### agents/openai.yaml\n```yaml\ndisplay_name: 客服工单分诊\nshort_description: 对客服工单分类,并起草首轮回复。\ndefault_prompt: 请分诊这个客服工单,并起草首轮回复。\n```\n\n### 资源\n- `references/triage-taxonomy.md`:分类定义、紧急程度提示和示例。\n- `references/escalation-policy.md`:升级负责人和升级标准。\n\n### 验证\n用账务、安全、故障和功能请求等代表性工单测试。确认输出会最小化 PII,并且严重问题会被升级。\n",
|
||||
"B": "## Skill 包建议:support-triage\n\n### 边界\n负责重复出现的客服工单分诊:用户提供工单文本以及客户/产品上下文,需要结构化路由决策。不要用于一次性文案润色、泛泛的客服同理心训练、CRM 配置,或超出升级范围的法律/安全事件处置。\n\n### 输出契约\n这个 skill 必须返回:\n- `category`\n- `urgency`\n- `first_response_draft`\n- `escalation_owner`\n- `evidence_used`\n- `missing_information`\n- `pii_handling_note`\n\n### 包结构\n```\nsupport-triage/\n SKILL.md\n agents/interface.yaml\n references/\n triage-taxonomy.md\n escalation-policy.md\n privacy-redaction.md\n evals/\n trigger_cases.json\n output/\n cases.jsonl\n fixtures/\n reports/\n output-risk-profile.md\n output_quality_scorecard.md\n```\n\n### SKILL.md\n```markdown\n---\nname: support-triage\ndescription: 将重复出现的 B2B SaaS 客服工单分诊为分类、紧急程度、首轮回复、升级负责人、判断依据和缺失信息。当输入包含原始工单、客户等级、产品模块、故障记录或支持队列上下文时使用。不要用于一次性文案润色、CRM 设置、法律建议或最终安全事件处置。\n---\n\n# 客服工单分诊\n\n## 工作流\n1. 确认这是重复的工单分诊任务,而不是一次性文案润色。\n2. 阅读工单文本、客户等级、产品模块和故障记录。\n3. 使用 `references/triage-taxonomy.md` 判断分类和紧急程度。\n4. 按 `references/escalation-policy.md` 检查升级标准。\n5. 起草首轮回复:确认问题、避免无依据承诺,只请求最少的缺失信息。\n6. 按 `references/privacy-redaction.md` 对 PII 做脱敏或摘要。\n7. 严格按输出契约返回。\n\n## 必填输出\n使用这些字段:\n- category\n- urgency\n- first_response_draft\n- escalation_owner\n- evidence_used\n- missing_information\n- pii_handling_note\n```\n\n### agents/interface.yaml\n```yaml\ndisplay_name: 客服工单分诊\nshort_description: 对工单分类、起草首轮回复,并给出升级依据。\ndefault_prompt: 请用分类、紧急程度、回复、升级负责人和依据来分诊这个客服工单。\n```\n\n### 评测用例\n1. 企业客户在已知故障期间提交工单:必须标为 `critical`,并升级给 incident commander。\n2. SMB 客户的账务困惑:不应过度升级。\n3. 带客户邮箱和 token 片段的安全披露:必须脱敏 token,并升级安全团队。\n4. 伪装成投诉的功能请求:应归类为功能请求,紧急程度为普通。\n5. 近邻请求:“把这段回复改得更温和”不应触发包级分诊。\n\n### 发布门禁\n- 触发评测:正例、反例、近邻文案润色。\n- 输出评测:首轮回复不能编造 SLA,升级必须匹配策略。\n- 隐私检查:报告不能保存原始工单 PII。\n- 审查备注:如果分类规则或升级负责人未提供,标记为 `missing evidence`,不要编造。\n\n### 下一步\n加入 3 个匿名工单 fixture,运行输出评测,并记录错误升级、泛泛回复和 PII 泄露的失败分类。\n"
|
||||
},
|
||||
"html_report": "case-01-support-triage.html"
|
||||
},
|
||||
{
|
||||
"id": "case-02-monthly-revenue-reconciliation",
|
||||
"title": "月度收入对账 Skill",
|
||||
"scenario": "一个财务运营团队每个月结账前都要比对 Stripe 导出、数据仓库发票 CSV 和人工调整表,找出金额、币种、发票和调整项的不一致。",
|
||||
"user_prompt": "请创建一个用于月度收入对账的可复用 skill。输入是 Stripe balance export CSV、warehouse invoice CSV 和 adjustments sheet。输出需要标出不一致项、解释可能原因,并生成可用于月结的摘要。准确性比速度更重要。",
|
||||
"rubric": [
|
||||
"是否识别出这是 file-backed 且准确性敏感的任务。",
|
||||
"是否定义了确定性脚本和资源边界。",
|
||||
"是否说明输入/输出 schema 与对账容差。",
|
||||
"是否包含 fixture 和失败用例验证。",
|
||||
"是否避免编造财务事实或隐藏未解决差异。"
|
||||
],
|
||||
"variants": {
|
||||
"A": "## Skill 包建议:revenue-reconciliation\n\n### 边界\n负责围绕 Stripe balance export、warehouse invoice CSV 和调整表的重复月结对账。排除税务建议、收入确认政策决策、支付渠道配置和一次性表格美化。\n\n### 风险等级\nGoverned,file-backed,准确性敏感。任何可用于月结的结论前,都必须有确定性解析和可见的未解决项目。\n\n### 包结构\n```\nrevenue-reconciliation/\n SKILL.md\n agents/interface.yaml\n scripts/\n reconcile_revenue.py\n validate_reconciliation_fixture.py\n references/\n input-schema.md\n tolerance-policy.md\n close-summary-contract.md\n evals/\n output/\n cases.jsonl\n fixtures/\n stripe_sample.csv\n warehouse_sample.csv\n adjustments_sample.csv\n reports/\n output-risk-profile.md\n output_quality_scorecard.md\n trust_report.md\n```\n\n### SKILL.md\n```markdown\n---\nname: revenue-reconciliation\ndescription: 对来自 Stripe 导出、warehouse invoice CSV 和调整表的重复月结收入文件进行对账。用于 file-backed 差异检测、可能原因分析、未解决项目报告和月结摘要。不要用于收入确认建议、税务指导、支付渠道配置或一次性表格格式整理。\n---\n\n# 收入对账\n\n## 工作流\n1. 要求提供所有输入文件;缺失文件必须标记为 `missing evidence`。\n2. 阅读 `references/input-schema.md`,先校验列再分析。\n3. 运行 `scripts/reconcile_revenue.py`,规范化 ID、币种、金额精度、日期和调整项关联。\n4. 审查 JSON 输出,并按缺失发票、金额差异、币种差异、重复项、时间差异或仅调整项分类。\n5. 只基于脚本证据生成月结摘要。\n6. 保持未解决差异可见。不要编造原因、审批或政策判断。\n\n## 输出契约\n- input_files\n- validation_status\n- totals_by_source\n- matched_count\n- mismatch_table\n- likely_causes\n- unresolved_items\n- close_ready_summary\n- missing_evidence\n```\n\n### 确定性脚本契约\n`scripts/reconcile_revenue.py` 应接受:\n```bash\npython3 scripts/reconcile_revenue.py --stripe stripe.csv --warehouse warehouse.csv --adjustments adjustments.csv --output reconciliation.json\n```\n\n它应返回包含源行 ID 的结构化 JSON,让摘要里的每个结论都能追溯到 file-backed fixture。\n\n### 评测\n- Fixture 1:所有记录匹配。\n- Fixture 2:Stripe 有付款,但 warehouse 缺发票。\n- Fixture 3:warehouse 金额超过容差。\n- Fixture 4:人工调整解释了差异。\n- 近邻请求:“把这个表格弄好看一点”不应路由到这里。\n\n### 门禁\n- 汇总前必须通过输入 schema 校验。\n- 如果遗漏未解决差异,输出评测必须失败。\n- Trust check 应标记网络访问为不必要。\n- Review Studio 应在晋级前显示 file-backed fixture 覆盖和未解决差异处理。\n",
|
||||
"B": "## 建议 Skill:revenue-reconciliation\n\n### 目的\n帮助 Codex 对 Stripe、数据仓库发票和人工调整表中的月度收入记录进行对账。\n\n### 建议包结构\n```\nrevenue-reconciliation/\n SKILL.md\n agents/openai.yaml\n scripts/\n reconcile_revenue.py\n references/\n csv-schema.md\n```\n\n### SKILL.md 草稿\n```markdown\n---\nname: revenue-reconciliation\ndescription: 对 Stripe balance export、warehouse invoice CSV 和调整表中的月度收入数据进行对账。当用户要求比较收入文件、找出不一致项或准备月结摘要时使用。\n---\n\n# 收入对账\n\n## 工作流\n1. 确认用户提供了 Stripe 导出、warehouse invoice CSV 和调整表。\n2. 阅读 `references/csv-schema.md`,了解预期列。\n3. 使用用户提供的文件运行 `scripts/reconcile_revenue.py`。\n4. 审查不一致项,并总结可能原因。\n5. 不要编造缺失值。清楚标记未解决记录。\n\n## 输出\n- 已检查文件\n- 匹配总额\n- 不一致项\n- 可能原因\n- 未解决项目\n- 月结摘要\n```\n\n### 脚本\n`scripts/reconcile_revenue.py` 应解析 CSV 输入,规范化 invoice ID 和币种,比较金额,并输出 JSON 供 Codex 总结。\n\n### agents/openai.yaml\n```yaml\ndisplay_name: 收入对账\nshort_description: 比对收入 CSV,并总结月结差异。\ndefault_prompt: 请对这些收入文件进行对账,并生成月结摘要。\n```\n\n### 验证\n使用包含匹配发票、缺失发票、重复发票和仅调整项记录的样例 CSV。确认未解决差异不会被隐藏。\n"
|
||||
},
|
||||
"html_report": "case-02-monthly-revenue-reconciliation.html"
|
||||
},
|
||||
{
|
||||
"id": "case-03-webinar-repurposing",
|
||||
"title": "Webinar 内容复用 Skill",
|
||||
"scenario": "一个市场团队经常把 webinar 逐字稿改写成 LinkedIn 帖子、邮件 teaser 和 newsletter 段落,同时必须保证所有说法都有来源,并避开禁止宣传的 claim。",
|
||||
"user_prompt": "请做一个可复用 skill,把 webinar 逐字稿复用成市场内容。输入包括逐字稿、讲者姓名、产品定位说明和禁止使用的 claim。输出包括 LinkedIn 帖子、邮件 teaser、newsletter 段落、可引用金句和来源依据说明。",
|
||||
"rubric": [
|
||||
"是否保留来源约束,并处理 banned claims。",
|
||||
"是否定义可重复的多渠道输出格式。",
|
||||
"是否把语气和定位资料放到 references,避免入口膨胀。",
|
||||
"是否有针对幻觉 claim 和泛泛市场文案的评测。",
|
||||
"是否在中等治理风险下保持 skill 足够轻量。"
|
||||
],
|
||||
"variants": {
|
||||
"A": "## 建议 Skill:webinar-repurposer\n\n### 目的\n创建一个 skill,把 webinar 逐字稿转成可复用的市场内容。\n\n### 包结构\n```\nwebinar-repurposer/\n SKILL.md\n agents/openai.yaml\n references/\n brand-voice.md\n banned-claims.md\n```\n\n### SKILL.md 草稿\n```markdown\n---\nname: webinar-repurposer\ndescription: 将 webinar 逐字稿复用成 LinkedIn 帖子、邮件 teaser、newsletter 段落、可引用金句和来源依据说明。当用户提供逐字稿、讲者、定位说明或禁止 claim 时使用。\n---\n\n# Webinar 内容复用\n\n## 工作流\n1. 阅读逐字稿、讲者姓名、产品定位说明和禁止 claim。\n2. 提取核心主题、最强的来源支持观点和可用引语。\n3. 起草一条 LinkedIn 帖子、一段邮件 teaser、一段 newsletter 和若干金句。\n4. 对照逐字稿和禁止 claim 检查每个说法。\n5. 为重要 claim 添加来源依据说明。\n\n## 输出\n- LinkedIn 帖子\n- 邮件 teaser\n- Newsletter 段落\n- 可引用金句\n- 来源依据说明\n- 已避免的 claim\n\n## 参考资料\n语气见 `references/brand-voice.md`,禁止 claim 见 `references/banned-claims.md`。\n```\n\n### agents/openai.yaml\n```yaml\ndisplay_name: Webinar 内容复用\nshort_description: 将 webinar 逐字稿转成有来源依据的市场内容。\ndefault_prompt: 请把这份 webinar 逐字稿复用成可发布的多渠道市场内容。\n```\n\n### 验证\n用包含强金句、证据较弱、以及容易误用禁止 claim 的逐字稿测试。确认输出会避免没有依据的 claim。\n",
|
||||
"B": "## Skill 包建议:webinar-repurposer\n\n### 边界\n负责在提供来源逐字稿和定位约束时,把逐字稿复用为市场内容。排除全新 campaign strategy、没有依据的产品 claim、法律审核和一次性文案润色。\n\n### 类型\nProduction-light。它需要输出质量检查和 banned-claim 防护,但除非涉及受监管 claim 或上市公司披露规则,否则不需要做成很重的 governed 包。\n\n### 包结构\n```\nwebinar-repurposer/\n SKILL.md\n agents/interface.yaml\n references/\n brand-voice.md\n positioning-notes.md\n banned-claims.md\n evals/\n output/\n cases.jsonl\n reports/\n output-risk-profile.md\n prompt-quality-profile.md\n```\n\n### SKILL.md\n```markdown\n---\nname: webinar-repurposer\ndescription: 将重复出现的 webinar 逐字稿复用为有来源依据的 LinkedIn 帖子、邮件 teaser、newsletter 段落、金句和 claim 依据说明。当提供逐字稿、讲者、定位说明或禁止 claim 时使用。不要用于无依据的发布 claim、法律审批、全新 campaign strategy 或一次性文案润色。\n---\n\n# Webinar 内容复用\n\n## 工作流\n1. 确认逐字稿是事实来源。\n2. 提取有来源支持的主题、讲者背书的引语和可安全复用的 claim。\n3. 起草前先检查 `references/banned-claims.md`。\n4. 生成各渠道输出,但不要添加逐字稿中没有的性能数字、客户结果或产品承诺。\n5. 添加来源依据说明,把每个主要 claim 绑定到逐字稿证据。\n\n## 必填输出\n- linkedin_post\n- email_teaser\n- newsletter_section\n- pull_quotes\n- source_grounding_notes\n- claims_avoided\n- missing_evidence\n```\n\n### 输出风险画像\n常见失败:\n- 生成任何产品都能用的泛泛市场话术。\n- 编造指标或客户结果。\n- 过度改写金句,导致意思偏离。\n- 因为某个 claim 很有吸引力而忽略 banned claims。\n\n### 输出评测用例\n1. 逐字稿包含诱人的“guaranteed ROI”禁止 claim:输出必须避开。\n2. 逐字稿没有量化证明:输出不能编造数字。\n3. 讲者原话不够顺:可以轻微修语法,但必须保留原意。\n4. 近邻请求:“从零写一个新 campaign idea”不应路由到这里。\n\n### 审查门禁\n- 必填 section 必须全部出现。\n- Banned claim 检查必须显式出现。\n- 来源依据说明必须引用逐字稿位置或原话片段。\n- 缺失证据必须被标出,而不是用通用卖点填补。\n"
|
||||
},
|
||||
"html_report": "case-03-webinar-repurposing.html"
|
||||
},
|
||||
{
|
||||
"id": "case-04-incident-postmortem",
|
||||
"title": "故障复盘 Skill",
|
||||
"scenario": "一个基础设施团队经常把 Slack 故障时间线、告警数据和部署记录整理成故障复盘和后续行动项。",
|
||||
"user_prompt": "请创建一个可复用的 governed skill,用于故障复盘。输入包括告警时间线、Slack 摘要、部署记录、客户影响说明和负责人列表。输出应包含时间线、影响、根因假设、行动项、未解决证据和后续负责人矩阵。",
|
||||
"rubric": [
|
||||
"是否处理 governed/运营风险和未解决证据。",
|
||||
"是否区分假设和已确认根因。",
|
||||
"是否定义行动项负责人矩阵和回滚/跟进边界。",
|
||||
"是否要求 file-backed 或 source-backed 证据。",
|
||||
"是否有针对 blame language 和编造因果的审查门禁。"
|
||||
],
|
||||
"variants": {
|
||||
"A": "## Skill 包建议:incident-postmortem\n\n### 边界\n负责根据 source-backed 时间线、Slack 摘要、部署记录、客户影响说明和负责人列表起草 governed 故障复盘。不要用于实时 incident command、最终 RCA 签核、HR/归责分析或面向客户的法律声明。\n\n### 类型\nGoverned。这个包会影响运营责任归属,如果证据不足,容易制造虚假因果。\n\n### 包结构\n```\nincident-postmortem/\n SKILL.md\n agents/interface.yaml\n references/\n postmortem-contract.md\n severity-policy.md\n blame-free-language.md\n action-owner-matrix.md\n evals/\n output/\n cases.jsonl\n fixtures/\n alert_timeline.json\n slack_summary.md\n deploy_notes.md\n reports/\n output-risk-profile.md\n output_quality_scorecard.md\n trust_report.md\n review-studio.html\n```\n\n### SKILL.md\n```markdown\n---\nname: incident-postmortem\ndescription: 根据告警时间线、Slack 摘要、部署记录、影响说明和负责人列表起草 governed 故障复盘。用于 source-backed 时间线重建、影响总结、根因假设、行动项、未解决证据和后续负责人矩阵。不要用于实时故障指挥、最终 RCA 审批、归责或法律/客户承诺。\n---\n\n# 故障复盘\n\n## 工作流\n1. 要求提供 source-backed 故障输入,并把缺失输入列为 `missing evidence`。\n2. 只根据已提供时间戳建立时间线;如需推断顺序,必须明确标注。\n3. 分开列出 `confirmed_facts`、`root_cause_hypotheses` 和 `unresolved_evidence`。\n4. 总结客户影响,但不要编造受影响账户、持续时间或 SLA 违约。\n5. 创建行动项:包含 owner、due date、验证信号和回滚/跟进边界。\n6. 使用 `references/blame-free-language.md` 的无责语言。\n7. 除非 reviewer 明确提供,否则最终 RCA 审批不属于本 skill。\n\n## 输出契约\n- incident_summary\n- source_inputs\n- timeline\n- customer_impact\n- confirmed_facts\n- root_cause_hypotheses\n- unresolved_evidence\n- action_items\n- owner_matrix\n- approval_status\n```\n\n### 输出评测用例\n1. Slack 和部署记录冲突:必须保留为未解决证据。\n2. 告警时间线缺恢复时间:不能编造持续时长。\n3. 用户要求实时故障决策:应路由出去,或说明本 skill 只做复盘。\n4. 来源材料带有归责语言:输出必须改写为系统/流程语言。\n5. 缺负责人列表:行动项 owner 字段应为 `missing evidence`。\n\n### 门禁\n- 时间线和部署记录需要 file-backed fixture 覆盖。\n- 输出评测禁止编造因果和隐藏未解决证据。\n- Review Studio 在人工 reviewer 审批行动负责人矩阵前保持 warning。\n- Trust report 应显示无网络和无破坏性操作。\n",
|
||||
"B": "## 建议 Skill:incident-postmortem\n\n### 目的\n帮助 Codex 根据时间线、Slack 摘要、部署记录、影响说明和负责人列表创建结构化故障复盘。\n\n### 包结构\n```\nincident-postmortem/\n SKILL.md\n agents/openai.yaml\n references/\n postmortem-template.md\n severity-policy.md\n```\n\n### SKILL.md 草稿\n```markdown\n---\nname: incident-postmortem\ndescription: 根据告警时间线、Slack 摘要、部署记录、客户影响说明和负责人列表创建故障复盘。当用户需要时间线、影响、根因假设、行动项、未解决证据或负责人矩阵时使用。\n---\n\n# 故障复盘\n\n## 工作流\n1. 收集告警时间线、Slack 摘要、部署记录、客户影响说明和负责人列表。\n2. 建立按时间排序的时间线。\n3. 总结客户和系统影响。\n4. 识别已确认事实和根因假设。\n5. 在提供负责人和截止时间时,起草行动项。\n6. 清楚标记未解决证据。\n7. 避免归责式语言。\n\n## 输出\n- 故障摘要\n- 时间线\n- 影响\n- 根因假设\n- 已确认事实\n- 未解决证据\n- 行动项\n- 负责人矩阵\n```\n\n### agents/openai.yaml\n```yaml\ndisplay_name: 故障复盘\nshort_description: 根据故障证据生成结构化复盘。\ndefault_prompt: 请把这些故障证据整理成复盘和负责人矩阵。\n```\n\n### 验证\n用证据完整、缺部署记录、Slack 说法冲突和暂时没有根因的 case 测试。确认 skill 会区分事实和假设。\n"
|
||||
},
|
||||
"html_report": "case-04-incident-postmortem.html"
|
||||
},
|
||||
{
|
||||
"id": "case-05-pr-review-followup",
|
||||
"title": "PR Review 跟进 Skill",
|
||||
"scenario": "一个小工程团队经常收到 GitHub PR review comments,希望 Codex 能把评论转成补丁、回复摘要和验证记录。",
|
||||
"user_prompt": "请设计一个用于处理 PR review comments 的可复用 skill。输入包括 review comments、变更文件、失败 CI 说明和 maintainer preferences。输出需要分组评论、只修改相关文件、写回复说明并运行验证。必须避免回滚无关的用户改动。",
|
||||
"rubric": [
|
||||
"是否理解 code-review 跟进和 dirty worktree 安全。",
|
||||
"是否定义评论分组、补丁、回复和验证工作流。",
|
||||
"是否避免过度重构和无关 revert。",
|
||||
"是否说明变更后需要的命令和证据。",
|
||||
"是否定义一般 code review 与评论跟进的触发排除。"
|
||||
],
|
||||
"variants": {
|
||||
"A": "## 建议 Skill:pr-review-followup\n\n### 目的\n创建一个 skill,帮助 Codex 安全处理 PR review comments,并总结回复。\n\n### 包结构\n```\npr-review-followup/\n SKILL.md\n agents/openai.yaml\n references/\n response-style.md\n```\n\n### SKILL.md 草稿\n```markdown\n---\nname: pr-review-followup\ndescription: 通过分组反馈、修改相关文件、编写回复说明和运行验证来处理 GitHub PR review comments。当用户提供 review comments、变更文件、CI 说明或 maintainer preferences 时使用。\n---\n\n# PR Review 跟进\n\n## 工作流\n1. 阅读所有 review comments,并按文件、主题和严重程度分组。\n2. 编辑前检查受影响文件。\n3. 只修改处理 comments 所需的文件。\n4. 不要回滚无关用户改动。\n5. 运行相关测试或 CI 复现命令。\n6. 总结变更,并为 reviewer 起草回复说明。\n\n## 输出\n- 评论分组\n- 修改文件\n- 验证命令\n- Reviewer 回复说明\n- 剩余问题\n```\n\n### agents/openai.yaml\n```yaml\ndisplay_name: PR Review 跟进\nshort_description: 处理 PR comments 并准备 reviewer 回复。\ndefault_prompt: 请处理这些 PR review comments,并总结验证结果。\n```\n\n### 验证\n用需要代码修改、文档修改、无需修改只需解释、以及 reviewer 要求冲突的 comments 测试。\n",
|
||||
"B": "## Skill 包建议:pr-review-followup\n\n### 边界\n负责 PR 已经有明确 reviewer comments、变更文件或 CI 说明之后的评论跟进。排除首次 code review、大范围重构、issue triage,以及没有绑定评论的推测性清理。\n\n### 包结构\n```\npr-review-followup/\n SKILL.md\n agents/interface.yaml\n references/\n response-style.md\n dirty-worktree-safety.md\n verification-policy.md\n evals/\n trigger_cases.json\n output/\n cases.jsonl\n reports/\n output-risk-profile.md\n output_quality_scorecard.md\n```\n\n### SKILL.md\n```markdown\n---\nname: pr-review-followup\ndescription: 处理具体 PR review comments:分组反馈、只修改相关文件、保留无关用户改动、起草 reviewer 回复并运行验证。当提供 review comments、变更文件、失败 CI 说明或 maintainer preferences 时使用。不要用于首次 code review、大范围重构、issue triage 或无关清理。\n---\n\n# PR Review 跟进\n\n## 工作流\n1. 编辑前记录 git status,并识别用户已经改动的文件。\n2. 按文件、行为、严重程度,以及是否需要代码、测试、文档或仅解释来分组 review comments。\n3. 修改前阅读受影响代码和附近测试。\n4. 只修改与评论绑定的文件。不要回滚无关改动,也不要格式化未触碰文件。\n5. 运行有针对性的验证,并记录命令和结果。\n6. 起草 reviewer 回复说明,把每组评论映射到变更、无需修改的理由或剩余问题。\n7. 如果评论冲突,停止并询问哪个 reviewer 指令优先。\n\n## 输出契约\n- comment_groups\n- patch_summary\n- files_changed\n- verification\n- reviewer_response_notes\n- unresolved_questions\n- unrelated_changes_preserved\n```\n\n### 输出评测用例\n1. 评论要求添加特定 null check:输出必须只修改受影响函数,并提到测试。\n2. Reviewer 要求与 PR 范围无关的大重构:输出应标出范围风险。\n3. Dirty worktree 中有无关用户文件:输出必须保留它。\n4. 两个 reviewer comments 冲突:输出必须询问优先级,而不是猜。\n5. 近邻请求:“从零 review 这个 PR”不应触发 follow-up mode。\n\n### 门禁\n- 触发评测必须区分首次 review 和评论跟进。\n- 如果回滚或隐藏无关改动,输出评测必须失败。\n- 验证策略必须记录跳过测试的原因。\n- 回复说明必须能追溯到评论分组。\n"
|
||||
},
|
||||
"html_report": "case-05-pr-review-followup.html"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,380 @@
|
||||
<!doctype html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>客服工单分诊 Skill - Skill 盲测评审</title>
|
||||
<style>
|
||||
:root {
|
||||
color-scheme: light;
|
||||
--bg: #f7f8fb;
|
||||
--panel: #ffffff;
|
||||
--ink: #20242c;
|
||||
--muted: #687082;
|
||||
--line: #d9deea;
|
||||
--accent: #2563eb;
|
||||
--accent-2: #0f766e;
|
||||
--warn: #b45309;
|
||||
}
|
||||
* { box-sizing: border-box; }
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
|
||||
background: var(--bg);
|
||||
color: var(--ink);
|
||||
line-height: 1.55;
|
||||
}
|
||||
header {
|
||||
padding: 28px clamp(18px, 4vw, 52px) 18px;
|
||||
background: #ffffff;
|
||||
border-bottom: 1px solid var(--line);
|
||||
}
|
||||
main { padding: 24px clamp(18px, 4vw, 52px) 52px; }
|
||||
h1 { margin: 0 0 8px; font-size: clamp(26px, 3vw, 38px); letter-spacing: 0; }
|
||||
h2 { margin: 0 0 12px; font-size: 20px; }
|
||||
h3 { margin: 18px 0 8px; font-size: 16px; }
|
||||
p { margin: 0 0 10px; }
|
||||
a { color: var(--accent); text-decoration: none; }
|
||||
a:hover { text-decoration: underline; }
|
||||
.meta, .note { color: var(--muted); }
|
||||
.grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 18px; align-items: start; }
|
||||
.card, .panel {
|
||||
background: var(--panel);
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 8px;
|
||||
padding: 18px;
|
||||
}
|
||||
.case-list { display: grid; gap: 12px; margin-top: 18px; }
|
||||
.case-row {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr auto;
|
||||
gap: 12px;
|
||||
align-items: center;
|
||||
background: var(--panel);
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 8px;
|
||||
padding: 14px 16px;
|
||||
}
|
||||
.badge {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
min-height: 28px;
|
||||
padding: 4px 10px;
|
||||
border-radius: 999px;
|
||||
background: #e8f0ff;
|
||||
color: #1d4ed8;
|
||||
font-size: 13px;
|
||||
font-weight: 650;
|
||||
}
|
||||
.rubric { margin: 0; padding-left: 20px; }
|
||||
.rubric li { margin-bottom: 6px; }
|
||||
.variant {
|
||||
background: var(--panel);
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
}
|
||||
.variant-head {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
gap: 12px;
|
||||
align-items: center;
|
||||
padding: 12px 16px;
|
||||
border-bottom: 1px solid var(--line);
|
||||
background: #f2f5fa;
|
||||
}
|
||||
.variant-body { padding: 16px; }
|
||||
pre {
|
||||
overflow: auto;
|
||||
padding: 12px;
|
||||
border-radius: 6px;
|
||||
background: #111827;
|
||||
color: #f9fafb;
|
||||
font-size: 13px;
|
||||
}
|
||||
code { font-family: "SFMono-Regular", Consolas, monospace; }
|
||||
.review-box {
|
||||
margin-top: 18px;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 8px;
|
||||
padding: 16px;
|
||||
background: #fff;
|
||||
}
|
||||
.controls { display: flex; flex-wrap: wrap; gap: 10px; margin: 12px 0; }
|
||||
button, .button {
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 6px;
|
||||
background: #fff;
|
||||
color: var(--ink);
|
||||
min-height: 36px;
|
||||
padding: 7px 12px;
|
||||
cursor: pointer;
|
||||
font-weight: 650;
|
||||
}
|
||||
button.primary, .button.primary { background: var(--accent); border-color: var(--accent); color: #fff; }
|
||||
textarea {
|
||||
width: 100%;
|
||||
min-height: 96px;
|
||||
resize: vertical;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 6px;
|
||||
padding: 10px;
|
||||
font: inherit;
|
||||
}
|
||||
.warn { color: var(--warn); font-weight: 650; }
|
||||
.split { display: flex; flex-wrap: wrap; gap: 10px; }
|
||||
.small { font-size: 13px; }
|
||||
@media (max-width: 900px) {
|
||||
.grid { grid-template-columns: 1fr; }
|
||||
.case-row { grid-template-columns: 1fr; }
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body data-case-id="case-01-support-triage">
|
||||
<header>
|
||||
<div class="split"><a class="button" href="index.html">返回入口</a><a class="button" href="case-02-monthly-revenue-reconciliation.html">下一个</a></div>
|
||||
<h1>客服工单分诊 Skill</h1>
|
||||
<p class="meta">A/B 盲测评审。记录完判断前,不要打开答案钥匙。</p>
|
||||
</header>
|
||||
<main>
|
||||
<section class="panel">
|
||||
<h2>场景</h2>
|
||||
<p>一个 B2B SaaS 团队每天都要处理客户工单:判断分类、紧急程度、起草首轮回复,并把账务、安全、故障类问题升级给对应负责人。他们希望把这个重复流程做成一个给支持团队使用的 Codex skill。</p>
|
||||
<h3>用户请求</h3>
|
||||
<p>请把我们反复使用的客服工单分诊流程做成一个团队可复用的 skill。输入包括原始工单文本、客户等级、产品模块和近期故障记录。输出需要包含问题分类、紧急程度、首轮回复草稿、升级负责人和判断依据。不要把 PII 泄露到报告里。</p>
|
||||
<h3>评审标准</h3>
|
||||
<ol class="rubric"><li>是否有清楚的触发边界和近邻排除。</li>
|
||||
<li>是否是可复用的 skill 包结构,而不只是一个提示词。</li>
|
||||
<li>是否定义了分类、紧急程度、回复、升级和证据的输出契约。</li>
|
||||
<li>是否处理 PII 和客户内容的隐私风险。</li>
|
||||
<li>是否有能发现错误升级和泛泛回复的评测方案。</li></ol>
|
||||
</section>
|
||||
|
||||
<div class="grid" style="margin-top:18px">
|
||||
|
||||
<section class="variant">
|
||||
<div class="variant-head">
|
||||
<h2>方案 A</h2>
|
||||
<span class="badge">来源已隐藏</span>
|
||||
</div>
|
||||
<div class="variant-body">
|
||||
<h2>建议 Skill:support-triage</h2>
|
||||
|
||||
<h3>目的</h3>
|
||||
<p>创建一个简洁的 skill,帮助 Codex 对 B2B SaaS 客服工单进行分诊,并起草首轮回复。</p>
|
||||
|
||||
<h3>建议包结构</h3>
|
||||
<pre><code>support-triage/
|
||||
SKILL.md
|
||||
agents/openai.yaml
|
||||
references/
|
||||
triage-taxonomy.md
|
||||
escalation-policy.md</code></pre>
|
||||
|
||||
<h3>SKILL.md 草稿</h3>
|
||||
<pre><code>---
|
||||
name: support-triage
|
||||
description: 对 B2B SaaS 客服工单进行分诊并起草首轮回复。当用户提供原始工单文本、客户等级、产品模块、故障记录,或需要紧急程度、分类、升级建议时使用。
|
||||
---
|
||||
|
||||
# 客服工单分诊
|
||||
|
||||
使用这个 skill 对入站工单分类、起草合适的首轮回复,并识别是否需要升级。
|
||||
|
||||
## 工作流
|
||||
1. 阅读工单文本、客户等级、产品模块和近期故障记录。
|
||||
2. 将工单归为一个主分类:账务、访问权限、缺陷、故障、功能请求、安全、数据/隐私、上手问题或其他。
|
||||
3. 标记紧急程度:低、普通、高、严重。
|
||||
4. 起草首轮回复:确认问题、只询问必要补充信息,并避免没有依据的承诺。
|
||||
5. 对安全、隐私、严重故障、数据丢失或企业客户影响问题进行升级。
|
||||
6. 汇报判断依据,但不要复制不必要的 PII。
|
||||
|
||||
## 输出格式
|
||||
- 分类:
|
||||
- 紧急程度:
|
||||
- 首轮回复:
|
||||
- 升级负责人:
|
||||
- 判断依据:
|
||||
- 缺失信息:
|
||||
|
||||
## 参考资料
|
||||
- 分类规则见 `references/triage-taxonomy.md`。
|
||||
- 升级标准见 `references/escalation-policy.md`。</code></pre>
|
||||
|
||||
<h3>agents/openai.yaml</h3>
|
||||
<pre><code>display_name: 客服工单分诊
|
||||
short_description: 对客服工单分类,并起草首轮回复。
|
||||
default_prompt: 请分诊这个客服工单,并起草首轮回复。</code></pre>
|
||||
|
||||
<h3>资源</h3>
|
||||
<ul>
|
||||
<li>`references/triage-taxonomy.md`:分类定义、紧急程度提示和示例。</li>
|
||||
<li>`references/escalation-policy.md`:升级负责人和升级标准。</li>
|
||||
</ul>
|
||||
|
||||
<h3>验证</h3>
|
||||
<p>用账务、安全、故障和功能请求等代表性工单测试。确认输出会最小化 PII,并且严重问题会被升级。</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
<section class="variant">
|
||||
<div class="variant-head">
|
||||
<h2>方案 B</h2>
|
||||
<span class="badge">来源已隐藏</span>
|
||||
</div>
|
||||
<div class="variant-body">
|
||||
<h2>Skill 包建议:support-triage</h2>
|
||||
|
||||
<h3>边界</h3>
|
||||
<p>负责重复出现的客服工单分诊:用户提供工单文本以及客户/产品上下文,需要结构化路由决策。不要用于一次性文案润色、泛泛的客服同理心训练、CRM 配置,或超出升级范围的法律/安全事件处置。</p>
|
||||
|
||||
<h3>输出契约</h3>
|
||||
<p>这个 skill 必须返回:</p>
|
||||
<ul>
|
||||
<li>`category`</li>
|
||||
<li>`urgency`</li>
|
||||
<li>`first_response_draft`</li>
|
||||
<li>`escalation_owner`</li>
|
||||
<li>`evidence_used`</li>
|
||||
<li>`missing_information`</li>
|
||||
<li>`pii_handling_note`</li>
|
||||
</ul>
|
||||
|
||||
<h3>包结构</h3>
|
||||
<pre><code>support-triage/
|
||||
SKILL.md
|
||||
agents/interface.yaml
|
||||
references/
|
||||
triage-taxonomy.md
|
||||
escalation-policy.md
|
||||
privacy-redaction.md
|
||||
evals/
|
||||
trigger_cases.json
|
||||
output/
|
||||
cases.jsonl
|
||||
fixtures/
|
||||
reports/
|
||||
output-risk-profile.md
|
||||
output_quality_scorecard.md</code></pre>
|
||||
|
||||
<h3>SKILL.md</h3>
|
||||
<pre><code>---
|
||||
name: support-triage
|
||||
description: 将重复出现的 B2B SaaS 客服工单分诊为分类、紧急程度、首轮回复、升级负责人、判断依据和缺失信息。当输入包含原始工单、客户等级、产品模块、故障记录或支持队列上下文时使用。不要用于一次性文案润色、CRM 设置、法律建议或最终安全事件处置。
|
||||
---
|
||||
|
||||
# 客服工单分诊
|
||||
|
||||
## 工作流
|
||||
1. 确认这是重复的工单分诊任务,而不是一次性文案润色。
|
||||
2. 阅读工单文本、客户等级、产品模块和故障记录。
|
||||
3. 使用 `references/triage-taxonomy.md` 判断分类和紧急程度。
|
||||
4. 按 `references/escalation-policy.md` 检查升级标准。
|
||||
5. 起草首轮回复:确认问题、避免无依据承诺,只请求最少的缺失信息。
|
||||
6. 按 `references/privacy-redaction.md` 对 PII 做脱敏或摘要。
|
||||
7. 严格按输出契约返回。
|
||||
|
||||
## 必填输出
|
||||
使用这些字段:
|
||||
- category
|
||||
- urgency
|
||||
- first_response_draft
|
||||
- escalation_owner
|
||||
- evidence_used
|
||||
- missing_information
|
||||
- pii_handling_note</code></pre>
|
||||
|
||||
<h3>agents/interface.yaml</h3>
|
||||
<pre><code>display_name: 客服工单分诊
|
||||
short_description: 对工单分类、起草首轮回复,并给出升级依据。
|
||||
default_prompt: 请用分类、紧急程度、回复、升级负责人和依据来分诊这个客服工单。</code></pre>
|
||||
|
||||
<h3>评测用例</h3>
|
||||
<p>1. 企业客户在已知故障期间提交工单:必须标为 `critical`,并升级给 incident commander。</p>
|
||||
<p>2. SMB 客户的账务困惑:不应过度升级。</p>
|
||||
<p>3. 带客户邮箱和 token 片段的安全披露:必须脱敏 token,并升级安全团队。</p>
|
||||
<p>4. 伪装成投诉的功能请求:应归类为功能请求,紧急程度为普通。</p>
|
||||
<p>5. 近邻请求:“把这段回复改得更温和”不应触发包级分诊。</p>
|
||||
|
||||
<h3>发布门禁</h3>
|
||||
<ul>
|
||||
<li>触发评测:正例、反例、近邻文案润色。</li>
|
||||
<li>输出评测:首轮回复不能编造 SLA,升级必须匹配策略。</li>
|
||||
<li>隐私检查:报告不能保存原始工单 PII。</li>
|
||||
<li>审查备注:如果分类规则或升级负责人未提供,标记为 `missing evidence`,不要编造。</li>
|
||||
</ul>
|
||||
|
||||
<h3>下一步</h3>
|
||||
<p>加入 3 个匿名工单 fixture,运行输出评测,并记录错误升级、泛泛回复和 PII 泄露的失败分类。</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
</div>
|
||||
|
||||
<section class="review-box">
|
||||
<h2>你的判断</h2>
|
||||
<p class="note">只根据评审标准和页面里可见的两个输出做判断。选择会保存到当前浏览器的本地存储里,也可以回到入口页导出。</p>
|
||||
<div class="controls" role="radiogroup" aria-label="胜出方案">
|
||||
<label><input type="radio" name="winner" value="A"> 方案 A 更好</label>
|
||||
<label><input type="radio" name="winner" value="B"> 方案 B 更好</label>
|
||||
<label><input type="radio" name="winner" value="tie"> 平局 / 没有明显胜出</label>
|
||||
</div>
|
||||
<label for="confidence">信心程度</label>
|
||||
<div class="controls">
|
||||
<select id="confidence">
|
||||
<option value="">请选择</option>
|
||||
<option value="0.4">0.4,较弱</option>
|
||||
<option value="0.6">0.6,中等</option>
|
||||
<option value="0.8">0.8,较强</option>
|
||||
<option value="1.0">1.0,非常确定</option>
|
||||
</select>
|
||||
</div>
|
||||
<label for="reason">理由</label>
|
||||
<textarea id="reason" placeholder="为什么这个方案更好?请写出具体的评审标准差异。"></textarea>
|
||||
<div class="controls">
|
||||
<button class="primary" type="button" onclick="saveDecision()">保存判断</button>
|
||||
<button type="button" onclick="clearDecision()">清空</button>
|
||||
</div>
|
||||
<p id="save-status" class="small note"></p>
|
||||
</section>
|
||||
</main>
|
||||
<script>
|
||||
const caseId = document.body.dataset.caseId;
|
||||
const key = "blindSkillReview:" + caseId;
|
||||
function currentDecision() {
|
||||
const selected = document.querySelector('input[name="winner"]:checked');
|
||||
return {
|
||||
case_id: caseId,
|
||||
winner_variant: selected ? selected.value : "",
|
||||
confidence: document.getElementById("confidence").value,
|
||||
reason: document.getElementById("reason").value.trim(),
|
||||
reviewed_at: new Date().toISOString()
|
||||
};
|
||||
}
|
||||
function saveDecision() {
|
||||
const decision = currentDecision();
|
||||
localStorage.setItem(key, JSON.stringify(decision));
|
||||
document.getElementById("save-status").textContent = "已保存:" + decision.reviewed_at;
|
||||
}
|
||||
function clearDecision() {
|
||||
localStorage.removeItem(key);
|
||||
document.querySelectorAll('input[name="winner"]').forEach(el => el.checked = false);
|
||||
document.getElementById("confidence").value = "";
|
||||
document.getElementById("reason").value = "";
|
||||
document.getElementById("save-status").textContent = "已清空。";
|
||||
}
|
||||
function loadDecision() {
|
||||
const raw = localStorage.getItem(key);
|
||||
if (!raw) return;
|
||||
const decision = JSON.parse(raw);
|
||||
const selected = document.querySelector('input[name="winner"][value="' + decision.winner_variant + '"]');
|
||||
if (selected) selected.checked = true;
|
||||
document.getElementById("confidence").value = decision.confidence || "";
|
||||
document.getElementById("reason").value = decision.reason || "";
|
||||
document.getElementById("save-status").textContent = "已加载保存过的判断。";
|
||||
}
|
||||
loadDecision();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,368 @@
|
||||
<!doctype html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>月度收入对账 Skill - Skill 盲测评审</title>
|
||||
<style>
|
||||
:root {
|
||||
color-scheme: light;
|
||||
--bg: #f7f8fb;
|
||||
--panel: #ffffff;
|
||||
--ink: #20242c;
|
||||
--muted: #687082;
|
||||
--line: #d9deea;
|
||||
--accent: #2563eb;
|
||||
--accent-2: #0f766e;
|
||||
--warn: #b45309;
|
||||
}
|
||||
* { box-sizing: border-box; }
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
|
||||
background: var(--bg);
|
||||
color: var(--ink);
|
||||
line-height: 1.55;
|
||||
}
|
||||
header {
|
||||
padding: 28px clamp(18px, 4vw, 52px) 18px;
|
||||
background: #ffffff;
|
||||
border-bottom: 1px solid var(--line);
|
||||
}
|
||||
main { padding: 24px clamp(18px, 4vw, 52px) 52px; }
|
||||
h1 { margin: 0 0 8px; font-size: clamp(26px, 3vw, 38px); letter-spacing: 0; }
|
||||
h2 { margin: 0 0 12px; font-size: 20px; }
|
||||
h3 { margin: 18px 0 8px; font-size: 16px; }
|
||||
p { margin: 0 0 10px; }
|
||||
a { color: var(--accent); text-decoration: none; }
|
||||
a:hover { text-decoration: underline; }
|
||||
.meta, .note { color: var(--muted); }
|
||||
.grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 18px; align-items: start; }
|
||||
.card, .panel {
|
||||
background: var(--panel);
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 8px;
|
||||
padding: 18px;
|
||||
}
|
||||
.case-list { display: grid; gap: 12px; margin-top: 18px; }
|
||||
.case-row {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr auto;
|
||||
gap: 12px;
|
||||
align-items: center;
|
||||
background: var(--panel);
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 8px;
|
||||
padding: 14px 16px;
|
||||
}
|
||||
.badge {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
min-height: 28px;
|
||||
padding: 4px 10px;
|
||||
border-radius: 999px;
|
||||
background: #e8f0ff;
|
||||
color: #1d4ed8;
|
||||
font-size: 13px;
|
||||
font-weight: 650;
|
||||
}
|
||||
.rubric { margin: 0; padding-left: 20px; }
|
||||
.rubric li { margin-bottom: 6px; }
|
||||
.variant {
|
||||
background: var(--panel);
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
}
|
||||
.variant-head {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
gap: 12px;
|
||||
align-items: center;
|
||||
padding: 12px 16px;
|
||||
border-bottom: 1px solid var(--line);
|
||||
background: #f2f5fa;
|
||||
}
|
||||
.variant-body { padding: 16px; }
|
||||
pre {
|
||||
overflow: auto;
|
||||
padding: 12px;
|
||||
border-radius: 6px;
|
||||
background: #111827;
|
||||
color: #f9fafb;
|
||||
font-size: 13px;
|
||||
}
|
||||
code { font-family: "SFMono-Regular", Consolas, monospace; }
|
||||
.review-box {
|
||||
margin-top: 18px;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 8px;
|
||||
padding: 16px;
|
||||
background: #fff;
|
||||
}
|
||||
.controls { display: flex; flex-wrap: wrap; gap: 10px; margin: 12px 0; }
|
||||
button, .button {
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 6px;
|
||||
background: #fff;
|
||||
color: var(--ink);
|
||||
min-height: 36px;
|
||||
padding: 7px 12px;
|
||||
cursor: pointer;
|
||||
font-weight: 650;
|
||||
}
|
||||
button.primary, .button.primary { background: var(--accent); border-color: var(--accent); color: #fff; }
|
||||
textarea {
|
||||
width: 100%;
|
||||
min-height: 96px;
|
||||
resize: vertical;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 6px;
|
||||
padding: 10px;
|
||||
font: inherit;
|
||||
}
|
||||
.warn { color: var(--warn); font-weight: 650; }
|
||||
.split { display: flex; flex-wrap: wrap; gap: 10px; }
|
||||
.small { font-size: 13px; }
|
||||
@media (max-width: 900px) {
|
||||
.grid { grid-template-columns: 1fr; }
|
||||
.case-row { grid-template-columns: 1fr; }
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body data-case-id="case-02-monthly-revenue-reconciliation">
|
||||
<header>
|
||||
<div class="split"><a class="button" href="index.html">返回入口</a><a class="button" href="case-01-support-triage.html">上一个</a><a class="button" href="case-03-webinar-repurposing.html">下一个</a></div>
|
||||
<h1>月度收入对账 Skill</h1>
|
||||
<p class="meta">A/B 盲测评审。记录完判断前,不要打开答案钥匙。</p>
|
||||
</header>
|
||||
<main>
|
||||
<section class="panel">
|
||||
<h2>场景</h2>
|
||||
<p>一个财务运营团队每个月结账前都要比对 Stripe 导出、数据仓库发票 CSV 和人工调整表,找出金额、币种、发票和调整项的不一致。</p>
|
||||
<h3>用户请求</h3>
|
||||
<p>请创建一个用于月度收入对账的可复用 skill。输入是 Stripe balance export CSV、warehouse invoice CSV 和 adjustments sheet。输出需要标出不一致项、解释可能原因,并生成可用于月结的摘要。准确性比速度更重要。</p>
|
||||
<h3>评审标准</h3>
|
||||
<ol class="rubric"><li>是否识别出这是 file-backed 且准确性敏感的任务。</li>
|
||||
<li>是否定义了确定性脚本和资源边界。</li>
|
||||
<li>是否说明输入/输出 schema 与对账容差。</li>
|
||||
<li>是否包含 fixture 和失败用例验证。</li>
|
||||
<li>是否避免编造财务事实或隐藏未解决差异。</li></ol>
|
||||
</section>
|
||||
|
||||
<div class="grid" style="margin-top:18px">
|
||||
|
||||
<section class="variant">
|
||||
<div class="variant-head">
|
||||
<h2>方案 A</h2>
|
||||
<span class="badge">来源已隐藏</span>
|
||||
</div>
|
||||
<div class="variant-body">
|
||||
<h2>Skill 包建议:revenue-reconciliation</h2>
|
||||
|
||||
<h3>边界</h3>
|
||||
<p>负责围绕 Stripe balance export、warehouse invoice CSV 和调整表的重复月结对账。排除税务建议、收入确认政策决策、支付渠道配置和一次性表格美化。</p>
|
||||
|
||||
<h3>风险等级</h3>
|
||||
<p>Governed,file-backed,准确性敏感。任何可用于月结的结论前,都必须有确定性解析和可见的未解决项目。</p>
|
||||
|
||||
<h3>包结构</h3>
|
||||
<pre><code>revenue-reconciliation/
|
||||
SKILL.md
|
||||
agents/interface.yaml
|
||||
scripts/
|
||||
reconcile_revenue.py
|
||||
validate_reconciliation_fixture.py
|
||||
references/
|
||||
input-schema.md
|
||||
tolerance-policy.md
|
||||
close-summary-contract.md
|
||||
evals/
|
||||
output/
|
||||
cases.jsonl
|
||||
fixtures/
|
||||
stripe_sample.csv
|
||||
warehouse_sample.csv
|
||||
adjustments_sample.csv
|
||||
reports/
|
||||
output-risk-profile.md
|
||||
output_quality_scorecard.md
|
||||
trust_report.md</code></pre>
|
||||
|
||||
<h3>SKILL.md</h3>
|
||||
<pre><code>---
|
||||
name: revenue-reconciliation
|
||||
description: 对来自 Stripe 导出、warehouse invoice CSV 和调整表的重复月结收入文件进行对账。用于 file-backed 差异检测、可能原因分析、未解决项目报告和月结摘要。不要用于收入确认建议、税务指导、支付渠道配置或一次性表格格式整理。
|
||||
---
|
||||
|
||||
# 收入对账
|
||||
|
||||
## 工作流
|
||||
1. 要求提供所有输入文件;缺失文件必须标记为 `missing evidence`。
|
||||
2. 阅读 `references/input-schema.md`,先校验列再分析。
|
||||
3. 运行 `scripts/reconcile_revenue.py`,规范化 ID、币种、金额精度、日期和调整项关联。
|
||||
4. 审查 JSON 输出,并按缺失发票、金额差异、币种差异、重复项、时间差异或仅调整项分类。
|
||||
5. 只基于脚本证据生成月结摘要。
|
||||
6. 保持未解决差异可见。不要编造原因、审批或政策判断。
|
||||
|
||||
## 输出契约
|
||||
- input_files
|
||||
- validation_status
|
||||
- totals_by_source
|
||||
- matched_count
|
||||
- mismatch_table
|
||||
- likely_causes
|
||||
- unresolved_items
|
||||
- close_ready_summary
|
||||
- missing_evidence</code></pre>
|
||||
|
||||
<h3>确定性脚本契约</h3>
|
||||
<p>`scripts/reconcile_revenue.py` 应接受:</p>
|
||||
<pre><code>python3 scripts/reconcile_revenue.py --stripe stripe.csv --warehouse warehouse.csv --adjustments adjustments.csv --output reconciliation.json</code></pre>
|
||||
|
||||
<p>它应返回包含源行 ID 的结构化 JSON,让摘要里的每个结论都能追溯到 file-backed fixture。</p>
|
||||
|
||||
<h3>评测</h3>
|
||||
<ul>
|
||||
<li>Fixture 1:所有记录匹配。</li>
|
||||
<li>Fixture 2:Stripe 有付款,但 warehouse 缺发票。</li>
|
||||
<li>Fixture 3:warehouse 金额超过容差。</li>
|
||||
<li>Fixture 4:人工调整解释了差异。</li>
|
||||
<li>近邻请求:“把这个表格弄好看一点”不应路由到这里。</li>
|
||||
</ul>
|
||||
|
||||
<h3>门禁</h3>
|
||||
<ul>
|
||||
<li>汇总前必须通过输入 schema 校验。</li>
|
||||
<li>如果遗漏未解决差异,输出评测必须失败。</li>
|
||||
<li>Trust check 应标记网络访问为不必要。</li>
|
||||
<li>Review Studio 应在晋级前显示 file-backed fixture 覆盖和未解决差异处理。</li>
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
<section class="variant">
|
||||
<div class="variant-head">
|
||||
<h2>方案 B</h2>
|
||||
<span class="badge">来源已隐藏</span>
|
||||
</div>
|
||||
<div class="variant-body">
|
||||
<h2>建议 Skill:revenue-reconciliation</h2>
|
||||
|
||||
<h3>目的</h3>
|
||||
<p>帮助 Codex 对 Stripe、数据仓库发票和人工调整表中的月度收入记录进行对账。</p>
|
||||
|
||||
<h3>建议包结构</h3>
|
||||
<pre><code>revenue-reconciliation/
|
||||
SKILL.md
|
||||
agents/openai.yaml
|
||||
scripts/
|
||||
reconcile_revenue.py
|
||||
references/
|
||||
csv-schema.md</code></pre>
|
||||
|
||||
<h3>SKILL.md 草稿</h3>
|
||||
<pre><code>---
|
||||
name: revenue-reconciliation
|
||||
description: 对 Stripe balance export、warehouse invoice CSV 和调整表中的月度收入数据进行对账。当用户要求比较收入文件、找出不一致项或准备月结摘要时使用。
|
||||
---
|
||||
|
||||
# 收入对账
|
||||
|
||||
## 工作流
|
||||
1. 确认用户提供了 Stripe 导出、warehouse invoice CSV 和调整表。
|
||||
2. 阅读 `references/csv-schema.md`,了解预期列。
|
||||
3. 使用用户提供的文件运行 `scripts/reconcile_revenue.py`。
|
||||
4. 审查不一致项,并总结可能原因。
|
||||
5. 不要编造缺失值。清楚标记未解决记录。
|
||||
|
||||
## 输出
|
||||
- 已检查文件
|
||||
- 匹配总额
|
||||
- 不一致项
|
||||
- 可能原因
|
||||
- 未解决项目
|
||||
- 月结摘要</code></pre>
|
||||
|
||||
<h3>脚本</h3>
|
||||
<p>`scripts/reconcile_revenue.py` 应解析 CSV 输入,规范化 invoice ID 和币种,比较金额,并输出 JSON 供 Codex 总结。</p>
|
||||
|
||||
<h3>agents/openai.yaml</h3>
|
||||
<pre><code>display_name: 收入对账
|
||||
short_description: 比对收入 CSV,并总结月结差异。
|
||||
default_prompt: 请对这些收入文件进行对账,并生成月结摘要。</code></pre>
|
||||
|
||||
<h3>验证</h3>
|
||||
<p>使用包含匹配发票、缺失发票、重复发票和仅调整项记录的样例 CSV。确认未解决差异不会被隐藏。</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
</div>
|
||||
|
||||
<section class="review-box">
|
||||
<h2>你的判断</h2>
|
||||
<p class="note">只根据评审标准和页面里可见的两个输出做判断。选择会保存到当前浏览器的本地存储里,也可以回到入口页导出。</p>
|
||||
<div class="controls" role="radiogroup" aria-label="胜出方案">
|
||||
<label><input type="radio" name="winner" value="A"> 方案 A 更好</label>
|
||||
<label><input type="radio" name="winner" value="B"> 方案 B 更好</label>
|
||||
<label><input type="radio" name="winner" value="tie"> 平局 / 没有明显胜出</label>
|
||||
</div>
|
||||
<label for="confidence">信心程度</label>
|
||||
<div class="controls">
|
||||
<select id="confidence">
|
||||
<option value="">请选择</option>
|
||||
<option value="0.4">0.4,较弱</option>
|
||||
<option value="0.6">0.6,中等</option>
|
||||
<option value="0.8">0.8,较强</option>
|
||||
<option value="1.0">1.0,非常确定</option>
|
||||
</select>
|
||||
</div>
|
||||
<label for="reason">理由</label>
|
||||
<textarea id="reason" placeholder="为什么这个方案更好?请写出具体的评审标准差异。"></textarea>
|
||||
<div class="controls">
|
||||
<button class="primary" type="button" onclick="saveDecision()">保存判断</button>
|
||||
<button type="button" onclick="clearDecision()">清空</button>
|
||||
</div>
|
||||
<p id="save-status" class="small note"></p>
|
||||
</section>
|
||||
</main>
|
||||
<script>
|
||||
const caseId = document.body.dataset.caseId;
|
||||
const key = "blindSkillReview:" + caseId;
|
||||
function currentDecision() {
|
||||
const selected = document.querySelector('input[name="winner"]:checked');
|
||||
return {
|
||||
case_id: caseId,
|
||||
winner_variant: selected ? selected.value : "",
|
||||
confidence: document.getElementById("confidence").value,
|
||||
reason: document.getElementById("reason").value.trim(),
|
||||
reviewed_at: new Date().toISOString()
|
||||
};
|
||||
}
|
||||
function saveDecision() {
|
||||
const decision = currentDecision();
|
||||
localStorage.setItem(key, JSON.stringify(decision));
|
||||
document.getElementById("save-status").textContent = "已保存:" + decision.reviewed_at;
|
||||
}
|
||||
function clearDecision() {
|
||||
localStorage.removeItem(key);
|
||||
document.querySelectorAll('input[name="winner"]').forEach(el => el.checked = false);
|
||||
document.getElementById("confidence").value = "";
|
||||
document.getElementById("reason").value = "";
|
||||
document.getElementById("save-status").textContent = "已清空。";
|
||||
}
|
||||
function loadDecision() {
|
||||
const raw = localStorage.getItem(key);
|
||||
if (!raw) return;
|
||||
const decision = JSON.parse(raw);
|
||||
const selected = document.querySelector('input[name="winner"][value="' + decision.winner_variant + '"]');
|
||||
if (selected) selected.checked = true;
|
||||
document.getElementById("confidence").value = decision.confidence || "";
|
||||
document.getElementById("reason").value = decision.reason || "";
|
||||
document.getElementById("save-status").textContent = "已加载保存过的判断。";
|
||||
}
|
||||
loadDecision();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,356 @@
|
||||
<!doctype html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Webinar 内容复用 Skill - Skill 盲测评审</title>
|
||||
<style>
|
||||
:root {
|
||||
color-scheme: light;
|
||||
--bg: #f7f8fb;
|
||||
--panel: #ffffff;
|
||||
--ink: #20242c;
|
||||
--muted: #687082;
|
||||
--line: #d9deea;
|
||||
--accent: #2563eb;
|
||||
--accent-2: #0f766e;
|
||||
--warn: #b45309;
|
||||
}
|
||||
* { box-sizing: border-box; }
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
|
||||
background: var(--bg);
|
||||
color: var(--ink);
|
||||
line-height: 1.55;
|
||||
}
|
||||
header {
|
||||
padding: 28px clamp(18px, 4vw, 52px) 18px;
|
||||
background: #ffffff;
|
||||
border-bottom: 1px solid var(--line);
|
||||
}
|
||||
main { padding: 24px clamp(18px, 4vw, 52px) 52px; }
|
||||
h1 { margin: 0 0 8px; font-size: clamp(26px, 3vw, 38px); letter-spacing: 0; }
|
||||
h2 { margin: 0 0 12px; font-size: 20px; }
|
||||
h3 { margin: 18px 0 8px; font-size: 16px; }
|
||||
p { margin: 0 0 10px; }
|
||||
a { color: var(--accent); text-decoration: none; }
|
||||
a:hover { text-decoration: underline; }
|
||||
.meta, .note { color: var(--muted); }
|
||||
.grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 18px; align-items: start; }
|
||||
.card, .panel {
|
||||
background: var(--panel);
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 8px;
|
||||
padding: 18px;
|
||||
}
|
||||
.case-list { display: grid; gap: 12px; margin-top: 18px; }
|
||||
.case-row {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr auto;
|
||||
gap: 12px;
|
||||
align-items: center;
|
||||
background: var(--panel);
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 8px;
|
||||
padding: 14px 16px;
|
||||
}
|
||||
.badge {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
min-height: 28px;
|
||||
padding: 4px 10px;
|
||||
border-radius: 999px;
|
||||
background: #e8f0ff;
|
||||
color: #1d4ed8;
|
||||
font-size: 13px;
|
||||
font-weight: 650;
|
||||
}
|
||||
.rubric { margin: 0; padding-left: 20px; }
|
||||
.rubric li { margin-bottom: 6px; }
|
||||
.variant {
|
||||
background: var(--panel);
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
}
|
||||
.variant-head {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
gap: 12px;
|
||||
align-items: center;
|
||||
padding: 12px 16px;
|
||||
border-bottom: 1px solid var(--line);
|
||||
background: #f2f5fa;
|
||||
}
|
||||
.variant-body { padding: 16px; }
|
||||
pre {
|
||||
overflow: auto;
|
||||
padding: 12px;
|
||||
border-radius: 6px;
|
||||
background: #111827;
|
||||
color: #f9fafb;
|
||||
font-size: 13px;
|
||||
}
|
||||
code { font-family: "SFMono-Regular", Consolas, monospace; }
|
||||
.review-box {
|
||||
margin-top: 18px;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 8px;
|
||||
padding: 16px;
|
||||
background: #fff;
|
||||
}
|
||||
.controls { display: flex; flex-wrap: wrap; gap: 10px; margin: 12px 0; }
|
||||
button, .button {
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 6px;
|
||||
background: #fff;
|
||||
color: var(--ink);
|
||||
min-height: 36px;
|
||||
padding: 7px 12px;
|
||||
cursor: pointer;
|
||||
font-weight: 650;
|
||||
}
|
||||
button.primary, .button.primary { background: var(--accent); border-color: var(--accent); color: #fff; }
|
||||
textarea {
|
||||
width: 100%;
|
||||
min-height: 96px;
|
||||
resize: vertical;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 6px;
|
||||
padding: 10px;
|
||||
font: inherit;
|
||||
}
|
||||
.warn { color: var(--warn); font-weight: 650; }
|
||||
.split { display: flex; flex-wrap: wrap; gap: 10px; }
|
||||
.small { font-size: 13px; }
|
||||
@media (max-width: 900px) {
|
||||
.grid { grid-template-columns: 1fr; }
|
||||
.case-row { grid-template-columns: 1fr; }
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body data-case-id="case-03-webinar-repurposing">
|
||||
<header>
|
||||
<div class="split"><a class="button" href="index.html">返回入口</a><a class="button" href="case-02-monthly-revenue-reconciliation.html">上一个</a><a class="button" href="case-04-incident-postmortem.html">下一个</a></div>
|
||||
<h1>Webinar 内容复用 Skill</h1>
|
||||
<p class="meta">A/B 盲测评审。记录完判断前,不要打开答案钥匙。</p>
|
||||
</header>
|
||||
<main>
|
||||
<section class="panel">
|
||||
<h2>场景</h2>
|
||||
<p>一个市场团队经常把 webinar 逐字稿改写成 LinkedIn 帖子、邮件 teaser 和 newsletter 段落,同时必须保证所有说法都有来源,并避开禁止宣传的 claim。</p>
|
||||
<h3>用户请求</h3>
|
||||
<p>请做一个可复用 skill,把 webinar 逐字稿复用成市场内容。输入包括逐字稿、讲者姓名、产品定位说明和禁止使用的 claim。输出包括 LinkedIn 帖子、邮件 teaser、newsletter 段落、可引用金句和来源依据说明。</p>
|
||||
<h3>评审标准</h3>
|
||||
<ol class="rubric"><li>是否保留来源约束,并处理 banned claims。</li>
|
||||
<li>是否定义可重复的多渠道输出格式。</li>
|
||||
<li>是否把语气和定位资料放到 references,避免入口膨胀。</li>
|
||||
<li>是否有针对幻觉 claim 和泛泛市场文案的评测。</li>
|
||||
<li>是否在中等治理风险下保持 skill 足够轻量。</li></ol>
|
||||
</section>
|
||||
|
||||
<div class="grid" style="margin-top:18px">
|
||||
|
||||
<section class="variant">
|
||||
<div class="variant-head">
|
||||
<h2>方案 A</h2>
|
||||
<span class="badge">来源已隐藏</span>
|
||||
</div>
|
||||
<div class="variant-body">
|
||||
<h2>建议 Skill:webinar-repurposer</h2>
|
||||
|
||||
<h3>目的</h3>
|
||||
<p>创建一个 skill,把 webinar 逐字稿转成可复用的市场内容。</p>
|
||||
|
||||
<h3>包结构</h3>
|
||||
<pre><code>webinar-repurposer/
|
||||
SKILL.md
|
||||
agents/openai.yaml
|
||||
references/
|
||||
brand-voice.md
|
||||
banned-claims.md</code></pre>
|
||||
|
||||
<h3>SKILL.md 草稿</h3>
|
||||
<pre><code>---
|
||||
name: webinar-repurposer
|
||||
description: 将 webinar 逐字稿复用成 LinkedIn 帖子、邮件 teaser、newsletter 段落、可引用金句和来源依据说明。当用户提供逐字稿、讲者、定位说明或禁止 claim 时使用。
|
||||
---
|
||||
|
||||
# Webinar 内容复用
|
||||
|
||||
## 工作流
|
||||
1. 阅读逐字稿、讲者姓名、产品定位说明和禁止 claim。
|
||||
2. 提取核心主题、最强的来源支持观点和可用引语。
|
||||
3. 起草一条 LinkedIn 帖子、一段邮件 teaser、一段 newsletter 和若干金句。
|
||||
4. 对照逐字稿和禁止 claim 检查每个说法。
|
||||
5. 为重要 claim 添加来源依据说明。
|
||||
|
||||
## 输出
|
||||
- LinkedIn 帖子
|
||||
- 邮件 teaser
|
||||
- Newsletter 段落
|
||||
- 可引用金句
|
||||
- 来源依据说明
|
||||
- 已避免的 claim
|
||||
|
||||
## 参考资料
|
||||
语气见 `references/brand-voice.md`,禁止 claim 见 `references/banned-claims.md`。</code></pre>
|
||||
|
||||
<h3>agents/openai.yaml</h3>
|
||||
<pre><code>display_name: Webinar 内容复用
|
||||
short_description: 将 webinar 逐字稿转成有来源依据的市场内容。
|
||||
default_prompt: 请把这份 webinar 逐字稿复用成可发布的多渠道市场内容。</code></pre>
|
||||
|
||||
<h3>验证</h3>
|
||||
<p>用包含强金句、证据较弱、以及容易误用禁止 claim 的逐字稿测试。确认输出会避免没有依据的 claim。</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
<section class="variant">
|
||||
<div class="variant-head">
|
||||
<h2>方案 B</h2>
|
||||
<span class="badge">来源已隐藏</span>
|
||||
</div>
|
||||
<div class="variant-body">
|
||||
<h2>Skill 包建议:webinar-repurposer</h2>
|
||||
|
||||
<h3>边界</h3>
|
||||
<p>负责在提供来源逐字稿和定位约束时,把逐字稿复用为市场内容。排除全新 campaign strategy、没有依据的产品 claim、法律审核和一次性文案润色。</p>
|
||||
|
||||
<h3>类型</h3>
|
||||
<p>Production-light。它需要输出质量检查和 banned-claim 防护,但除非涉及受监管 claim 或上市公司披露规则,否则不需要做成很重的 governed 包。</p>
|
||||
|
||||
<h3>包结构</h3>
|
||||
<pre><code>webinar-repurposer/
|
||||
SKILL.md
|
||||
agents/interface.yaml
|
||||
references/
|
||||
brand-voice.md
|
||||
positioning-notes.md
|
||||
banned-claims.md
|
||||
evals/
|
||||
output/
|
||||
cases.jsonl
|
||||
reports/
|
||||
output-risk-profile.md
|
||||
prompt-quality-profile.md</code></pre>
|
||||
|
||||
<h3>SKILL.md</h3>
|
||||
<pre><code>---
|
||||
name: webinar-repurposer
|
||||
description: 将重复出现的 webinar 逐字稿复用为有来源依据的 LinkedIn 帖子、邮件 teaser、newsletter 段落、金句和 claim 依据说明。当提供逐字稿、讲者、定位说明或禁止 claim 时使用。不要用于无依据的发布 claim、法律审批、全新 campaign strategy 或一次性文案润色。
|
||||
---
|
||||
|
||||
# Webinar 内容复用
|
||||
|
||||
## 工作流
|
||||
1. 确认逐字稿是事实来源。
|
||||
2. 提取有来源支持的主题、讲者背书的引语和可安全复用的 claim。
|
||||
3. 起草前先检查 `references/banned-claims.md`。
|
||||
4. 生成各渠道输出,但不要添加逐字稿中没有的性能数字、客户结果或产品承诺。
|
||||
5. 添加来源依据说明,把每个主要 claim 绑定到逐字稿证据。
|
||||
|
||||
## 必填输出
|
||||
- linkedin_post
|
||||
- email_teaser
|
||||
- newsletter_section
|
||||
- pull_quotes
|
||||
- source_grounding_notes
|
||||
- claims_avoided
|
||||
- missing_evidence</code></pre>
|
||||
|
||||
<h3>输出风险画像</h3>
|
||||
<p>常见失败:</p>
|
||||
<ul>
|
||||
<li>生成任何产品都能用的泛泛市场话术。</li>
|
||||
<li>编造指标或客户结果。</li>
|
||||
<li>过度改写金句,导致意思偏离。</li>
|
||||
<li>因为某个 claim 很有吸引力而忽略 banned claims。</li>
|
||||
</ul>
|
||||
|
||||
<h3>输出评测用例</h3>
|
||||
<p>1. 逐字稿包含诱人的“guaranteed ROI”禁止 claim:输出必须避开。</p>
|
||||
<p>2. 逐字稿没有量化证明:输出不能编造数字。</p>
|
||||
<p>3. 讲者原话不够顺:可以轻微修语法,但必须保留原意。</p>
|
||||
<p>4. 近邻请求:“从零写一个新 campaign idea”不应路由到这里。</p>
|
||||
|
||||
<h3>审查门禁</h3>
|
||||
<ul>
|
||||
<li>必填 section 必须全部出现。</li>
|
||||
<li>Banned claim 检查必须显式出现。</li>
|
||||
<li>来源依据说明必须引用逐字稿位置或原话片段。</li>
|
||||
<li>缺失证据必须被标出,而不是用通用卖点填补。</li>
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
</div>
|
||||
|
||||
<section class="review-box">
|
||||
<h2>你的判断</h2>
|
||||
<p class="note">只根据评审标准和页面里可见的两个输出做判断。选择会保存到当前浏览器的本地存储里,也可以回到入口页导出。</p>
|
||||
<div class="controls" role="radiogroup" aria-label="胜出方案">
|
||||
<label><input type="radio" name="winner" value="A"> 方案 A 更好</label>
|
||||
<label><input type="radio" name="winner" value="B"> 方案 B 更好</label>
|
||||
<label><input type="radio" name="winner" value="tie"> 平局 / 没有明显胜出</label>
|
||||
</div>
|
||||
<label for="confidence">信心程度</label>
|
||||
<div class="controls">
|
||||
<select id="confidence">
|
||||
<option value="">请选择</option>
|
||||
<option value="0.4">0.4,较弱</option>
|
||||
<option value="0.6">0.6,中等</option>
|
||||
<option value="0.8">0.8,较强</option>
|
||||
<option value="1.0">1.0,非常确定</option>
|
||||
</select>
|
||||
</div>
|
||||
<label for="reason">理由</label>
|
||||
<textarea id="reason" placeholder="为什么这个方案更好?请写出具体的评审标准差异。"></textarea>
|
||||
<div class="controls">
|
||||
<button class="primary" type="button" onclick="saveDecision()">保存判断</button>
|
||||
<button type="button" onclick="clearDecision()">清空</button>
|
||||
</div>
|
||||
<p id="save-status" class="small note"></p>
|
||||
</section>
|
||||
</main>
|
||||
<script>
|
||||
const caseId = document.body.dataset.caseId;
|
||||
const key = "blindSkillReview:" + caseId;
|
||||
function currentDecision() {
|
||||
const selected = document.querySelector('input[name="winner"]:checked');
|
||||
return {
|
||||
case_id: caseId,
|
||||
winner_variant: selected ? selected.value : "",
|
||||
confidence: document.getElementById("confidence").value,
|
||||
reason: document.getElementById("reason").value.trim(),
|
||||
reviewed_at: new Date().toISOString()
|
||||
};
|
||||
}
|
||||
function saveDecision() {
|
||||
const decision = currentDecision();
|
||||
localStorage.setItem(key, JSON.stringify(decision));
|
||||
document.getElementById("save-status").textContent = "已保存:" + decision.reviewed_at;
|
||||
}
|
||||
function clearDecision() {
|
||||
localStorage.removeItem(key);
|
||||
document.querySelectorAll('input[name="winner"]').forEach(el => el.checked = false);
|
||||
document.getElementById("confidence").value = "";
|
||||
document.getElementById("reason").value = "";
|
||||
document.getElementById("save-status").textContent = "已清空。";
|
||||
}
|
||||
function loadDecision() {
|
||||
const raw = localStorage.getItem(key);
|
||||
if (!raw) return;
|
||||
const decision = JSON.parse(raw);
|
||||
const selected = document.querySelector('input[name="winner"][value="' + decision.winner_variant + '"]');
|
||||
if (selected) selected.checked = true;
|
||||
document.getElementById("confidence").value = decision.confidence || "";
|
||||
document.getElementById("reason").value = decision.reason || "";
|
||||
document.getElementById("save-status").textContent = "已加载保存过的判断。";
|
||||
}
|
||||
loadDecision();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,361 @@
|
||||
<!doctype html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>故障复盘 Skill - Skill 盲测评审</title>
|
||||
<style>
|
||||
:root {
|
||||
color-scheme: light;
|
||||
--bg: #f7f8fb;
|
||||
--panel: #ffffff;
|
||||
--ink: #20242c;
|
||||
--muted: #687082;
|
||||
--line: #d9deea;
|
||||
--accent: #2563eb;
|
||||
--accent-2: #0f766e;
|
||||
--warn: #b45309;
|
||||
}
|
||||
* { box-sizing: border-box; }
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
|
||||
background: var(--bg);
|
||||
color: var(--ink);
|
||||
line-height: 1.55;
|
||||
}
|
||||
header {
|
||||
padding: 28px clamp(18px, 4vw, 52px) 18px;
|
||||
background: #ffffff;
|
||||
border-bottom: 1px solid var(--line);
|
||||
}
|
||||
main { padding: 24px clamp(18px, 4vw, 52px) 52px; }
|
||||
h1 { margin: 0 0 8px; font-size: clamp(26px, 3vw, 38px); letter-spacing: 0; }
|
||||
h2 { margin: 0 0 12px; font-size: 20px; }
|
||||
h3 { margin: 18px 0 8px; font-size: 16px; }
|
||||
p { margin: 0 0 10px; }
|
||||
a { color: var(--accent); text-decoration: none; }
|
||||
a:hover { text-decoration: underline; }
|
||||
.meta, .note { color: var(--muted); }
|
||||
.grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 18px; align-items: start; }
|
||||
.card, .panel {
|
||||
background: var(--panel);
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 8px;
|
||||
padding: 18px;
|
||||
}
|
||||
.case-list { display: grid; gap: 12px; margin-top: 18px; }
|
||||
.case-row {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr auto;
|
||||
gap: 12px;
|
||||
align-items: center;
|
||||
background: var(--panel);
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 8px;
|
||||
padding: 14px 16px;
|
||||
}
|
||||
.badge {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
min-height: 28px;
|
||||
padding: 4px 10px;
|
||||
border-radius: 999px;
|
||||
background: #e8f0ff;
|
||||
color: #1d4ed8;
|
||||
font-size: 13px;
|
||||
font-weight: 650;
|
||||
}
|
||||
.rubric { margin: 0; padding-left: 20px; }
|
||||
.rubric li { margin-bottom: 6px; }
|
||||
.variant {
|
||||
background: var(--panel);
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
}
|
||||
.variant-head {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
gap: 12px;
|
||||
align-items: center;
|
||||
padding: 12px 16px;
|
||||
border-bottom: 1px solid var(--line);
|
||||
background: #f2f5fa;
|
||||
}
|
||||
.variant-body { padding: 16px; }
|
||||
pre {
|
||||
overflow: auto;
|
||||
padding: 12px;
|
||||
border-radius: 6px;
|
||||
background: #111827;
|
||||
color: #f9fafb;
|
||||
font-size: 13px;
|
||||
}
|
||||
code { font-family: "SFMono-Regular", Consolas, monospace; }
|
||||
.review-box {
|
||||
margin-top: 18px;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 8px;
|
||||
padding: 16px;
|
||||
background: #fff;
|
||||
}
|
||||
.controls { display: flex; flex-wrap: wrap; gap: 10px; margin: 12px 0; }
|
||||
button, .button {
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 6px;
|
||||
background: #fff;
|
||||
color: var(--ink);
|
||||
min-height: 36px;
|
||||
padding: 7px 12px;
|
||||
cursor: pointer;
|
||||
font-weight: 650;
|
||||
}
|
||||
button.primary, .button.primary { background: var(--accent); border-color: var(--accent); color: #fff; }
|
||||
textarea {
|
||||
width: 100%;
|
||||
min-height: 96px;
|
||||
resize: vertical;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 6px;
|
||||
padding: 10px;
|
||||
font: inherit;
|
||||
}
|
||||
.warn { color: var(--warn); font-weight: 650; }
|
||||
.split { display: flex; flex-wrap: wrap; gap: 10px; }
|
||||
.small { font-size: 13px; }
|
||||
@media (max-width: 900px) {
|
||||
.grid { grid-template-columns: 1fr; }
|
||||
.case-row { grid-template-columns: 1fr; }
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body data-case-id="case-04-incident-postmortem">
|
||||
<header>
|
||||
<div class="split"><a class="button" href="index.html">返回入口</a><a class="button" href="case-03-webinar-repurposing.html">上一个</a><a class="button" href="case-05-pr-review-followup.html">下一个</a></div>
|
||||
<h1>故障复盘 Skill</h1>
|
||||
<p class="meta">A/B 盲测评审。记录完判断前,不要打开答案钥匙。</p>
|
||||
</header>
|
||||
<main>
|
||||
<section class="panel">
|
||||
<h2>场景</h2>
|
||||
<p>一个基础设施团队经常把 Slack 故障时间线、告警数据和部署记录整理成故障复盘和后续行动项。</p>
|
||||
<h3>用户请求</h3>
|
||||
<p>请创建一个可复用的 governed skill,用于故障复盘。输入包括告警时间线、Slack 摘要、部署记录、客户影响说明和负责人列表。输出应包含时间线、影响、根因假设、行动项、未解决证据和后续负责人矩阵。</p>
|
||||
<h3>评审标准</h3>
|
||||
<ol class="rubric"><li>是否处理 governed/运营风险和未解决证据。</li>
|
||||
<li>是否区分假设和已确认根因。</li>
|
||||
<li>是否定义行动项负责人矩阵和回滚/跟进边界。</li>
|
||||
<li>是否要求 file-backed 或 source-backed 证据。</li>
|
||||
<li>是否有针对 blame language 和编造因果的审查门禁。</li></ol>
|
||||
</section>
|
||||
|
||||
<div class="grid" style="margin-top:18px">
|
||||
|
||||
<section class="variant">
|
||||
<div class="variant-head">
|
||||
<h2>方案 A</h2>
|
||||
<span class="badge">来源已隐藏</span>
|
||||
</div>
|
||||
<div class="variant-body">
|
||||
<h2>Skill 包建议:incident-postmortem</h2>
|
||||
|
||||
<h3>边界</h3>
|
||||
<p>负责根据 source-backed 时间线、Slack 摘要、部署记录、客户影响说明和负责人列表起草 governed 故障复盘。不要用于实时 incident command、最终 RCA 签核、HR/归责分析或面向客户的法律声明。</p>
|
||||
|
||||
<h3>类型</h3>
|
||||
<p>Governed。这个包会影响运营责任归属,如果证据不足,容易制造虚假因果。</p>
|
||||
|
||||
<h3>包结构</h3>
|
||||
<pre><code>incident-postmortem/
|
||||
SKILL.md
|
||||
agents/interface.yaml
|
||||
references/
|
||||
postmortem-contract.md
|
||||
severity-policy.md
|
||||
blame-free-language.md
|
||||
action-owner-matrix.md
|
||||
evals/
|
||||
output/
|
||||
cases.jsonl
|
||||
fixtures/
|
||||
alert_timeline.json
|
||||
slack_summary.md
|
||||
deploy_notes.md
|
||||
reports/
|
||||
output-risk-profile.md
|
||||
output_quality_scorecard.md
|
||||
trust_report.md
|
||||
review-studio.html</code></pre>
|
||||
|
||||
<h3>SKILL.md</h3>
|
||||
<pre><code>---
|
||||
name: incident-postmortem
|
||||
description: 根据告警时间线、Slack 摘要、部署记录、影响说明和负责人列表起草 governed 故障复盘。用于 source-backed 时间线重建、影响总结、根因假设、行动项、未解决证据和后续负责人矩阵。不要用于实时故障指挥、最终 RCA 审批、归责或法律/客户承诺。
|
||||
---
|
||||
|
||||
# 故障复盘
|
||||
|
||||
## 工作流
|
||||
1. 要求提供 source-backed 故障输入,并把缺失输入列为 `missing evidence`。
|
||||
2. 只根据已提供时间戳建立时间线;如需推断顺序,必须明确标注。
|
||||
3. 分开列出 `confirmed_facts`、`root_cause_hypotheses` 和 `unresolved_evidence`。
|
||||
4. 总结客户影响,但不要编造受影响账户、持续时间或 SLA 违约。
|
||||
5. 创建行动项:包含 owner、due date、验证信号和回滚/跟进边界。
|
||||
6. 使用 `references/blame-free-language.md` 的无责语言。
|
||||
7. 除非 reviewer 明确提供,否则最终 RCA 审批不属于本 skill。
|
||||
|
||||
## 输出契约
|
||||
- incident_summary
|
||||
- source_inputs
|
||||
- timeline
|
||||
- customer_impact
|
||||
- confirmed_facts
|
||||
- root_cause_hypotheses
|
||||
- unresolved_evidence
|
||||
- action_items
|
||||
- owner_matrix
|
||||
- approval_status</code></pre>
|
||||
|
||||
<h3>输出评测用例</h3>
|
||||
<p>1. Slack 和部署记录冲突:必须保留为未解决证据。</p>
|
||||
<p>2. 告警时间线缺恢复时间:不能编造持续时长。</p>
|
||||
<p>3. 用户要求实时故障决策:应路由出去,或说明本 skill 只做复盘。</p>
|
||||
<p>4. 来源材料带有归责语言:输出必须改写为系统/流程语言。</p>
|
||||
<p>5. 缺负责人列表:行动项 owner 字段应为 `missing evidence`。</p>
|
||||
|
||||
<h3>门禁</h3>
|
||||
<ul>
|
||||
<li>时间线和部署记录需要 file-backed fixture 覆盖。</li>
|
||||
<li>输出评测禁止编造因果和隐藏未解决证据。</li>
|
||||
<li>Review Studio 在人工 reviewer 审批行动负责人矩阵前保持 warning。</li>
|
||||
<li>Trust report 应显示无网络和无破坏性操作。</li>
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
<section class="variant">
|
||||
<div class="variant-head">
|
||||
<h2>方案 B</h2>
|
||||
<span class="badge">来源已隐藏</span>
|
||||
</div>
|
||||
<div class="variant-body">
|
||||
<h2>建议 Skill:incident-postmortem</h2>
|
||||
|
||||
<h3>目的</h3>
|
||||
<p>帮助 Codex 根据时间线、Slack 摘要、部署记录、影响说明和负责人列表创建结构化故障复盘。</p>
|
||||
|
||||
<h3>包结构</h3>
|
||||
<pre><code>incident-postmortem/
|
||||
SKILL.md
|
||||
agents/openai.yaml
|
||||
references/
|
||||
postmortem-template.md
|
||||
severity-policy.md</code></pre>
|
||||
|
||||
<h3>SKILL.md 草稿</h3>
|
||||
<pre><code>---
|
||||
name: incident-postmortem
|
||||
description: 根据告警时间线、Slack 摘要、部署记录、客户影响说明和负责人列表创建故障复盘。当用户需要时间线、影响、根因假设、行动项、未解决证据或负责人矩阵时使用。
|
||||
---
|
||||
|
||||
# 故障复盘
|
||||
|
||||
## 工作流
|
||||
1. 收集告警时间线、Slack 摘要、部署记录、客户影响说明和负责人列表。
|
||||
2. 建立按时间排序的时间线。
|
||||
3. 总结客户和系统影响。
|
||||
4. 识别已确认事实和根因假设。
|
||||
5. 在提供负责人和截止时间时,起草行动项。
|
||||
6. 清楚标记未解决证据。
|
||||
7. 避免归责式语言。
|
||||
|
||||
## 输出
|
||||
- 故障摘要
|
||||
- 时间线
|
||||
- 影响
|
||||
- 根因假设
|
||||
- 已确认事实
|
||||
- 未解决证据
|
||||
- 行动项
|
||||
- 负责人矩阵</code></pre>
|
||||
|
||||
<h3>agents/openai.yaml</h3>
|
||||
<pre><code>display_name: 故障复盘
|
||||
short_description: 根据故障证据生成结构化复盘。
|
||||
default_prompt: 请把这些故障证据整理成复盘和负责人矩阵。</code></pre>
|
||||
|
||||
<h3>验证</h3>
|
||||
<p>用证据完整、缺部署记录、Slack 说法冲突和暂时没有根因的 case 测试。确认 skill 会区分事实和假设。</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
</div>
|
||||
|
||||
<section class="review-box">
|
||||
<h2>你的判断</h2>
|
||||
<p class="note">只根据评审标准和页面里可见的两个输出做判断。选择会保存到当前浏览器的本地存储里,也可以回到入口页导出。</p>
|
||||
<div class="controls" role="radiogroup" aria-label="胜出方案">
|
||||
<label><input type="radio" name="winner" value="A"> 方案 A 更好</label>
|
||||
<label><input type="radio" name="winner" value="B"> 方案 B 更好</label>
|
||||
<label><input type="radio" name="winner" value="tie"> 平局 / 没有明显胜出</label>
|
||||
</div>
|
||||
<label for="confidence">信心程度</label>
|
||||
<div class="controls">
|
||||
<select id="confidence">
|
||||
<option value="">请选择</option>
|
||||
<option value="0.4">0.4,较弱</option>
|
||||
<option value="0.6">0.6,中等</option>
|
||||
<option value="0.8">0.8,较强</option>
|
||||
<option value="1.0">1.0,非常确定</option>
|
||||
</select>
|
||||
</div>
|
||||
<label for="reason">理由</label>
|
||||
<textarea id="reason" placeholder="为什么这个方案更好?请写出具体的评审标准差异。"></textarea>
|
||||
<div class="controls">
|
||||
<button class="primary" type="button" onclick="saveDecision()">保存判断</button>
|
||||
<button type="button" onclick="clearDecision()">清空</button>
|
||||
</div>
|
||||
<p id="save-status" class="small note"></p>
|
||||
</section>
|
||||
</main>
|
||||
<script>
|
||||
const caseId = document.body.dataset.caseId;
|
||||
const key = "blindSkillReview:" + caseId;
|
||||
function currentDecision() {
|
||||
const selected = document.querySelector('input[name="winner"]:checked');
|
||||
return {
|
||||
case_id: caseId,
|
||||
winner_variant: selected ? selected.value : "",
|
||||
confidence: document.getElementById("confidence").value,
|
||||
reason: document.getElementById("reason").value.trim(),
|
||||
reviewed_at: new Date().toISOString()
|
||||
};
|
||||
}
|
||||
function saveDecision() {
|
||||
const decision = currentDecision();
|
||||
localStorage.setItem(key, JSON.stringify(decision));
|
||||
document.getElementById("save-status").textContent = "已保存:" + decision.reviewed_at;
|
||||
}
|
||||
function clearDecision() {
|
||||
localStorage.removeItem(key);
|
||||
document.querySelectorAll('input[name="winner"]').forEach(el => el.checked = false);
|
||||
document.getElementById("confidence").value = "";
|
||||
document.getElementById("reason").value = "";
|
||||
document.getElementById("save-status").textContent = "已清空。";
|
||||
}
|
||||
function loadDecision() {
|
||||
const raw = localStorage.getItem(key);
|
||||
if (!raw) return;
|
||||
const decision = JSON.parse(raw);
|
||||
const selected = document.querySelector('input[name="winner"][value="' + decision.winner_variant + '"]');
|
||||
if (selected) selected.checked = true;
|
||||
document.getElementById("confidence").value = decision.confidence || "";
|
||||
document.getElementById("reason").value = decision.reason || "";
|
||||
document.getElementById("save-status").textContent = "已加载保存过的判断。";
|
||||
}
|
||||
loadDecision();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,344 @@
|
||||
<!doctype html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>PR Review 跟进 Skill - Skill 盲测评审</title>
|
||||
<style>
|
||||
:root {
|
||||
color-scheme: light;
|
||||
--bg: #f7f8fb;
|
||||
--panel: #ffffff;
|
||||
--ink: #20242c;
|
||||
--muted: #687082;
|
||||
--line: #d9deea;
|
||||
--accent: #2563eb;
|
||||
--accent-2: #0f766e;
|
||||
--warn: #b45309;
|
||||
}
|
||||
* { box-sizing: border-box; }
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
|
||||
background: var(--bg);
|
||||
color: var(--ink);
|
||||
line-height: 1.55;
|
||||
}
|
||||
header {
|
||||
padding: 28px clamp(18px, 4vw, 52px) 18px;
|
||||
background: #ffffff;
|
||||
border-bottom: 1px solid var(--line);
|
||||
}
|
||||
main { padding: 24px clamp(18px, 4vw, 52px) 52px; }
|
||||
h1 { margin: 0 0 8px; font-size: clamp(26px, 3vw, 38px); letter-spacing: 0; }
|
||||
h2 { margin: 0 0 12px; font-size: 20px; }
|
||||
h3 { margin: 18px 0 8px; font-size: 16px; }
|
||||
p { margin: 0 0 10px; }
|
||||
a { color: var(--accent); text-decoration: none; }
|
||||
a:hover { text-decoration: underline; }
|
||||
.meta, .note { color: var(--muted); }
|
||||
.grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 18px; align-items: start; }
|
||||
.card, .panel {
|
||||
background: var(--panel);
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 8px;
|
||||
padding: 18px;
|
||||
}
|
||||
.case-list { display: grid; gap: 12px; margin-top: 18px; }
|
||||
.case-row {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr auto;
|
||||
gap: 12px;
|
||||
align-items: center;
|
||||
background: var(--panel);
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 8px;
|
||||
padding: 14px 16px;
|
||||
}
|
||||
.badge {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
min-height: 28px;
|
||||
padding: 4px 10px;
|
||||
border-radius: 999px;
|
||||
background: #e8f0ff;
|
||||
color: #1d4ed8;
|
||||
font-size: 13px;
|
||||
font-weight: 650;
|
||||
}
|
||||
.rubric { margin: 0; padding-left: 20px; }
|
||||
.rubric li { margin-bottom: 6px; }
|
||||
.variant {
|
||||
background: var(--panel);
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
}
|
||||
.variant-head {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
gap: 12px;
|
||||
align-items: center;
|
||||
padding: 12px 16px;
|
||||
border-bottom: 1px solid var(--line);
|
||||
background: #f2f5fa;
|
||||
}
|
||||
.variant-body { padding: 16px; }
|
||||
pre {
|
||||
overflow: auto;
|
||||
padding: 12px;
|
||||
border-radius: 6px;
|
||||
background: #111827;
|
||||
color: #f9fafb;
|
||||
font-size: 13px;
|
||||
}
|
||||
code { font-family: "SFMono-Regular", Consolas, monospace; }
|
||||
.review-box {
|
||||
margin-top: 18px;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 8px;
|
||||
padding: 16px;
|
||||
background: #fff;
|
||||
}
|
||||
.controls { display: flex; flex-wrap: wrap; gap: 10px; margin: 12px 0; }
|
||||
button, .button {
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 6px;
|
||||
background: #fff;
|
||||
color: var(--ink);
|
||||
min-height: 36px;
|
||||
padding: 7px 12px;
|
||||
cursor: pointer;
|
||||
font-weight: 650;
|
||||
}
|
||||
button.primary, .button.primary { background: var(--accent); border-color: var(--accent); color: #fff; }
|
||||
textarea {
|
||||
width: 100%;
|
||||
min-height: 96px;
|
||||
resize: vertical;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 6px;
|
||||
padding: 10px;
|
||||
font: inherit;
|
||||
}
|
||||
.warn { color: var(--warn); font-weight: 650; }
|
||||
.split { display: flex; flex-wrap: wrap; gap: 10px; }
|
||||
.small { font-size: 13px; }
|
||||
@media (max-width: 900px) {
|
||||
.grid { grid-template-columns: 1fr; }
|
||||
.case-row { grid-template-columns: 1fr; }
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body data-case-id="case-05-pr-review-followup">
|
||||
<header>
|
||||
<div class="split"><a class="button" href="index.html">返回入口</a><a class="button" href="case-04-incident-postmortem.html">上一个</a></div>
|
||||
<h1>PR Review 跟进 Skill</h1>
|
||||
<p class="meta">A/B 盲测评审。记录完判断前,不要打开答案钥匙。</p>
|
||||
</header>
|
||||
<main>
|
||||
<section class="panel">
|
||||
<h2>场景</h2>
|
||||
<p>一个小工程团队经常收到 GitHub PR review comments,希望 Codex 能把评论转成补丁、回复摘要和验证记录。</p>
|
||||
<h3>用户请求</h3>
|
||||
<p>请设计一个用于处理 PR review comments 的可复用 skill。输入包括 review comments、变更文件、失败 CI 说明和 maintainer preferences。输出需要分组评论、只修改相关文件、写回复说明并运行验证。必须避免回滚无关的用户改动。</p>
|
||||
<h3>评审标准</h3>
|
||||
<ol class="rubric"><li>是否理解 code-review 跟进和 dirty worktree 安全。</li>
|
||||
<li>是否定义评论分组、补丁、回复和验证工作流。</li>
|
||||
<li>是否避免过度重构和无关 revert。</li>
|
||||
<li>是否说明变更后需要的命令和证据。</li>
|
||||
<li>是否定义一般 code review 与评论跟进的触发排除。</li></ol>
|
||||
</section>
|
||||
|
||||
<div class="grid" style="margin-top:18px">
|
||||
|
||||
<section class="variant">
|
||||
<div class="variant-head">
|
||||
<h2>方案 A</h2>
|
||||
<span class="badge">来源已隐藏</span>
|
||||
</div>
|
||||
<div class="variant-body">
|
||||
<h2>建议 Skill:pr-review-followup</h2>
|
||||
|
||||
<h3>目的</h3>
|
||||
<p>创建一个 skill,帮助 Codex 安全处理 PR review comments,并总结回复。</p>
|
||||
|
||||
<h3>包结构</h3>
|
||||
<pre><code>pr-review-followup/
|
||||
SKILL.md
|
||||
agents/openai.yaml
|
||||
references/
|
||||
response-style.md</code></pre>
|
||||
|
||||
<h3>SKILL.md 草稿</h3>
|
||||
<pre><code>---
|
||||
name: pr-review-followup
|
||||
description: 通过分组反馈、修改相关文件、编写回复说明和运行验证来处理 GitHub PR review comments。当用户提供 review comments、变更文件、CI 说明或 maintainer preferences 时使用。
|
||||
---
|
||||
|
||||
# PR Review 跟进
|
||||
|
||||
## 工作流
|
||||
1. 阅读所有 review comments,并按文件、主题和严重程度分组。
|
||||
2. 编辑前检查受影响文件。
|
||||
3. 只修改处理 comments 所需的文件。
|
||||
4. 不要回滚无关用户改动。
|
||||
5. 运行相关测试或 CI 复现命令。
|
||||
6. 总结变更,并为 reviewer 起草回复说明。
|
||||
|
||||
## 输出
|
||||
- 评论分组
|
||||
- 修改文件
|
||||
- 验证命令
|
||||
- Reviewer 回复说明
|
||||
- 剩余问题</code></pre>
|
||||
|
||||
<h3>agents/openai.yaml</h3>
|
||||
<pre><code>display_name: PR Review 跟进
|
||||
short_description: 处理 PR comments 并准备 reviewer 回复。
|
||||
default_prompt: 请处理这些 PR review comments,并总结验证结果。</code></pre>
|
||||
|
||||
<h3>验证</h3>
|
||||
<p>用需要代码修改、文档修改、无需修改只需解释、以及 reviewer 要求冲突的 comments 测试。</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
<section class="variant">
|
||||
<div class="variant-head">
|
||||
<h2>方案 B</h2>
|
||||
<span class="badge">来源已隐藏</span>
|
||||
</div>
|
||||
<div class="variant-body">
|
||||
<h2>Skill 包建议:pr-review-followup</h2>
|
||||
|
||||
<h3>边界</h3>
|
||||
<p>负责 PR 已经有明确 reviewer comments、变更文件或 CI 说明之后的评论跟进。排除首次 code review、大范围重构、issue triage,以及没有绑定评论的推测性清理。</p>
|
||||
|
||||
<h3>包结构</h3>
|
||||
<pre><code>pr-review-followup/
|
||||
SKILL.md
|
||||
agents/interface.yaml
|
||||
references/
|
||||
response-style.md
|
||||
dirty-worktree-safety.md
|
||||
verification-policy.md
|
||||
evals/
|
||||
trigger_cases.json
|
||||
output/
|
||||
cases.jsonl
|
||||
reports/
|
||||
output-risk-profile.md
|
||||
output_quality_scorecard.md</code></pre>
|
||||
|
||||
<h3>SKILL.md</h3>
|
||||
<pre><code>---
|
||||
name: pr-review-followup
|
||||
description: 处理具体 PR review comments:分组反馈、只修改相关文件、保留无关用户改动、起草 reviewer 回复并运行验证。当提供 review comments、变更文件、失败 CI 说明或 maintainer preferences 时使用。不要用于首次 code review、大范围重构、issue triage 或无关清理。
|
||||
---
|
||||
|
||||
# PR Review 跟进
|
||||
|
||||
## 工作流
|
||||
1. 编辑前记录 git status,并识别用户已经改动的文件。
|
||||
2. 按文件、行为、严重程度,以及是否需要代码、测试、文档或仅解释来分组 review comments。
|
||||
3. 修改前阅读受影响代码和附近测试。
|
||||
4. 只修改与评论绑定的文件。不要回滚无关改动,也不要格式化未触碰文件。
|
||||
5. 运行有针对性的验证,并记录命令和结果。
|
||||
6. 起草 reviewer 回复说明,把每组评论映射到变更、无需修改的理由或剩余问题。
|
||||
7. 如果评论冲突,停止并询问哪个 reviewer 指令优先。
|
||||
|
||||
## 输出契约
|
||||
- comment_groups
|
||||
- patch_summary
|
||||
- files_changed
|
||||
- verification
|
||||
- reviewer_response_notes
|
||||
- unresolved_questions
|
||||
- unrelated_changes_preserved</code></pre>
|
||||
|
||||
<h3>输出评测用例</h3>
|
||||
<p>1. 评论要求添加特定 null check:输出必须只修改受影响函数,并提到测试。</p>
|
||||
<p>2. Reviewer 要求与 PR 范围无关的大重构:输出应标出范围风险。</p>
|
||||
<p>3. Dirty worktree 中有无关用户文件:输出必须保留它。</p>
|
||||
<p>4. 两个 reviewer comments 冲突:输出必须询问优先级,而不是猜。</p>
|
||||
<p>5. 近邻请求:“从零 review 这个 PR”不应触发 follow-up mode。</p>
|
||||
|
||||
<h3>门禁</h3>
|
||||
<ul>
|
||||
<li>触发评测必须区分首次 review 和评论跟进。</li>
|
||||
<li>如果回滚或隐藏无关改动,输出评测必须失败。</li>
|
||||
<li>验证策略必须记录跳过测试的原因。</li>
|
||||
<li>回复说明必须能追溯到评论分组。</li>
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
</div>
|
||||
|
||||
<section class="review-box">
|
||||
<h2>你的判断</h2>
|
||||
<p class="note">只根据评审标准和页面里可见的两个输出做判断。选择会保存到当前浏览器的本地存储里,也可以回到入口页导出。</p>
|
||||
<div class="controls" role="radiogroup" aria-label="胜出方案">
|
||||
<label><input type="radio" name="winner" value="A"> 方案 A 更好</label>
|
||||
<label><input type="radio" name="winner" value="B"> 方案 B 更好</label>
|
||||
<label><input type="radio" name="winner" value="tie"> 平局 / 没有明显胜出</label>
|
||||
</div>
|
||||
<label for="confidence">信心程度</label>
|
||||
<div class="controls">
|
||||
<select id="confidence">
|
||||
<option value="">请选择</option>
|
||||
<option value="0.4">0.4,较弱</option>
|
||||
<option value="0.6">0.6,中等</option>
|
||||
<option value="0.8">0.8,较强</option>
|
||||
<option value="1.0">1.0,非常确定</option>
|
||||
</select>
|
||||
</div>
|
||||
<label for="reason">理由</label>
|
||||
<textarea id="reason" placeholder="为什么这个方案更好?请写出具体的评审标准差异。"></textarea>
|
||||
<div class="controls">
|
||||
<button class="primary" type="button" onclick="saveDecision()">保存判断</button>
|
||||
<button type="button" onclick="clearDecision()">清空</button>
|
||||
</div>
|
||||
<p id="save-status" class="small note"></p>
|
||||
</section>
|
||||
</main>
|
||||
<script>
|
||||
const caseId = document.body.dataset.caseId;
|
||||
const key = "blindSkillReview:" + caseId;
|
||||
function currentDecision() {
|
||||
const selected = document.querySelector('input[name="winner"]:checked');
|
||||
return {
|
||||
case_id: caseId,
|
||||
winner_variant: selected ? selected.value : "",
|
||||
confidence: document.getElementById("confidence").value,
|
||||
reason: document.getElementById("reason").value.trim(),
|
||||
reviewed_at: new Date().toISOString()
|
||||
};
|
||||
}
|
||||
function saveDecision() {
|
||||
const decision = currentDecision();
|
||||
localStorage.setItem(key, JSON.stringify(decision));
|
||||
document.getElementById("save-status").textContent = "已保存:" + decision.reviewed_at;
|
||||
}
|
||||
function clearDecision() {
|
||||
localStorage.removeItem(key);
|
||||
document.querySelectorAll('input[name="winner"]').forEach(el => el.checked = false);
|
||||
document.getElementById("confidence").value = "";
|
||||
document.getElementById("reason").value = "";
|
||||
document.getElementById("save-status").textContent = "已清空。";
|
||||
}
|
||||
function loadDecision() {
|
||||
const raw = localStorage.getItem(key);
|
||||
if (!raw) return;
|
||||
const decision = JSON.parse(raw);
|
||||
const selected = document.querySelector('input[name="winner"][value="' + decision.winner_variant + '"]');
|
||||
if (selected) selected.checked = true;
|
||||
document.getElementById("confidence").value = decision.confidence || "";
|
||||
document.getElementById("reason").value = decision.reason || "";
|
||||
document.getElementById("save-status").textContent = "已加载保存过的判断。";
|
||||
}
|
||||
loadDecision();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,220 @@
|
||||
<!doctype html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>人工盲测评审包 - Meta Skill 对比</title>
|
||||
<style>
|
||||
:root {
|
||||
color-scheme: light;
|
||||
--bg: #f7f8fb;
|
||||
--panel: #ffffff;
|
||||
--ink: #20242c;
|
||||
--muted: #687082;
|
||||
--line: #d9deea;
|
||||
--accent: #2563eb;
|
||||
--accent-2: #0f766e;
|
||||
--warn: #b45309;
|
||||
}
|
||||
* { box-sizing: border-box; }
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
|
||||
background: var(--bg);
|
||||
color: var(--ink);
|
||||
line-height: 1.55;
|
||||
}
|
||||
header {
|
||||
padding: 28px clamp(18px, 4vw, 52px) 18px;
|
||||
background: #ffffff;
|
||||
border-bottom: 1px solid var(--line);
|
||||
}
|
||||
main { padding: 24px clamp(18px, 4vw, 52px) 52px; }
|
||||
h1 { margin: 0 0 8px; font-size: clamp(26px, 3vw, 38px); letter-spacing: 0; }
|
||||
h2 { margin: 0 0 12px; font-size: 20px; }
|
||||
h3 { margin: 18px 0 8px; font-size: 16px; }
|
||||
p { margin: 0 0 10px; }
|
||||
a { color: var(--accent); text-decoration: none; }
|
||||
a:hover { text-decoration: underline; }
|
||||
.meta, .note { color: var(--muted); }
|
||||
.grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 18px; align-items: start; }
|
||||
.card, .panel {
|
||||
background: var(--panel);
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 8px;
|
||||
padding: 18px;
|
||||
}
|
||||
.case-list { display: grid; gap: 12px; margin-top: 18px; }
|
||||
.case-row {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr auto;
|
||||
gap: 12px;
|
||||
align-items: center;
|
||||
background: var(--panel);
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 8px;
|
||||
padding: 14px 16px;
|
||||
}
|
||||
.badge {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
min-height: 28px;
|
||||
padding: 4px 10px;
|
||||
border-radius: 999px;
|
||||
background: #e8f0ff;
|
||||
color: #1d4ed8;
|
||||
font-size: 13px;
|
||||
font-weight: 650;
|
||||
}
|
||||
.rubric { margin: 0; padding-left: 20px; }
|
||||
.rubric li { margin-bottom: 6px; }
|
||||
.variant {
|
||||
background: var(--panel);
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
}
|
||||
.variant-head {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
gap: 12px;
|
||||
align-items: center;
|
||||
padding: 12px 16px;
|
||||
border-bottom: 1px solid var(--line);
|
||||
background: #f2f5fa;
|
||||
}
|
||||
.variant-body { padding: 16px; }
|
||||
pre {
|
||||
overflow: auto;
|
||||
padding: 12px;
|
||||
border-radius: 6px;
|
||||
background: #111827;
|
||||
color: #f9fafb;
|
||||
font-size: 13px;
|
||||
}
|
||||
code { font-family: "SFMono-Regular", Consolas, monospace; }
|
||||
.review-box {
|
||||
margin-top: 18px;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 8px;
|
||||
padding: 16px;
|
||||
background: #fff;
|
||||
}
|
||||
.controls { display: flex; flex-wrap: wrap; gap: 10px; margin: 12px 0; }
|
||||
button, .button {
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 6px;
|
||||
background: #fff;
|
||||
color: var(--ink);
|
||||
min-height: 36px;
|
||||
padding: 7px 12px;
|
||||
cursor: pointer;
|
||||
font-weight: 650;
|
||||
}
|
||||
button.primary, .button.primary { background: var(--accent); border-color: var(--accent); color: #fff; }
|
||||
textarea {
|
||||
width: 100%;
|
||||
min-height: 96px;
|
||||
resize: vertical;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 6px;
|
||||
padding: 10px;
|
||||
font: inherit;
|
||||
}
|
||||
.warn { color: var(--warn); font-weight: 650; }
|
||||
.split { display: flex; flex-wrap: wrap; gap: 10px; }
|
||||
.small { font-size: 13px; }
|
||||
@media (max-width: 900px) {
|
||||
.grid { grid-template-columns: 1fr; }
|
||||
.case-row { grid-template-columns: 1fr; }
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1>人工盲测评审包</h1>
|
||||
<p class="meta">5 个真实常见的 skill 创建场景。打开答案钥匙前,方案来源都会保持隐藏。</p>
|
||||
</header>
|
||||
<main>
|
||||
<section class="panel">
|
||||
<h2>评审说明</h2>
|
||||
<p>依次打开每个案例,按评审标准比较方案 A 和方案 B,保存胜出方案和理由,然后回到这里导出判断结果。5 个判断全部保存前,不要打开 <code>DO_NOT_OPEN_answer_key.html</code> 或 <code>DO_NOT_OPEN_answer_key.json</code>。</p>
|
||||
<p class="warn">证据边界:这些输出是 Codex 在本地套用两份 skill 说明生成的,适合做人类盲测评审,但不能冒充 provider-backed 的独立模型执行证据。</p>
|
||||
<div class="controls">
|
||||
<button class="primary" type="button" onclick="exportDecisions()">导出已保存判断</button>
|
||||
<a class="button" href="review-decisions-template.json">判断模板</a>
|
||||
<a class="button" href="blind-pack.json">盲测包 JSON</a>
|
||||
</div>
|
||||
<textarea id="export" placeholder="导出的判断结果会显示在这里。"></textarea>
|
||||
</section>
|
||||
<section class="case-list">
|
||||
|
||||
<div class="case-row">
|
||||
<div>
|
||||
<div class="badge">案例 1</div>
|
||||
<h2 style="margin-top:10px">客服工单分诊 Skill</h2>
|
||||
<p class="meta">一个 B2B SaaS 团队每天都要处理客户工单:判断分类、紧急程度、起草首轮回复,并把账务、安全、故障类问题升级给对应负责人。他们希望把这个重复流程做成一个给支持团队使用的 Codex skill。</p>
|
||||
</div>
|
||||
<a class="button primary" href="case-01-support-triage.html">打开报告</a>
|
||||
</div>
|
||||
|
||||
<div class="case-row">
|
||||
<div>
|
||||
<div class="badge">案例 2</div>
|
||||
<h2 style="margin-top:10px">月度收入对账 Skill</h2>
|
||||
<p class="meta">一个财务运营团队每个月结账前都要比对 Stripe 导出、数据仓库发票 CSV 和人工调整表,找出金额、币种、发票和调整项的不一致。</p>
|
||||
</div>
|
||||
<a class="button primary" href="case-02-monthly-revenue-reconciliation.html">打开报告</a>
|
||||
</div>
|
||||
|
||||
<div class="case-row">
|
||||
<div>
|
||||
<div class="badge">案例 3</div>
|
||||
<h2 style="margin-top:10px">Webinar 内容复用 Skill</h2>
|
||||
<p class="meta">一个市场团队经常把 webinar 逐字稿改写成 LinkedIn 帖子、邮件 teaser 和 newsletter 段落,同时必须保证所有说法都有来源,并避开禁止宣传的 claim。</p>
|
||||
</div>
|
||||
<a class="button primary" href="case-03-webinar-repurposing.html">打开报告</a>
|
||||
</div>
|
||||
|
||||
<div class="case-row">
|
||||
<div>
|
||||
<div class="badge">案例 4</div>
|
||||
<h2 style="margin-top:10px">故障复盘 Skill</h2>
|
||||
<p class="meta">一个基础设施团队经常把 Slack 故障时间线、告警数据和部署记录整理成故障复盘和后续行动项。</p>
|
||||
</div>
|
||||
<a class="button primary" href="case-04-incident-postmortem.html">打开报告</a>
|
||||
</div>
|
||||
|
||||
<div class="case-row">
|
||||
<div>
|
||||
<div class="badge">案例 5</div>
|
||||
<h2 style="margin-top:10px">PR Review 跟进 Skill</h2>
|
||||
<p class="meta">一个小工程团队经常收到 GitHub PR review comments,希望 Codex 能把评论转成补丁、回复摘要和验证记录。</p>
|
||||
</div>
|
||||
<a class="button primary" href="case-05-pr-review-followup.html">打开报告</a>
|
||||
</div>
|
||||
|
||||
</section>
|
||||
</main>
|
||||
<script>
|
||||
const caseIds = ["case-01-support-triage", "case-02-monthly-revenue-reconciliation", "case-03-webinar-repurposing", "case-04-incident-postmortem", "case-05-pr-review-followup"];
|
||||
function exportDecisions() {
|
||||
const decisions = caseIds.map(id => {
|
||||
const raw = localStorage.getItem("blindSkillReview:" + id);
|
||||
return raw ? JSON.parse(raw) : { case_id: id, winner_variant: "", confidence: "", reason: "", reviewed_at: "" };
|
||||
});
|
||||
const payload = {
|
||||
schema_version: "1.0",
|
||||
review_pack: "blind-human-review-2026-06-29",
|
||||
reviewer: "",
|
||||
blind_review_attestation: {
|
||||
answer_key_not_opened_before_decisions: false,
|
||||
completed_before_answer_key: false
|
||||
},
|
||||
decisions
|
||||
};
|
||||
document.getElementById("export").value = JSON.stringify(payload, null, 2);
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,42 @@
|
||||
{
|
||||
"schema_version": "1.0",
|
||||
"review_pack": "blind-human-review-2026-06-29",
|
||||
"reviewer": "",
|
||||
"reviewed_at": "",
|
||||
"blind_review_attestation": {
|
||||
"answer_key_not_opened_before_decisions": false,
|
||||
"completed_before_answer_key": false
|
||||
},
|
||||
"decisions": [
|
||||
{
|
||||
"case_id": "case-01-support-triage",
|
||||
"winner_variant": "",
|
||||
"confidence": "",
|
||||
"reason": ""
|
||||
},
|
||||
{
|
||||
"case_id": "case-02-monthly-revenue-reconciliation",
|
||||
"winner_variant": "",
|
||||
"confidence": "",
|
||||
"reason": ""
|
||||
},
|
||||
{
|
||||
"case_id": "case-03-webinar-repurposing",
|
||||
"winner_variant": "",
|
||||
"confidence": "",
|
||||
"reason": ""
|
||||
},
|
||||
{
|
||||
"case_id": "case-04-incident-postmortem",
|
||||
"winner_variant": "",
|
||||
"confidence": "",
|
||||
"reason": ""
|
||||
},
|
||||
{
|
||||
"case_id": "case-05-pr-review-followup",
|
||||
"winner_variant": "",
|
||||
"confidence": "",
|
||||
"reason": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
{
|
||||
"schema_version": "1.0",
|
||||
"review_pack": "blind-human-review-2026-06-29",
|
||||
"reviewer": "single human reviewer",
|
||||
"reviewed_at": "2026-06-29T03:01:03.037Z",
|
||||
"recorded_at": "2026-06-29T03:04:34Z",
|
||||
"blind_review_attestation": {
|
||||
"answer_key_not_opened_before_decisions": true,
|
||||
"completed_before_answer_key": true,
|
||||
"attestation_source": "User confirmed in chat after decisions were submitted: 确认:我是在完成五个判断之后才让你打开答案钥匙的,评审前没有看来源。以上 5 个判断都是揭晓来源前完成的。"
|
||||
},
|
||||
"limitations": {
|
||||
"reviewer_count": 1,
|
||||
"reasons_present": false,
|
||||
"reason_gap": "The reviewer selected winners with confidence 1.0, but per-case rationale fields were left empty.",
|
||||
"execution_boundary": "Outputs were generated locally from two skill instruction files. This is human blind A/B review evidence, not provider-backed independent model execution evidence."
|
||||
},
|
||||
"decisions": [
|
||||
{
|
||||
"case_id": "case-01-support-triage",
|
||||
"winner_variant": "B",
|
||||
"confidence": "1.0",
|
||||
"reason": "",
|
||||
"reviewed_at": "2026-06-29T03:00:00.994Z"
|
||||
},
|
||||
{
|
||||
"case_id": "case-02-monthly-revenue-reconciliation",
|
||||
"winner_variant": "A",
|
||||
"confidence": "1.0",
|
||||
"reason": "",
|
||||
"reviewed_at": "2026-06-29T03:00:18.277Z"
|
||||
},
|
||||
{
|
||||
"case_id": "case-03-webinar-repurposing",
|
||||
"winner_variant": "B",
|
||||
"confidence": "1.0",
|
||||
"reason": "",
|
||||
"reviewed_at": "2026-06-29T03:00:34.343Z"
|
||||
},
|
||||
{
|
||||
"case_id": "case-04-incident-postmortem",
|
||||
"winner_variant": "A",
|
||||
"confidence": "1.0",
|
||||
"reason": "",
|
||||
"reviewed_at": "2026-06-29T03:00:49.160Z"
|
||||
},
|
||||
{
|
||||
"case_id": "case-05-pr-review-followup",
|
||||
"winner_variant": "B",
|
||||
"confidence": "1.0",
|
||||
"reason": "",
|
||||
"reviewed_at": "2026-06-29T03:01:03.037Z"
|
||||
}
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user