feat(guard): E_WAIT_LANGUAGE 补第四类——把「什么时候上线」写成派给前端的动作项
changelog-filename-gate / validate (push) Failing after 1s
changelog-filename-gate / validate (push) Failing after 1s
今天上午装这条守卫时只想到「等/待/另发」这一种形态,当天下午就被另一种形态绕过去了: 20_7443 正文写着「上生产前请与后端确认这个开关的状态」与「生产环境未开」, mmg 据此来问上线时间、并要求「后端把生产开关打开」——而守卫全绿,因为这两句 一个词表词都没用上。它们把不确定性包装成了「请你去确认」,语法换了,作用一样: 读者只能停在那里等一个他查不到的状态。 判据仍是那一句:这条影响他「怎么写代码」,还是只影响他「什么时候开始写」。 上线时点属后者。前端需不需要同步上线,由 frontend_action_required 与模板里 「前端是否必须同步上线」那个结构化字段承载,正文自由文本里不该再出现。 词表先对全仓 1068 份 changelog 实跑,只留零命中且零正当用法的 12 个词。剔除两个: 「何时开」 —— 误伤「保护何时开始生效」「窗口何时开过」 「生产上线」—— 误伤 07_5640「生产上线需配 annual-direct-plan-id」,那是真契约边界 部署时间戳没做成规则:该形态全仓 0 命中,分辨力无从验证,而必须放行的 「带时刻实测取证句」有 690 处——判据的误伤面远大于收益时,门禁只会教人绕开它。 这一类只能靠 §2.1 的条文和复盘接住,机器接不住,如实记在注释里。 测试:新增 2 条阳性 + 1 条阴性对照,阴性那条与阳性只差一个「上生产前」, 用来钉住分界线(「收到 809009 找后端确认该环境的开关」是运维处置,必须放行)。 npm test 59 项 58 绿;唯一的红是存量的 E_ALIAS_STATE(11_7510,与本次无关)。 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
这个提交包含在:
@@ -445,6 +445,21 @@ const WAIT_LANGUAGE_PHRASES = [
|
|||||||
// 三、直接叫停对接
|
// 三、直接叫停对接
|
||||||
'请先等', '暂缓对接', '暂不要对接', '先不要对接', '先别对接',
|
'请先等', '暂缓对接', '暂不要对接', '先不要对接', '先别对接',
|
||||||
'我们这边还在', '该缺陷已在修',
|
'我们这边还在', '该缺陷已在修',
|
||||||
|
// 四、把「什么时候上线」写成派给前端的动作项
|
||||||
|
// (2026-09-21 复盘补:20_7443 写了「上生产前请与后端确认这个开关的状态」,
|
||||||
|
// mmg 因此来问上线时间与「请后端把生产开关打开」。上面三类词表一个都没拦住——
|
||||||
|
// 它们匹配的是「等/待/另发」,而这句把不确定性包装成了「请你去确认」。
|
||||||
|
// 上线时点不影响「怎么写代码」,只影响「什么时候开始写」,属本规则该删的那一半。
|
||||||
|
// 前端需不需要同步上线,有 frontend_action_required 与模板里「前端是否必须同步上线」
|
||||||
|
// 那个结构化字段承载,正文自由文本里不再重复。)
|
||||||
|
'上生产前请', '上生产前与', '上线前请', '上线前与',
|
||||||
|
'上线时间', '上线排期', '上生产时间', '何时上线',
|
||||||
|
'由谁开', '谁来开', '排期确定后', '排期确认后',
|
||||||
|
// ⚙ 词表已对全仓 1068 份 changelog 实跑,以上全部零命中。两个候选词被剔除:
|
||||||
|
// 「何时开」——误伤「保护何时开始生效」「窗口何时开过」
|
||||||
|
// 「生产上线」——误伤 07_5640「生产上线需配 annual-direct-plan-id」(真契约边界)
|
||||||
|
// 部署时间戳没做成规则:该形态全仓 0 命中(分辨力验不了),
|
||||||
|
// 而必须放行的「带时刻实测取证句」有 690 处,误伤面远大于收益。
|
||||||
// ⚠️ 不要把「暂不可用 / 暂时不可用」加回来:2026-09-21 对全仓 1968 份 changelog 实测,
|
// ⚠️ 不要把「暂不可用 / 暂时不可用」加回来:2026-09-21 对全仓 1968 份 changelog 实测,
|
||||||
// 它命中的几乎全是错误码表与响应示例里的**文案**(如「584105 结算字典暂时不可用,请稍后重试」),
|
// 它命中的几乎全是错误码表与响应示例里的**文案**(如「584105 结算字典暂时不可用,请稍后重试」),
|
||||||
// 那正是本规则必须放行的契约内容。判据的分辨力不够时,门禁只会教人绕开它。
|
// 那正是本规则必须放行的契约内容。判据的分辨力不够时,门禁只会教人绕开它。
|
||||||
|
|||||||
@@ -187,6 +187,39 @@ test('accepts coverage limits that do not ask the frontend to wait', () => {
|
|||||||
assert.deepEqual(errors.filter(({ code }) => code === 'E_WAIT_LANGUAGE'), []);
|
assert.deepEqual(errors.filter(({ code }) => code === 'E_WAIT_LANGUAGE'), []);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('rejects turning launch timing into an action item for the frontend', () => {
|
||||||
|
const value = document().replace('## 七、不影响范围', `## 六.8、环境开关
|
||||||
|
|
||||||
|
- 上生产前请与后端确认这个开关的状态,否则提交会被拒。
|
||||||
|
|
||||||
|
## 七、不影响范围`);
|
||||||
|
const errors = validateV2Document(FILE, value, { requireV2: true });
|
||||||
|
assert.ok(errors.some(({ code }) => code === 'E_WAIT_LANGUAGE'));
|
||||||
|
});
|
||||||
|
|
||||||
|
test('rejects asking who flips the production switch and when', () => {
|
||||||
|
const value = document().replace('## 七、不影响范围', `## 六.8、环境开关
|
||||||
|
|
||||||
|
- 生产开关由谁开、何时上线,待排期确认后另行同步。
|
||||||
|
|
||||||
|
## 七、不影响范围`);
|
||||||
|
const errors = validateV2Document(FILE, value, { requireV2: true });
|
||||||
|
assert.ok(errors.some(({ code }) => code === 'E_WAIT_LANGUAGE'));
|
||||||
|
});
|
||||||
|
|
||||||
|
// 阴性对照:撞上错误码时的运维处置建议是「怎么诊断」,不是「什么时候开工」,必须放行。
|
||||||
|
// 它与上一条只差一个「上生产前」,正好钉住本规则的分界线。
|
||||||
|
test('accepts runbook advice for an error code without launch timing', () => {
|
||||||
|
const value = document().replace('## 七、不影响范围', `## 六.8、环境开关
|
||||||
|
|
||||||
|
- 收到 \`809009\` 即表示所在环境的开关没开,找后端确认该环境的开关——这不是数据问题,重试与补数据均无效。
|
||||||
|
- 窗口何时开过、保护何时开始生效,都可从时间线事件读到。
|
||||||
|
|
||||||
|
## 七、不影响范围`);
|
||||||
|
const errors = validateV2Document(FILE, value, { requireV2: true });
|
||||||
|
assert.deepEqual(errors.filter(({ code }) => code === 'E_WAIT_LANGUAGE'), []);
|
||||||
|
});
|
||||||
|
|
||||||
test('rejects backend and gateway pending at publication', () => {
|
test('rejects backend and gateway pending at publication', () => {
|
||||||
const errors = validateV2Document(
|
const errors = validateV2Document(
|
||||||
FILE,
|
FILE,
|
||||||
|
|||||||
在新工单中引用
屏蔽一个用户