From b5989a94a1eaf6ec429894aebf3169a781e9e2ae Mon Sep 17 00:00:00 2001 From: JianFeeeee Date: Fri, 25 Sep 2026 06:33:46 +0800 Subject: [PATCH] =?UTF-8?q?feat(deploy):=20=E6=8C=89=20=E2=91=AC=E2=80=B2?= =?UTF-8?q?=20=E7=BB=99=20=E2=91=A4b=20=E4=B8=8E=20=C2=A77=20=E7=9A=84?= =?UTF-8?q?=E7=BB=BF=E8=A1=A5**=E8=B4=9F=E5=90=91=E6=B8=85=E5=8D=95**?= =?UTF-8?q?=EF=BC=88=E5=88=A4=E6=8D=AE=E9=A1=BB=E5=86=99=E5=87=BA=E5=AE=83?= =?UTF-8?q?=E4=B8=8D=E8=A6=86=E7=9B=96=E5=93=AA=E5=87=A0=E7=B1=BB=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit pi 2026-09-25 提的 ⑬′:写"要验 X"时必须写清**动作覆盖到哪**,而"覆盖到哪"要写成 **负向清单**(不覆盖哪些)—— 因为正向范围可以含糊,负向清单必须逐条列,否则等于没写。 他给的量化形式:假绿区 = |R| − |C|(R=宣称范围,C=实际能判红的集合)。 这两个判据原先只在**红**的时候说话,**绿**时读者会把"绿"读成"这份二进制没问题" —— 而它们其实只答了一个问题:"内嵌 revision 是否等于 HEAD"。 ⑤b note(绿时): …;本判据**不覆盖**: ①从脏树构建(含未提交代码,只披露不判红) ②部署后被手工替换/修改(只看内嵌 revision) §7 ok(绿时): 已装二进制 = 当前 HEAD(xxxxxxxx)—— 不覆盖: 从脏树构建 / 部署后手工替换 ★ 这条规矩**已被它自己验证过一次**:我 ⑤b 的 R\C 里那一格(`modified=true` 的脏树构建) **不是我想到的,是 pi 找出来的** —— 我写 ⑤b 时以为 R = C。写出负向清单这件事 本身就会把那格逼出来。 自检新增一格 `★网关二进制:绿时 note 必须写负向清单(不覆盖哪几类)`,62 → **63 项**, `判据自检失败` 不出现;`bash -n` 通过;`--dry-run` rc=0 且不落地。 --- deploy/check-deploy-drift.mjs | 18 +++++++++++++++++- deploy/redeploy-gateway.sh | 5 ++++- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/deploy/check-deploy-drift.mjs b/deploy/check-deploy-drift.mjs index 7443dc3..1f5bfae 100644 --- a/deploy/check-deploy-drift.mjs +++ b/deploy/check-deploy-drift.mjs @@ -1223,10 +1223,18 @@ export function checkLayout(inject = {}) { // ⇒ 把 modified 也读出来说清楚;**不改 ok**(脏树在本仓是常态, // 判红会造出总在亮的判据 —— 与本文件 ⑥ 的既定严重度一致:WARN,不参与退出码)。 const mod = (text.match(/vcs\.modified=(\w+)/) || [])[1] ?? ''; + // ★ ⑬′(pi 2026-09-25):判据文案必须写出**负向清单**(R\C —— 它**不**覆盖哪几类失败)。 + // 正向范围可以含糊,负向清单必须逐条列,否则读者会把"绿"读成"这份二进制没问题"。 + // 本判据的 R\C 就是下面这两类 —— 它们**只有编译/别的判据能判**: + // · 从脏树构建(revision 相等但含未提交代码)—— 本判据只**披露** modified,不判红 + // · 二进制内容与某次提交一致、但**部署后又被人手改过**(本判据只看内嵌 revision) + const negative = '本判据**不覆盖**: ①从脏树构建(含未提交代码,只披露不判红)' + + '②部署后被手工替换/修改(只看内嵌 revision)'; binRevNote = `与仓库 HEAD 一致(${got.slice(0, 8)})` + (mod === 'true' ? ',但 vcs.modified=true ⇒ **含未提交代码**,不对应任何已提交版本' - : mod === 'false' ? '' : '(未记录 vcs.modified ⇒ 是否含未提交代码未知)'); + : mod === 'false' ? '' : '(未记录 vcs.modified ⇒ 是否含未提交代码未知)') + + `;${negative}`; } else { binRevOk = false; binRevNote = `${BIN} 是 ${got.slice(0, 8)},仓库 HEAD 是 ${head.slice(0, 8)} —— ` @@ -1581,6 +1589,14 @@ export function layoutSelfCheck() { name: '★网关二进制:revision 与 HEAD 相同 ⇒ 必须绿', ok: seventh(binRevOf({ rev: 'c'.repeat(40) }, 'c'.repeat(40)))?.ok === true }, + { + // ★ ⑬′:绿的时候也必须写出**负向清单**(本判据不覆盖哪几类)。 + // 否则"绿"会被读成"这份二进制没问题",而它其实只答了一个问题: + // "内嵌 revision 是否等于 HEAD"。写成正向范围可以含糊,负向清单必须逐条列。 + name: '★网关二进制:绿时 note 必须写负向清单(不覆盖哪几类)', + ok: seventh(binRevOf({ rev: 'c'.repeat(40) }, 'c'.repeat(40)))?.ok === true + && /不覆盖/.test(seventh(binRevOf({ rev: 'c'.repeat(40) }, 'c'.repeat(40)))?.note ?? '') + }, { // ★ revision 相同 **但** modified=true ⇒ 仍是绿,**但 note 必须点明**"含未提交代码"。 // 这是本判据唯一的**假绿**形状(pi 2026-09-25 指出):树脏时 Go 照样写 diff --git a/deploy/redeploy-gateway.sh b/deploy/redeploy-gateway.sh index e2c7f21..cfaf65b 100755 --- a/deploy/redeploy-gateway.sh +++ b/deploy/redeploy-gateway.sh @@ -455,7 +455,10 @@ _headrev="$(git -C "$REPO" rev-parse HEAD 2>/dev/null)" if [ -z "$_binrev" ] || [ -z "$_headrev" ]; then warn "无法比对二进制版本(二进制 revision='${_binrev}',HEAD='${_headrev}')—— **不判**,不等于一致" elif [ "$_binrev" = "$_headrev" ]; then - ok "已装二进制 = 当前 HEAD(${_binrev%"${_binrev#????????}"})" + # ★ ⑬′:绿也要写**负向清单** —— 否则"绿"会被读成"这份二进制没问题"。 + # 本判据只答一个问题:"内嵌 revision 是否等于 HEAD";不覆盖: ①从脏树构建(下一条只披露) + # ②部署后被手工替换/修改(只看内嵌 revision)。 + ok "已装二进制 = 当前 HEAD(${_binrev%"${_binrev#????????}"})—— 不覆盖: 从脏树构建 / 部署后手工替换" else bad "已装二进制是 ${_binrev%"${_binrev#????????}"},HEAD 是 ${_headrev%"${_headrev#????????}"} —— 装的不是当前代码" CHECK_FAIL=$((CHECK_FAIL+1))