diff --git a/deploy/check-deploy-drift.mjs b/deploy/check-deploy-drift.mjs index 1f5bfae..f0e0efc 100644 --- a/deploy/check-deploy-drift.mjs +++ b/deploy/check-deploy-drift.mjs @@ -1228,6 +1228,10 @@ export function checkLayout(inject = {}) { // 本判据的 R\C 就是下面这两类 —— 它们**只有编译/别的判据能判**: // · 从脏树构建(revision 相等但含未提交代码)—— 本判据只**披露** modified,不判红 // · 二进制内容与某次提交一致、但**部署后又被人手改过**(本判据只看内嵌 revision) + // ★ 注意本判据**读不到构建时的工作树**:它读的是二进制的内嵌位,而 `git status` + // 在这里问的是**此刻**的树 —— 两者可能不同(构建完又提交了 / 别人的改动进来了)。 + // 所以"这次构建带了哪些未提交文件"由**部署脚本**在构建步打印(那里才是同一时刻), + // 本判据只回答"含不含未提交代码"。别把这里补成 `git status` 然后当成构建清单。 const negative = '本判据**不覆盖**: ①从脏树构建(含未提交代码,只披露不判红)' + '②部署后被手工替换/修改(只看内嵌 revision)'; binRevNote = `与仓库 HEAD 一致(${got.slice(0, 8)})` diff --git a/deploy/redeploy-gateway.sh b/deploy/redeploy-gateway.sh index cfaf65b..132cf5b 100755 --- a/deploy/redeploy-gateway.sh +++ b/deploy/redeploy-gateway.sh @@ -245,6 +245,25 @@ STAGE="/tmp/agentmail-gateway-build-$TS" # 改标准目录部署是为了"运行时不再依赖源码目录";没有 -trimpath 时这条只做到一半: # 依赖确实没了,但**源仓库位置还印在产物上**。判据在 check-deploy-drift(标准目录 ⑤)。 run "rm -f '$STAGE'" +# ★ 构建时的**工作树清单** —— 比"一个 modified 位"可归因(pi 2026-09-25 提出,我实测确认)。 +# +# 为什么不是一个 bool:`go build` 在脏树上**照样**写 `vcs.revision=`,只额外记 +# `vcs.modified=true` ⇒ 那个位只说"含未提交代码",**不说是谁的什么**。而本仓是 +# **多 agent 并发**:那些未提交改动通常**不是部署者的**,是别人的在飞工作。 +# ⇒ 这不是理论:本仓为此**已经付过代价**(check-deploy-drift 判据⑥ 注释里那笔账)—— +# 2026-09-14 `pool.mjs` 一行未提交的 `let missingSessionCount = 0;` 被"从脏工作区做的" +# 快照原样带进生产,而当时判据① 报的是「逐字节一致」。 +# ⇒ 处置取**第三种**:既不判红(脏树在本仓是常态,判红=总在亮),也不只留一个不可归因的位, +# 而是**把"这次构建带着哪些未提交文件"打印出来**。 +# ★ 判红与否两种选择都改变不了这个事实:**清单有名字,bool 没有** —— +# 出了事能直接看出"带进去的是谁的那两个文件",而不是只能回答"当时是脏的"。 +# 位置贴紧构建步:上面那句 `go build` 读的就是此刻的工作树。 +if [ -n "$(git -C "$REPO" status --porcelain 2>/dev/null)" ]; then + warn "工作树不干净 —— 下面这份未提交清单会被**编进这次构建**(多 agent 并发时通常不是你的改动):" + git -C "$REPO" status --porcelain 2>/dev/null | sed 's/^/ /' +else + ok "工作树干净(构建件不含未提交代码)" +fi if [ "$DRY_RUN" = 1 ]; then printf ' [dry-run] (cd server && go build -trimpath -o %s ./cmd/server)\n' "$STAGE" else