一场没有新技术的评审
2026 年 11 月 5 日,内容团队向治理评审会提交了一个方案:把 content.summarize 与 moderation.classify 开放给创作者工具,服务对象从主站编辑扩展到外部创作者,预计日调用量从 2,000 次升到 20,000 次。
方案里没有新技术。摘要与审核能力已经跑了两个季度,链路 A 的基线是 96.25%、每次成功交付 3,496 微元、P95 3,523ms。真正需要决定的是四件事:要不要为创作者工具新建一个回复能力、额度从哪里借、创作者草稿能不能进入跨团队评测集、首日放量到多少。
这四件事都不是模型问题,而是治理问题。评审会的作用不是重新讲一遍技术方案,而是让每个受影响的一方带着证据到场,用同一份基线做决定。
会前:七方各带什么
评审记录在会前 48 小时冻结。参会方不是「相关同学都来」,而是七个有明确职责的席位,每席必须带来指定证据。带不齐证据的席位可以发言,但不能投票。
| 席位 | 角色 | 必须带来的证据 | 关心什么 |
|---|---|---|---|
| 内容团队 | 提供方 | 能力契约、试点计划 | 能力是否按自己的场景运行 |
| 创作者工具 | 调用方 | 流量预测 | 配额、延迟、失败时用户看到什么 |
| 交易团队 | 出借方 | 额度账本 | 借出的份额能否按期归还 |
| 平台 | 平台方 | 基线报告 | 目录、版本、成本口径是否一致 |
| 安全 | 安全 | 风险登记 | 新入口是否扩大攻击面 |
| 合规 | 合规 | 留存策略 | 创作者草稿的隐私与删除 |
| SRE | 稳定性 | SLO 看板 | 峰值是否超过平台容量 |
这份名单里没有「领导」席位。治理评审不是汇报会,决策权来自职责与证据,不来自职级。如果某一方缺席,相关议题只能记为待办,不能当场表决通过。
四个争议点
评审材料把分歧提前写成四条,每条都记录各方立场与最终决议。这样做的目的不是消灭分歧,而是让分歧可追踪。
| 编号 | 争议 | 主要立场 | 决议 |
|---|---|---|---|
| D1 | 是否新建 reply.chat | 内容团队要按草稿场景调提示;平台要求同一功能键只有一个在役能力 | 复用 chat.reply 2.1.0,只开放契约内的提示后缀与 economy 档位覆盖 |
| D2 | 借用交易团队 1,500 万微元 | 内容团队大促需要扩容;交易团队要求明确归还日 | 借用 1,500 万,单次上限不变,2026-12-15 前归还,逾期自动回收 |
| D3 | 创作者草稿进入评测集 | 内容团队要真实样本;合规要求不跨租户共享 | 跨团队只用合成与脱敏样本,租户样本留在租户域内 |
| D4 | 首日放量比例 | 内容团队要 100%;SRE 要求先试点 | 先 10% 试点两周,条件关闭后再评审全量 |
D1 的决议值得展开。内容团队的诉求是合理的:草稿场景的措辞确实与客服回复不同。但新建能力会让「回复」这个功能键出现两个在役实现,平台看板上的成功率被拆成两条曲线,复用收益也会消失。最终方案是把差异收进契约允许的覆盖范围,而不是复制一个能力。这既满足了场景,也保住了单一口径。
D2 的关键不是借多少,而是归还规则。没有归还日的借用就是永久占用;没有单次上限约束的借用会让借入方用低价请求把额度迅速耗光。决议把三个数字写死:1,500 万、2026-12-15、单次上限不变。
D3 是合规席位的否决点。创作者草稿包含未发布内容,跨租户共享会形成新的隐私面。评审没有讨论「能不能脱敏到足够安全」,而是直接限定样本类型:跨团队只使用合成样本与已脱敏样本。这条限制会降低评测覆盖率,但它是可执行的。
D4 是放量节奏。内容团队担心试点覆盖不到大促峰值,SRE 担心一次性放量会把平台 P95 推过 SLO。决议采用两阶段:先 10% 试点两周,用试点数据补足评测与容量证据,再开第二次评审判定全量。
基线怎么进入评审
评审的第一页不是方案,而是 13.1 的基线结论:12 条中 9 条通过、2 条部分、1 条失败,总体 conditional,没有 blocking 失败。
这张表改变了讨论方式。没有基线时,各方会从自己的立场出发争论「风险大不大」;有了基线,争论变成「哪条缺口必须在放量前关闭」。三个缺口自然对应到三个待办:评测语料缺隐私级别、合规缺删除演练、退役能力缺 owner 与迁移签字。
基线也限定了决议的上限。conditional 不能被写成 approve,因为那等于宣称所有条件已满足;它只能写成 conditional,并附条件清单。如果基线是 blocked,决议只能是 reject,除非先补掉 blocking 项再重新开会。
决议规则
评审结论只有三种:approve、conditional、reject。它们与基线结论有硬约束:
| 基线结论 | 允许的决议 | 说明 |
|---|---|---|
| pass | approve / conditional / reject | 仍可因其他风险拒绝 |
| conditional | conditional / reject | 不能直接 approve |
| blocked | reject | 必须先补 blocking 项 |
待办也分两类。blocking 待办未关闭前,最多只能试点;非 blocking 待办可以并行推进,不影响试点,但会影响下一次全量评审。每条待办必须有 owner 与截止日期,日期统一写成 YYYY-MM-DD,便于按日比较。
评审记录的实现
下面的模块把参会方、争议、决议、待办与基线判定放在同一个记录里。它先校验记录自身是否一致,再给出放量级别与待办统计。
// file: src/gov/baseline-review.ts
// tier: L2
// verify: node --test test/gov/baseline.test.ts
import { ECHO_BASELINE, evaluateBaseline } from "./baseline.ts";
import type { BaselineItem } from "./baseline.ts";
export type ReviewOutcome = "approve" | "conditional" | "reject";
export type RolloutLevel = "full" | "pilot" | "blocked";
export type ReviewRole = "provider" | "caller" | "platform" | "security" | "compliance" | "sre";
export interface ReviewParticipant {
team: string;
role: ReviewRole;
/** 该参会方必须带来的证据 id;空数组表示只需表决。 */
brings: readonly string[];
}
export interface ReviewDispute {
id: string;
topic: string;
positions: readonly { team: string; position: string }[];
resolution: string;
}
export interface ReviewTodo {
id: string;
owner: string;
/** 截止日期统一写 YYYY-MM-DD,便于按日比较而不是按时间戳比较。 */
due: string;
/** true 表示未关闭前只能试点,不能全量放量。 */
blocking: boolean;
done: boolean;
}
export interface ReviewRecord {
id: string;
subject: string;
baseline: readonly BaselineItem[];
participants: readonly ReviewParticipant[];
disputes: readonly ReviewDispute[];
outcome: ReviewOutcome;
todos: readonly ReviewTodo[];
}
export type ReviewIssueCode =
| "missing-role"
| "duplicate-todo"
| "invalid-todo-owner"
| "invalid-todo-due"
| "blocked-baseline-not-rejected"
| "approve-with-conditional-baseline"
| "approve-with-open-blocking-todo";
export interface ReviewIssue {
code: ReviewIssueCode;
subject: string;
detail: string;
}
const DATE = /^\d{4}-\d{2}-\d{2}$/;
const REQUIRED_ROLES: readonly ReviewRole[] = ["provider", "caller", "platform"];
function openBlockingTodos(record: ReviewRecord): ReviewTodo[] {
return record.todos.filter((todo) => todo.blocking && !todo.done);
}
/**
* 评审记录先自证一致,再谈结论:角色齐、日期合法、决议与基线不矛盾。
* 一次返回全部问题,避免修一个报一个。
*/
export function validateReview(record: ReviewRecord): ReviewIssue[] {
const issues: ReviewIssue[] = [];
const roles = new Set(record.participants.map((person) => person.role));
for (const role of REQUIRED_ROLES) {
if (!roles.has(role)) {
issues.push({ code: "missing-role", subject: role, detail: "required participant is absent" });
}
}
for (const item of record.baseline) {
if (item.domain !== "compliance" && item.domain !== "security") continue;
if (evaluateBaseline([item]).conclusion !== "pass" && !roles.has(item.domain)) {
issues.push({
code: "missing-role",
subject: item.domain,
detail: `${item.id} is not pass and no ${item.domain} participant`,
});
}
}
const seen = new Set<string>();
for (const todo of record.todos) {
if (seen.has(todo.id)) {
issues.push({ code: "duplicate-todo", subject: todo.id, detail: "todo id appears twice" });
}
seen.add(todo.id);
if (todo.owner.trim() === "") {
issues.push({ code: "invalid-todo-owner", subject: todo.id, detail: "owner is empty" });
}
if (!DATE.test(todo.due)) {
issues.push({ code: "invalid-todo-due", subject: todo.id, detail: `bad due ${todo.due}` });
}
}
const baseline = evaluateBaseline(record.baseline);
if (baseline.conclusion === "blocked" && record.outcome !== "reject") {
issues.push({
code: "blocked-baseline-not-rejected",
subject: record.id,
detail: `blocking failures: ${baseline.blockingFailures.join(",")}`,
});
}
if (baseline.conclusion === "conditional" && record.outcome === "approve") {
issues.push({
code: "approve-with-conditional-baseline",
subject: record.id,
detail: `conditions: ${baseline.conditions.join(",")}`,
});
}
if (record.outcome === "approve" && openBlockingTodos(record).length > 0) {
issues.push({
code: "approve-with-open-blocking-todo",
subject: record.id,
detail: openBlockingTodos(record).map((todo) => todo.id).join(","),
});
}
return issues;
}
/**
* 放量级别只由三件事决定:基线是否 blocked、决议是否 reject、是否还有未关闭的
* blocking 待办。三者都清才允许 full,否则最多 pilot。
*/
export function releaseLevel(record: ReviewRecord): RolloutLevel {
const baseline = evaluateBaseline(record.baseline);
if (record.outcome === "reject" || baseline.conclusion === "blocked") return "blocked";
if (record.outcome === "approve" && baseline.conclusion === "pass" && openBlockingTodos(record).length === 0) {
return "full";
}
return "pilot";
}
export type TodoState = "done" | "open" | "overdue";
export interface TodoReport {
total: number;
done: number;
open: number;
overdue: number;
openBlocking: number;
overdueBlocking: number;
}
export function trackTodos(record: ReviewRecord, asOf: string): TodoReport {
if (!DATE.test(asOf)) throw new Error(`review: invalid as-of date ${asOf}`);
const states = record.todos.map((todo): TodoState => {
if (todo.done) return "done";
return todo.due < asOf ? "overdue" : "open";
});
const count = (predicate: (todo: ReviewTodo, index: number) => boolean): number =>
record.todos.filter((todo, index) => predicate(todo, index)).length;
return {
total: record.todos.length,
done: count((_, index) => states[index] === "done"),
open: count((_, index) => states[index] === "open"),
overdue: count((_, index) => states[index] === "overdue"),
openBlocking: count((todo) => todo.blocking && !todo.done),
overdueBlocking: count((todo, index) => todo.blocking && states[index] === "overdue"),
};
}
/** 2026-11-05 的内容团队放量评审,示例记录,不是生产会议纪要。 */
export const ECHO_REVIEW: ReviewRecord = {
id: "gov-review-2026-11-05",
subject: "内容团队把摘要与审核能力开放给创作者工具",
baseline: ECHO_BASELINE,
participants: [
{ team: "content", role: "provider", brings: ["capability-contract", "pilot-plan"] },
{ team: "creator-tools", role: "caller", brings: ["traffic-forecast"] },
{ team: "transaction", role: "caller", brings: ["quota-ledger"] },
{ team: "platform", role: "platform", brings: ["baseline-report"] },
{ team: "security", role: "security", brings: ["risk-register-2026-10"] },
{ team: "compliance", role: "compliance", brings: ["retention-policy"] },
{ team: "sre", role: "sre", brings: ["slo-dashboard"] },
],
disputes: [
{
id: "D1",
topic: "是否为创作者工具新建 reply.chat",
positions: [
{ team: "content", position: "新建能力可以按草稿场景调提示与档位" },
{ team: "platform", position: "同一功能键不允许第二个在役能力" },
],
resolution: "复用 chat.reply 2.1.0,只开放契约内的提示后缀与 economy 档位覆盖",
},
{
id: "D2",
topic: "内容团队借用交易团队 1,500 万微元额度",
positions: [
{ team: "content", position: "大促期间需要临时扩容" },
{ team: "transaction", position: "借用必须在 12 月 15 日前归还" },
],
resolution: "借用 1,500 万微元,单次上限不变,2026-12-15 前归还,逾期自动回收",
},
{
id: "D3",
topic: "创作者草稿能否进入跨团队评测集",
positions: [
{ team: "content", position: "真实草稿最能覆盖边界" },
{ team: "compliance", position: "草稿含未发布内容,不能跨租户共享" },
],
resolution: "跨团队只用合成样本与脱敏样本,租户样本留在租户域内",
},
{
id: "D4",
topic: "首日放量到 100% 还是先试点",
positions: [
{ team: "content", position: "首日 100% 才能覆盖大促峰值" },
{ team: "sre", position: "基线与配额条件未关闭前只能试点" },
],
resolution: "先 10% 试点两周,条件关闭后再评审全量",
},
],
outcome: "conditional",
todos: [
{ id: "T1", owner: "eval-platform", due: "2026-11-12", blocking: true, done: false },
{ id: "T2", owner: "compliance", due: "2026-11-19", blocking: true, done: false },
{ id: "T3", owner: "platform-governance", due: "2026-11-30", blocking: false, done: false },
{ id: "T4", owner: "content", due: "2026-11-08", blocking: false, done: true },
],
};
示例样本上的运行结果
用上面的示例评审记录运行 node --test test/gov/baseline.test.ts,结果是:
| 检查 | 结果 |
|---|---|
validateReview | 返回空数组,记录自身一致 |
releaseLevel | pilot,不是 full,也不是 blocked |
trackTodos(2026-11-05) | 4 条待办:1 完成、3 开放、0 逾期、2 条开放 blocking |
trackTodos(2026-11-20) | 2 条逾期,其中 2 条是 blocking |
releaseLevel 返回 pilot 的原因不是基线 blocked,而是基线 conditional 且还有两条 blocking 待办未关闭。这正是评审想要的结果:内容团队可以开始 10% 试点,但不能把 20,000 次日调用一次性推上去。
到 11 月 20 日,T1 与 T2 都已逾期,且都是 blocking。这时试点本身也要降速:逾期 blocking 待办说明条件没有按计划关闭,继续扩大试点会把未验证的风险带给更多创作者。待办跟踪的意义就在这里,它把「会开完了」变成「条件关闭了没有」。
一次反例:为什么 approve 会被打回
把示例记录的决议改成 approve,再删掉合规席位,校验会返回三类问题:基线 conditional 却直接 approve、存在未关闭的 blocking 待办、合规条目未通过却没有合规参会方。
| 问题码 | 触发条件 | 后果 |
|---|---|---|
approve-with-conditional-baseline | 基线 conditional 且决议 approve | 决议无效,退回重审 |
approve-with-open-blocking-todo | 决议 approve 且存在未关闭 blocking 待办 | 只能按 pilot 执行 |
missing-role | 必需席位缺席或相关条目未通过 | 相关议题不得表决 |
反例说明一件事:评审记录不是会议纪要,而是可执行的约束。字段之间互相校验,才能防止「会上说得很严、纪要写成同意」。
评审之后
散会不是结束。决议要进入三个地方:能力目录记录本次放量的版本与覆盖范围,配额账本记录借用的 1,500 万与归还日,待办系统记录四条任务与 owner。三处都对得上,评审才算落地。
下一次全量评审的入口也很明确:两条 blocking 待办关闭、试点数据覆盖大促峰值、基线重新跑一遍。三项都满足,才把决议从 conditional 改成 approve。如果试点期间出现重复下单、越权或隐私事件,直接回到 blocked,不再讨论放量比例。
小结
这场评审没有产生新技术,只产生了四个决议和四条待办。基线把讨论从「风险大不大」变成「哪条缺口必须先关」,决议规则把 conditional 限定为试点,待办跟踪把会议结论变成可检查的日期与 owner。
跨团队评审的价值不在于人多,而在于每个席位都带证据、每条决议都受基线约束、每个条件都有负责人。下一节离开具体评审,回看四卷的分工与边界。
阅读导航:上一节:13.1 治理基线:回声的平台化清单 · 下一节:13.3 全书回顾与继续阅读 。
常见错误与边界
- 把评审开成汇报会。没有争议点、没有证据、没有待办的会议不产生治理结论。
- 参会方按职级而不是职责选择。决策需要的是 owner、调用方、平台、安全与合规。
- 基线只放在附件里。评审第一页必须是基线结论与缺口清单。
- 基线 conditional 却写 approve。字段校验应当直接把它打回。
- 待办没有 owner 或截止日期。没有这两项,条件永远不会被关闭。
- blocking 与普通待办混在一起。未关闭的 blocking 待办必须限制放量级别。
- 借用额度没有归还日。借用会变成永久占用,季度结算必然争议。
- 用真实租户数据填评测集。跨团队共享前必须限定样本类型与隐私级别。
- 试点没有退出条件。只写「先试点」不写何时扩大、何时停止,试点会无限期停留。
- 评审记录只存本地。目录、账本与待办系统三处对不上,决议就无法执行。
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。