diff --git a/scripts/validate-changelog-frontmatter.mjs b/scripts/validate-changelog-frontmatter.mjs index a12d0f56..2b82914e 100644 --- a/scripts/validate-changelog-frontmatter.mjs +++ b/scripts/validate-changelog-frontmatter.mjs @@ -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 实测, // 它命中的几乎全是错误码表与响应示例里的**文案**(如「584105 结算字典暂时不可用,请稍后重试」), // 那正是本规则必须放行的契约内容。判据的分辨力不够时,门禁只会教人绕开它。 diff --git a/tests/validate-changelog-frontmatter.test.mjs b/tests/validate-changelog-frontmatter.test.mjs index 5e7facd8..b22e6b1b 100644 --- a/tests/validate-changelog-frontmatter.test.mjs +++ b/tests/validate-changelog-frontmatter.test.mjs @@ -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'), []); }); +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', () => { const errors = validateV2Document( FILE,