模板 manifest 滞后:resource_key 已提交 main,CLI 渲染仍为旧模板 #1

Closed
opened 2026-09-24 22:38:17 +08:00 by xm · 6 comments
Owner

现象(2026-09-23/24)

  • yuvuResources main 已提交模板 resource_key 改动(commit 82e0dcc 等),但 CLI 拉取到的 manifest 渲染出的模板仍为旧版(0 个 resource_key)
  • 直接按模板应用必报 execution target lease does not match registered target;需手工在本地补 resource_key 才能运行
  • 模板文件与 manifest 发布链不同步,用户无法判断线上模板是否已含最新提交

期望

  1. manifest 发布与模板提交同步(提交即重建/发布 manifest),或提供显式发布步骤并文档化
  2. 提供 manifest 强制刷新/校验机制(如 yuvu resources refresh 或校验模板 hash)
  3. 模板渲染结果应包含来源 commit 信息,便于核对版本

影响

  • 模板直接应用必挂,用户侧需要 workaround(手工补字段),违背模板"开箱即用"预期
## 现象(2026-09-23/24) - yuvuResources main 已提交模板 resource_key 改动(commit 82e0dcc 等),但 CLI 拉取到的 manifest 渲染出的模板仍为旧版(0 个 resource_key) - 直接按模板应用必报 `execution target lease does not match registered target`;需手工在本地补 resource_key 才能运行 - 模板文件与 manifest 发布链不同步,用户无法判断线上模板是否已含最新提交 ## 期望 1. manifest 发布与模板提交同步(提交即重建/发布 manifest),或提供显式发布步骤并文档化 2. 提供 manifest 强制刷新/校验机制(如 `yuvu resources refresh` 或校验模板 hash) 3. 模板渲染结果应包含来源 commit 信息,便于核对版本 ## 影响 - 模板直接应用必挂,用户侧需要 workaround(手工补字段),违背模板"开箱即用"预期
Author
Owner

摘要

该问题根因不在 CLI 缓存逻辑,而在 yuvuResources 发布链路:manifest.json 是手工生成、手工提交的产物,模板提交(82e0dcc,2026-09-24 00:07)未同步重生成 manifest;CLI 的 refresh 只拉取已提交的单一 manifest 文件(含 SHA-256 与 revision),manifest 滞后则模板必然滞后,与缓存无关。事后 2188ec1(08:55 "Regenerate manifest after MAA-End template update")单独补提交才修复,佐证了"提交即滞后"的手工流程缺陷。CI 虽有 --check 门禁,但该 push 未被拦截(见下)。

【代码级根因】

  1. manifest 无自动发布:cmd/build-manifest/main.go:32-61 仅在手工运行 make manifest(Makefile:33-34)时生成;Makefile:39-40 的 check 含 go run ./cmd/build-manifest --check(main.go:48-56 比对不通过即 fatal "manifest.json is stale; run make manifest")。CI 为 .woodpecker.yml:1-8 仅跑 make check——是"检查"而非"重建",没有针对 templates/catalog 变更自动重生成 manifest 的步骤。
  2. --check 门禁被绕过/未生效:82e0dcc 提交时 .woodpecker.yml 已含 make check(git show 82e0dcc:.woodpecker.yml 确认),738aab4 即引入 --check,且 82e0dcc 未改动 manifest —— 按设计该 push 应 CI 失败。实际却合入 main,说明门禁(触发条件为 push 事件,.woodpecker.yml:1-2)当时未拦截或未被运行;这是流程缺口而非代码缺口,需人工核实该次 CI 记录。
  3. CLI 侧无自愈能力(符合预期但加剧体验):yuvu resources refresh 走 client.Refresh(yuvuCli 引用 yuvuResources/client:client/client.go:199-219)→ remoteManifest(client.go:414-430)仅 GET DefaultManifestURL(client.go:19,raw/branch/main/manifest.json)并按 manifest 内 SHA-256 校验下载模板(client.go:370-372、cache.go:24-30)。manifest 内容是什么,模板就是什么;refresh 不能修复滞后。缓存 fallback(client.go:214-218)只在远端拉取失败时用 last-known-good 并打印 warning,非本次原因。
  4. revision 无 commit 溯源:build-manifest/main.go:96-116 的 revision 是内容 SHA-256 拼接哈希,非 git commit;template render(internal/cli/template_commands.go:154-172)输出文档不含来源 revision,用户无从核对线上版本——与 issue"期望 3"一致。

【触发链路】

82e0dcc 改 templates/maaend/*.yaml 加 resource_key(git show 82e0dcc:仅 2 个模板文件,无 manifest)→ main 上 manifest 的 maaend/daily-full SHA-256 仍是旧值(对比 2188ec1 diff 中 0baad4b5…→f75e1222…)→ CLI refresh 拉到旧 manifest,按旧 SHA 取到旧模板(无 resource_key)→ 直接应用时 Core 报 execution target lease does not match registered target,用户需手工补字段。2188ec1(08:55)补生成 manifest 后 SHA 与 templates/ 一致(已用 shasum -a 256 核对 HEAD 上 f75e1222… 匹配),问题解除;说明整条链路无任何自动机制。

【影响面】

  • 所有依赖 maaend/* 模板的 CLI 用户在 00:07–08:55 窗口(及任何未来类似提交)内直接 template run/render 必得旧模板,apply 必挂。
  • 手工流程依赖人肉记忆"改模板要跑 make manifest"(README Publishing 章节虽有说明,但无强制)。
  • 用户无法从渲染结果判断模板版本(revision 不可见、非 commit)。

【修复建议】

  1. CI 门禁强化(最小改动):.woodpecker.yml 保持 make check(已含 --check,Makefile:39-40),但补充独立步骤确保 --check 的失败即中断合并(当前 push 触发若失败应已阻塞,需排查为何 82e0dcc 通过);并把 pre-push: diff-check check(Makefile:44)纳入工作流文档作为强制本地门槛。
  2. 模板路径变更自动重建:新增 Makefile target(如 manifest-auto)在 templates/、catalog/、runtime-profiles/ 有 diff 时执行 go run ./cmd/build-manifest(Makefile:33-34),并在 .woodpecker.yml push 步骤中先行自动重建、提交或失败——最稳妥是 CI 直接跑 make manifest && git diff --exit-code manifest.json,diff 非空即 fail,把"重建并检查差异"变成门禁本体。
  3. 显式发布步骤文档化:README 的 Publishing 段补充 make manifest && git commit manifest.json 为唯一发布入口,并在 commit message 模板/PR 检查清单中要求 manifest 与内容同 commit(对齐 2188ec1 的补救做法)。
  4. CLI 暴露 revision/来源(低成本):template render/show 在 stderr 输出 manifest.Revision 与 Source(数据已在 LoadResult/resourceStatusOutput,见 template_commands.go:17-31、client.go:41-46),或支持 --output json 附带 revision;yuvu resources status 已能打印 revision=(template_commands.go:93),补一句 README 指引即可。若需 commit 溯源,可在 build-manifest/main.go:114-120 的 manifest 增加 source_commit(由 CI 注入 git rev-parse HEAD,本地运行时留空并 warning)。

【验证建议】

  • 可复现检查(当前应为通过):cd yuvuResources && make check —— 若 build-manifest --check 报 stale 即复现滞后;再 grep -A2 '"maaend/daily-full"' manifest.json 与 shasum -a 256 templates/maaend/daily-full.yaml 比对 SHA。
  • 回归演练:在分支上仅改一个模板文件并 push,CI 应失败(--check 拦截);再 make manifest 提交后应通过。
  • CLI 侧:yuvu resources status 打印 revision=…,与仓库 manifest.json 的 revision 字段比对;yuvu template show maaend/daily-full 确认含 resource_key 后再 run。

【分析基线】

  • 仓库 HEAD:yuvuResources e2e2ace(2026-09-24 22:48),yuvuCli c4edf5e。
  • 已核对:82e0dcc 为 HEAD 祖先且未动 manifest;2188ec1 补生成;HEAD 上 --check 通过(实际运行 go run ./cmd/build-manifest --check,exit=0);82e0dcc 时 .woodpecker.yml/Makefile 已含门禁(git show 82e0dcc: 验证)。
  • 不确定项:82e0dcc 那一次 push 的 CI 实际执行结果无法从代码仓库确认,需查 Forgejo 流水线记录;source_commit 注入方案取决于 CI 环境变量可用性。
## 摘要 该问题根因不在 CLI 缓存逻辑,而在 yuvuResources 发布链路:manifest.json 是**手工生成、手工提交**的产物,模板提交(`82e0dcc`,2026-09-24 00:07)未同步重生成 manifest;CLI 的 `refresh` 只拉取**已提交的单一 manifest 文件**(含 SHA-256 与 revision),manifest 滞后则模板必然滞后,与缓存无关。事后 `2188ec1`(08:55 "Regenerate manifest after MAA-End template update")单独补提交才修复,佐证了"提交即滞后"的手工流程缺陷。CI 虽有 `--check` 门禁,但该 push 未被拦截(见下)。 ## 【代码级根因】 1. **manifest 无自动发布**:`cmd/build-manifest/main.go:32-61` 仅在手工运行 `make manifest`(`Makefile:33-34`)时生成;`Makefile:39-40` 的 `check` 含 `go run ./cmd/build-manifest --check`(`main.go:48-56` 比对不通过即 fatal "manifest.json is stale; run make manifest")。CI 为 `.woodpecker.yml:1-8` 仅跑 `make check`——是"检查"而非"重建",**没有针对 templates/catalog 变更自动重生成 manifest 的步骤**。 2. **`--check` 门禁被绕过/未生效**:`82e0dcc` 提交时 `.woodpecker.yml` 已含 `make check`(`git show 82e0dcc:.woodpecker.yml` 确认),`738aab4` 即引入 `--check`,且 `82e0dcc` 未改动 manifest —— 按设计该 push 应 CI 失败。实际却合入 main,说明门禁(触发条件为 `push` 事件,`.woodpecker.yml:1-2`)当时未拦截或未被运行;这是流程缺口而非代码缺口,需人工核实该次 CI 记录。 3. **CLI 侧无自愈能力(符合预期但加剧体验)**:`yuvu resources refresh` 走 `client.Refresh`(yuvuCli 引用 `yuvuResources/client`:`client/client.go:199-219`)→ `remoteManifest`(`client.go:414-430`)仅 GET `DefaultManifestURL`(`client.go:19`,raw/branch/main/manifest.json)并按 manifest 内 SHA-256 校验下载模板(`client.go:370-372`、`cache.go:24-30`)。**manifest 内容是什么,模板就是什么**;refresh 不能修复滞后。缓存 fallback(`client.go:214-218`)只在远端拉取失败时用 last-known-good 并打印 warning,非本次原因。 4. **revision 无 commit 溯源**:`build-manifest/main.go:96-116` 的 revision 是内容 SHA-256 拼接哈希,非 git commit;`template render`(`internal/cli/template_commands.go:154-172`)输出文档不含来源 revision,用户无从核对线上版本——与 issue"期望 3"一致。 ## 【触发链路】 `82e0dcc` 改 `templates/maaend/*.yaml` 加 `resource_key`(`git show 82e0dcc`:仅 2 个模板文件,无 manifest)→ main 上 manifest 的 `maaend/daily-full` SHA-256 仍是旧值(对比 `2188ec1` diff 中 `0baad4b5…→f75e1222…`)→ CLI `refresh` 拉到旧 manifest,按旧 SHA 取到**旧模板**(无 resource_key)→ 直接应用时 Core 报 `execution target lease does not match registered target`,用户需手工补字段。`2188ec1`(08:55)补生成 manifest 后 SHA 与 `templates/` 一致(已用 `shasum -a 256` 核对 HEAD 上 `f75e1222…` 匹配),问题解除;说明整条链路无任何自动机制。 ## 【影响面】 - 所有依赖 `maaend/*` 模板的 CLI 用户在 00:07–08:55 窗口(及任何未来类似提交)内直接 `template run/render` 必得旧模板,apply 必挂。 - 手工流程依赖人肉记忆"改模板要跑 `make manifest`"(README Publishing 章节虽有说明,但无强制)。 - 用户无法从渲染结果判断模板版本(revision 不可见、非 commit)。 ## 【修复建议】 1. **CI 门禁强化(最小改动)**:`.woodpecker.yml` 保持 `make check`(已含 `--check`,`Makefile:39-40`),但补充独立步骤确保 `--check` 的失败即中断合并(当前 `push` 触发若失败应已阻塞,需排查为何 82e0dcc 通过);并把 `pre-push: diff-check check`(`Makefile:44`)纳入工作流文档作为强制本地门槛。 2. **模板路径变更自动重建**:新增 Makefile target(如 `manifest-auto`)在 `templates/`、`catalog/`、`runtime-profiles/` 有 diff 时执行 `go run ./cmd/build-manifest`(`Makefile:33-34`),并在 `.woodpecker.yml` push 步骤中先行自动重建、提交或失败——最稳妥是 CI 直接跑 `make manifest && git diff --exit-code manifest.json`,diff 非空即 fail,把"重建并检查差异"变成门禁本体。 3. **显式发布步骤文档化**:README 的 Publishing 段补充 `make manifest && git commit manifest.json` 为唯一发布入口,并在 commit message 模板/PR 检查清单中要求 manifest 与内容同 commit(对齐 `2188ec1` 的补救做法)。 4. **CLI 暴露 revision/来源(低成本)**:`template render/show` 在 stderr 输出 `manifest.Revision` 与 `Source`(数据已在 `LoadResult`/`resourceStatusOutput`,见 `template_commands.go:17-31`、`client.go:41-46`),或支持 `--output json` 附带 revision;`yuvu resources status` 已能打印 `revision=`(`template_commands.go:93`),补一句 README 指引即可。若需 commit 溯源,可在 `build-manifest/main.go:114-120` 的 manifest 增加 `source_commit`(由 CI 注入 `git rev-parse HEAD`,本地运行时留空并 warning)。 ## 【验证建议】 - **可复现检查**(当前应为通过):`cd yuvuResources && make check` —— 若 `build-manifest --check` 报 stale 即复现滞后;再 `grep -A2 '"maaend/daily-full"' manifest.json` 与 `shasum -a 256 templates/maaend/daily-full.yaml` 比对 SHA。 - 回归演练:在分支上仅改一个模板文件并 push,CI 应失败(`--check` 拦截);再 `make manifest` 提交后应通过。 - CLI 侧:`yuvu resources status` 打印 `revision=…`,与仓库 `manifest.json` 的 `revision` 字段比对;`yuvu template show maaend/daily-full` 确认含 `resource_key` 后再 `run`。 ## 【分析基线】 - 仓库 HEAD:yuvuResources `e2e2ace`(2026-09-24 22:48),yuvuCli `c4edf5e`。 - 已核对:`82e0dcc` 为 HEAD 祖先且未动 manifest;`2188ec1` 补生成;HEAD 上 `--check` 通过(实际运行 `go run ./cmd/build-manifest --check`,exit=0);`82e0dcc` 时 `.woodpecker.yml`/`Makefile` 已含门禁(`git show 82e0dcc:` 验证)。 - 不确定项:82e0dcc 那一次 push 的 CI 实际执行结果无法从代码仓库确认,需查 Forgejo 流水线记录;`source_commit` 注入方案取决于 CI 环境变量可用性。
Author
Owner

修复计划定位

  • 全局顺序:#1 / 13(阶段一 · 止血)
  • 规模:S(约 0.5~1 天)
  • 前置依赖:无(建议最先做,它同时是后续模板类修复的发布安全前提)
  • 对应根因分析:issuecomment-27

全局序列(13 项)

  • 阶段一 止血:yuvuResources#1 → yuvuCore#10 → yuvuAdapter#4 → yuvuAdapter#5
  • 阶段二 可观测性:yuvuCore#8 → yuvuAdapter#6
  • 阶段三 可靠性核心:yuvuCore#9 → yuvuCore#6 → yuvuAdapter#7
  • 阶段四 部署一致性:yuvuCore#7 → yuvuNode#2
  • 阶段五 平台增强:yuvuCore#5 → yuvuAdapter#3

建议实施步骤(顺序)

  1. CI 门禁改为"重建+差异"本体:.woodpecker.yml 增加独立步骤 go run ./cmd/build-manifest && git diff --exit-code -- manifest.json(fail 即阻断),替代仅依赖 make check 内嵌 --check;保留 make check 作为兜底。
  2. 排查 82e0dcc 未被拦截的原因:查 Woodpecker 该次 push 的 pipeline 记录(是否未触发/被跳过/被忽略),恢复门禁有效性——这是本 issue 的核心未解点。
  3. 发布规程文档化:README Publishing 段明确"改 templates/、catalog/、runtime-profiles/ 必须同 commit 携带 manifest.json",并给出 make manifest && git commit manifest.json 作为唯一发布入口。
  4. CLI 可见性(低成本):template render/show 向 stderr 输出 revision/source(数据已具备);resources status 已打印 revision=,补 README 指引。
  5. (可选)source_commit 溯源:cmd/build-manifest 的 manifest 增加 source_commit(CI 注入 git rev-parse HEAD,本地留空+warning)。

依赖与编排

  • 无前置;完成后才建议对模板做功能性修改(yuvuCore#10、yuvuAdapter#5 的模板缓解)。
  • 提交顺序按 docs/QUALITY_GATE_CHECKLIST.md:行为变更(CI 配置)单独提交、文档单独提交。

验收标准

  • 故意只改一个模板文件、不跑 make manifest 的 push,CI 必须失败。
  • 修复后 manifest 与模板内容 SHA-256 一致(make check 通过)。
  • CLI 渲染输出可看到 manifest revision。

关联

  • 依赖方:yuvuCore#10、yuvuAdapter#5(模板改动需走修复后的发布链)。
  • 后续可选:把本项门禁模式复制到 yuvuAdapter 的 catalog/lint 链。
## 修复计划定位 - **全局顺序**:#1 / 13(阶段一 · 止血) - **规模**:S(约 0.5~1 天) - **前置依赖**:无(建议最先做,它同时是后续模板类修复的发布安全前提) - **对应根因分析**:[issuecomment-27](#issuecomment-27) **全局序列(13 项)** - 阶段一 止血:**yuvuResources#1** → yuvuCore#10 → yuvuAdapter#4 → yuvuAdapter#5 - 阶段二 可观测性:yuvuCore#8 → yuvuAdapter#6 - 阶段三 可靠性核心:yuvuCore#9 → yuvuCore#6 → yuvuAdapter#7 - 阶段四 部署一致性:yuvuCore#7 → yuvuNode#2 - 阶段五 平台增强:yuvuCore#5 → yuvuAdapter#3 ## 建议实施步骤(顺序) 1. **CI 门禁改为"重建+差异"本体**:`.woodpecker.yml` 增加独立步骤 `go run ./cmd/build-manifest && git diff --exit-code -- manifest.json`(fail 即阻断),替代仅依赖 `make check` 内嵌 `--check`;保留 `make check` 作为兜底。 2. **排查 82e0dcc 未被拦截的原因**:查 Woodpecker 该次 push 的 pipeline 记录(是否未触发/被跳过/被忽略),恢复门禁有效性——这是本 issue 的核心未解点。 3. **发布规程文档化**:README Publishing 段明确"改 `templates/`、`catalog/`、`runtime-profiles/` 必须同 commit 携带 `manifest.json`",并给出 `make manifest && git commit manifest.json` 作为唯一发布入口。 4. **CLI 可见性(低成本)**:`template render/show` 向 stderr 输出 `revision`/`source`(数据已具备);`resources status` 已打印 `revision=`,补 README 指引。 5. **(可选)`source_commit` 溯源**:`cmd/build-manifest` 的 manifest 增加 `source_commit`(CI 注入 `git rev-parse HEAD`,本地留空+warning)。 ## 依赖与编排 - 无前置;完成后才建议对模板做功能性修改(yuvuCore#10、yuvuAdapter#5 的模板缓解)。 - 提交顺序按 `docs/QUALITY_GATE_CHECKLIST.md`:行为变更(CI 配置)单独提交、文档单独提交。 ## 验收标准 - 故意只改一个模板文件、不跑 `make manifest` 的 push,CI 必须失败。 - 修复后 manifest 与模板内容 SHA-256 一致(`make check` 通过)。 - CLI 渲染输出可看到 manifest revision。 ## 关联 - 依赖方:yuvuCore#10、yuvuAdapter#5(模板改动需走修复后的发布链)。 - 后续可选:把本项门禁模式复制到 yuvuAdapter 的 catalog/lint 链。
Author
Owner

状态:修复已合并 ✅(仅记录,不触发关闭)

  • PR:xm/yuvuResources#2 — fast-forward(Forgejo Rebase),2026-09-26 00:48 → main 9c6cd28
  • 关键提交:
    • fffb41e CI 新增 manifest-guard(make manifest + git diff --exit-code -- manifest.json,漂移即失败)
    • 5e3b23c README 发布规程;975f47a 命令顺序修正(先 make manifest 再 make check)
    • 915f96f + 9c6cd28 门禁意图注释,并将 manifest-guard 前置到 check 之前(fail-fast,可读 diff 可见)
  • 验证:make check 全绿;build-manifest --check 通过;负向实测通过(改模板不重生成 manifest → 门禁非零退出;staged 陈旧 manifest → 非零退出)
  • 深审结论:manifest 确定性可独立复现;每个内容提交均携带 manifest 更新 → 逐提交 CI 绿

仍待处理(延后项):

  • 82e0dcc 那次 CI 记录排查(需 Woodpecker 平台权限)
  • CLI revision 来源显示(属 yuvuCli 改动)

(本评论为状态记录;关闭由 Hermes 处理。)

## 状态:修复已合并 ✅(仅记录,不触发关闭) - PR:xm/yuvuResources#2 — fast-forward(Forgejo Rebase),`2026-09-26 00:48` → main `9c6cd28` - 关键提交: - `fffb41e` CI 新增 `manifest-guard`(`make manifest` + `git diff --exit-code -- manifest.json`,漂移即失败) - `5e3b23c` README 发布规程;`975f47a` 命令顺序修正(先 `make manifest` 再 `make check`) - `915f96f` + `9c6cd28` 门禁意图注释,并将 manifest-guard 前置到 check 之前(fail-fast,可读 diff 可见) - 验证:`make check` 全绿;`build-manifest --check` 通过;负向实测通过(改模板不重生成 manifest → 门禁非零退出;staged 陈旧 manifest → 非零退出) - 深审结论:manifest 确定性可独立复现;每个内容提交均携带 manifest 更新 → 逐提交 CI 绿 仍待处理(延后项): - `82e0dcc` 那次 CI 记录排查(需 Woodpecker 平台权限) - CLI revision 来源显示(属 yuvuCli 改动) (本评论为状态记录;关闭由 Hermes 处理。)
Author
Owner

R4 复验报告(独立复验,不采信 agent 自述)——本轮 FAILED,issue 保持 open

轮次

  • task id 01a0dec7-fd6a-7b3a-be6f-65020ba769ad,实例 opencode-omo(01a05373-…),并发组 rg-rs-1
  • started 2026-09-27 01:34:03 CST → finished 02:04:06 CST,status=failed,error_code=execution_timeout,error_message=task execution timed out(execution_timeout_seconds=0 → 平台兜底 ≈30 分钟,实测 1803 s 被收割)
  • 落盘产物:DIAGNOSIS-R4.md(12036 B,02:02 落盘)。无 ROUND-NOTES-R4.md → 任务书要求的「ROUND-NOTES 首行 = skill 返回首行原文」证据缺失,本轮不能作为交付
  • commit / 推送:无。仓库 HEAD 仍为 98b605b;Forgejo refs/heads/main = 98b605b7ee4758f21c32934ff4c59ea820d5faf9(我自己 git ls-remote 核对)
  • 未推送的工作树:M README.md(+21 行,Provenance 段)+ 未跟踪 DIAGNOSIS-R4.md / TASKD-R4.md。按协作约定提交由 fixer 侧完成,本轮不代为推送

我独立复验的原始输出(独立副本 /home/zx/yuvu/workspaces/hermes/r4verify,HEAD=98b605b,go1.26.5,GOFLAGS=-mod=vendor GOTOOLCHAIN=local)

  1. manifest 重建一致性
$ make manifest
GOPROXY=off GOFLAGS=-mod=vendor go run ./cmd/build-manifest
make_exit=0
$ git status --porcelain          # (空)
$ git diff --exit-code -- manifest.json
GATE_EXIT=0
$ make check
… go vet ./… / go test ./… (client ok、internal/resources ok)/ check-resources: resource catalog and templates are valid / build-manifest --check
MAKE_CHECK_EXIT=0

→ 期望 1、3 在 HEAD 上确实成立,且可独立复现(生成器确定性)。

  1. 反向验证(我改模板字段、不重建 manifest)
$ git status --porcelain
 M templates/maa/daily.yaml
# (a) 裸 diff(不重建):盲的
$ git diff --exit-code -- manifest.json            → NAIVE_DIFF_EXIT=0
# (b) 门禁真身 = .woodpecker.yml manifest-guard 的两条命令
$ make manifest ; git diff --exit-code -- manifest.json
                                                   → GUARD_STEP_EXIT=1
   -  "revision": "68ab13cb…"  →  "revision": "c1157624…"
   -  "sha256": "ec73d339…"    →  "sha256": "23d118f8…"   (maa/daily)
# (c) 兜底(隔离运行,未先跑 guard)
$ make check                                       → MAKE_CHECK_ISOLATED_EXIT=2
   manifest.json is stale; run make manifest
# (d) 还原
$ git checkout -- . ; make manifest ; git diff --exit-code -- manifest.json → RESTORED_GATE_EXIT=0
  1. 82e0dcc「为何未被拦」的历史复跑(我按各提交的原始树重跑,非采信诊断)
49a3595 (09-23 20:34) EXIT=0   父提交,干净
82e0dcc (09-24 00:07) EXIT=1   manifest.json is stale; run make manifest
4887997 (09-24 08:55) EXIT=1
2188ec1 (09-24 08:55) EXIT=0   专门的 Regenerate 提交
.woodpecker.yml@82e0dcc steps = check, race(when: push/manual,无 paths 过滤)
Makefile@82e0dcc 的 check 已含 build-manifest --check

→ 与 DIAGNOSIS-R4.md §2b 结论一致:仓库侧当时就具备检出能力,漏拦在平台侧。这条我独立复跑得到相同结果,认可。

  1. file:line 抽验(我自己读源码核对)
  • client/client.go:457 = decoder.DisallowUnknownFields() ✓(「新增 manifest 字段会击穿存量 CLI」的论据成立)
  • README.md:23 ## Publishing、README.md:32-37 门禁与发布规程说明 ✓
  • cmd/build-manifest/main.go:33 = -check 开关、48-56 = stale 判定 + fatal 文案 ✓
  • .woodpecker.yml 步骤行号 4-10 / 12-15 / 17-20 ✓
  1. .woodpecker.yml 新增步骤原文
4 steps:
5   # Rebuilds the manifest first so drift fails fast with a readable diff; make check also validates via build-manifest --check.
6   manifest-guard:
7     image: docker.lib.zuixue.site/yuvu/images/yuvu-core-go-build:1.26-bookworm
8     commands:
9       - make manifest
10      - git diff --exit-code -- manifest.json

逻辑正确:先重建再比差异,并置于 check 之前(fail-fast、差异可读)。

我新发现的一条(比诊断更进一步,属假绿风险,必须记录)
manifest-guard(以及整个 .woodpecker.yml)目前永远不会被执行:xm/yuvuResources 在 Woodpecker 上根本没有注册。

GET https://woodpecker.nas.zuixue.site/api/repos?limit=100 → 11 个仓库,无 yuvuResources
  ['zx/gadget','zx/github-gadget','zx/matchsubtitles','zx/yuvu','zx/yuvuAdapter','zx/yuvuCli',
   'zx/yuvuCore','zx/yuvuImages','zx/yuvuNode','zx/yuvuNotify','zx/yuvuSkill']
GET /api/repos/lookup/zx/yuvuResources → 404 ;/api/repos/lookup/xm/yuvuResources → 404
Forgejo commit status(xm/yuvuResources):82e0dcc → statuses=0 ;9c6cd28 → 0 ;98b605b → 0
GET /api/v1/repos/xm/yuvuResources/hooks → []           # 无任何 webhook
branches/main → protected=false, enable_status_check=false, status_check_contexts=[]
git ls-remote https://forgejo.nas.zuixue.site/zx/yuvuResources.git → 需要凭据(该 CI 镜像仓不存在)
   对照 zx/yuvuCore.git → 匿名可读,main=6bbf576b98…

→ 「82e0dcc 为何没被拦」在现有平台上的答案是:该仓库没有任何 pipeline 在跑(不是被 skip、不是 paths 过滤、不是红而不卡)。这也意味着期望 1 的「提交即校验」在最后一环是空的:门禁存在,但无人执行。
限制:我只查了 woodpecker.nas.zuixue.site(技能记载的唯一 CI,admin=zx)。VM 上 woodpecker.zuixue.site 连不通(curl 000)。若另有 CI 实例,请以该实例记录为准。

门禁残余风险(供复验方判断)

  1. 裸 git diff --exit-code -- manifest.json 单独使用是盲的(实测 EXIT=0)。门禁正确性 100% 依赖「先 make manifest」。当前文件顺序正确,但后来者一旦把两条命令拆开/调序就会静默假绿——建议在步骤里加一条断言(重建后 manifest.json 与 HEAD 不一致即视为「漂移已发生」而直接失败)或注释写死「两条命令不可拆分」。
  2. 门禁校验的是「生成器输出 == 已提交文件」,不是「模板集合是否完整」。若生成器与 manifest 被同一提交一并改(例如生成器加入忽略规则),门禁无法发现。
  3. make check 作为兜底只在独立 checkout 下有效:同一 job 内若 manifest-guard 先跑过,manifest.json 已被重建,随后的 make check 必然绿(实测 guard 先跑后 make check EXIT=0)。CI 中两者是不同 step、共享同一 workspace,兜底的实际拦截力比看起来弱。

请复验方验证的清单

  1. 复核 82e0dcc 当时的 Woodpecker / AGit 事件记录是否存在。若确认无 pipeline → 本 issue 期望 2 的根因即「仓库未接入 CI」。
  2. 决定是否把 xm/yuvuResources 接入 CI(注册到 Woodpecker + 配置 forgejo.nas 镜像),或改用 pre-push / 服务端 hook 强制 make manifest;两者都不做时,期望 1 仍不成立。
  3. 复核我对 HEAD 98b605b 的复现(make manifest → git diff --exit-code -- manifest.json = 0;make check = 0)。
  4. 复核反向验证(改模板不重建 → 门禁 EXIT=1 / 兜底 EXIT=2)。
  5. 决定本轮未推送的 README.md Provenance 段是否由 fixer 侧补提(本轮因 30 分钟超时未提交)。
  6. yuvuCli 侧「渲染输出显示 revision + 来源 commit」仍是跨仓后续项。诊断 §4 的取舍(manifest 不嵌 source_commit)我认可:与 client/client.go:457 的严格解码、以及「重建+diff」确定性门禁都相容。

状态:issue 保持 open,label 未改(仍 needs-fix)。本轮判定未通过——轮次被超时收割、无 ROUND-NOTES、无 commit;期望 1/3 虽有历史提交在 HEAD 上成立,但执行链(CI 接入)缺失,属「有门禁、无执行」的假绿风险。
(本评论中所有凭据/令牌均已 [REDACTED]。)

## R4 复验报告(独立复验,不采信 agent 自述)——本轮 FAILED,issue 保持 open **轮次** - task id `01a0dec7-fd6a-7b3a-be6f-65020ba769ad`,实例 **opencode-omo**(`01a05373-…`),并发组 `rg-rs-1` - started `2026-09-27 01:34:03 CST` → finished `02:04:06 CST`,`status=failed`,`error_code=execution_timeout`,`error_message=task execution timed out`(`execution_timeout_seconds=0` → 平台兜底 ≈30 分钟,实测 1803 s 被收割) - 落盘产物:`DIAGNOSIS-R4.md`(12036 B,02:02 落盘)。**无 `ROUND-NOTES-R4.md`** → 任务书要求的「ROUND-NOTES 首行 = `skill` 返回首行原文」证据缺失,本轮不能作为交付 - **commit / 推送:无**。仓库 HEAD 仍为 `98b605b`;Forgejo `refs/heads/main` = `98b605b7ee4758f21c32934ff4c59ea820d5faf9`(我自己 `git ls-remote` 核对) - 未推送的工作树:`M README.md`(+21 行,Provenance 段)+ 未跟踪 `DIAGNOSIS-R4.md` / `TASKD-R4.md`。按协作约定提交由 fixer 侧完成,本轮不代为推送 **我独立复验的原始输出**(独立副本 `/home/zx/yuvu/workspaces/hermes/r4verify`,HEAD=98b605b,go1.26.5,`GOFLAGS=-mod=vendor GOTOOLCHAIN=local`) 1) manifest 重建一致性 ``` $ make manifest GOPROXY=off GOFLAGS=-mod=vendor go run ./cmd/build-manifest make_exit=0 $ git status --porcelain # (空) $ git diff --exit-code -- manifest.json GATE_EXIT=0 $ make check … go vet ./… / go test ./… (client ok、internal/resources ok)/ check-resources: resource catalog and templates are valid / build-manifest --check MAKE_CHECK_EXIT=0 ``` → 期望 1、3 在 HEAD 上确实成立,且可独立复现(生成器确定性)。 2) 反向验证(我改模板字段、**不**重建 manifest) ``` $ git status --porcelain M templates/maa/daily.yaml # (a) 裸 diff(不重建):盲的 $ git diff --exit-code -- manifest.json → NAIVE_DIFF_EXIT=0 # (b) 门禁真身 = .woodpecker.yml manifest-guard 的两条命令 $ make manifest ; git diff --exit-code -- manifest.json → GUARD_STEP_EXIT=1 - "revision": "68ab13cb…" → "revision": "c1157624…" - "sha256": "ec73d339…" → "sha256": "23d118f8…" (maa/daily) # (c) 兜底(隔离运行,未先跑 guard) $ make check → MAKE_CHECK_ISOLATED_EXIT=2 manifest.json is stale; run make manifest # (d) 还原 $ git checkout -- . ; make manifest ; git diff --exit-code -- manifest.json → RESTORED_GATE_EXIT=0 ``` 3) `82e0dcc`「为何未被拦」的历史复跑(我按各提交的原始树重跑,非采信诊断) ``` 49a3595 (09-23 20:34) EXIT=0 父提交,干净 82e0dcc (09-24 00:07) EXIT=1 manifest.json is stale; run make manifest 4887997 (09-24 08:55) EXIT=1 2188ec1 (09-24 08:55) EXIT=0 专门的 Regenerate 提交 .woodpecker.yml@82e0dcc steps = check, race(when: push/manual,无 paths 过滤) Makefile@82e0dcc 的 check 已含 build-manifest --check ``` → 与 `DIAGNOSIS-R4.md` §2b 结论一致:**仓库侧当时就具备检出能力**,漏拦在平台侧。这条我独立复跑得到相同结果,认可。 4) `file:line` 抽验(我自己读源码核对) - `client/client.go:457` = `decoder.DisallowUnknownFields()` ✓(「新增 manifest 字段会击穿存量 CLI」的论据成立) - `README.md:23 ## Publishing`、`README.md:32-37` 门禁与发布规程说明 ✓ - `cmd/build-manifest/main.go:33` = `-check` 开关、`48-56` = stale 判定 + fatal 文案 ✓ - `.woodpecker.yml` 步骤行号 4-10 / 12-15 / 17-20 ✓ 5) `.woodpecker.yml` 新增步骤原文 ```yaml 4 steps: 5 # Rebuilds the manifest first so drift fails fast with a readable diff; make check also validates via build-manifest --check. 6 manifest-guard: 7 image: docker.lib.zuixue.site/yuvu/images/yuvu-core-go-build:1.26-bookworm 8 commands: 9 - make manifest 10 - git diff --exit-code -- manifest.json ``` 逻辑正确:先重建再比差异,并置于 `check` 之前(fail-fast、差异可读)。 **我新发现的一条(比诊断更进一步,属假绿风险,必须记录)** `manifest-guard`(以及整个 `.woodpecker.yml`)目前**永远不会被执行**:`xm/yuvuResources` 在 Woodpecker 上根本没有注册。 ``` GET https://woodpecker.nas.zuixue.site/api/repos?limit=100 → 11 个仓库,无 yuvuResources ['zx/gadget','zx/github-gadget','zx/matchsubtitles','zx/yuvu','zx/yuvuAdapter','zx/yuvuCli', 'zx/yuvuCore','zx/yuvuImages','zx/yuvuNode','zx/yuvuNotify','zx/yuvuSkill'] GET /api/repos/lookup/zx/yuvuResources → 404 ;/api/repos/lookup/xm/yuvuResources → 404 Forgejo commit status(xm/yuvuResources):82e0dcc → statuses=0 ;9c6cd28 → 0 ;98b605b → 0 GET /api/v1/repos/xm/yuvuResources/hooks → [] # 无任何 webhook branches/main → protected=false, enable_status_check=false, status_check_contexts=[] git ls-remote https://forgejo.nas.zuixue.site/zx/yuvuResources.git → 需要凭据(该 CI 镜像仓不存在) 对照 zx/yuvuCore.git → 匿名可读,main=6bbf576b98… ``` → 「82e0dcc 为何没被拦」在现有平台上的答案是:**该仓库没有任何 pipeline 在跑**(不是被 skip、不是 paths 过滤、不是红而不卡)。这也意味着期望 1 的「提交即校验」在最后一环是空的:门禁存在,但无人执行。 限制:我只查了 `woodpecker.nas.zuixue.site`(技能记载的唯一 CI,admin=zx)。VM 上 `woodpecker.zuixue.site` 连不通(curl 000)。若另有 CI 实例,请以该实例记录为准。 **门禁残余风险(供复验方判断)** 1. 裸 `git diff --exit-code -- manifest.json` 单独使用是**盲的**(实测 EXIT=0)。门禁正确性 100% 依赖「先 `make manifest`」。当前文件顺序正确,但后来者一旦把两条命令拆开/调序就会静默假绿——建议在步骤里加一条断言(重建后 `manifest.json` 与 HEAD 不一致即视为「漂移已发生」而直接失败)或注释写死「两条命令不可拆分」。 2. 门禁校验的是「生成器输出 == 已提交文件」,**不是**「模板集合是否完整」。若生成器与 manifest 被同一提交一并改(例如生成器加入忽略规则),门禁无法发现。 3. `make check` 作为兜底只在**独立 checkout** 下有效:同一 job 内若 `manifest-guard` 先跑过,`manifest.json` 已被重建,随后的 `make check` 必然绿(实测 guard 先跑后 `make check` EXIT=0)。CI 中两者是不同 step、共享同一 workspace,兜底的实际拦截力比看起来弱。 **请复验方验证的清单** 1. 复核 `82e0dcc` 当时的 Woodpecker / AGit 事件记录是否存在。若确认无 pipeline → 本 issue 期望 2 的根因即「仓库未接入 CI」。 2. 决定是否把 `xm/yuvuResources` 接入 CI(注册到 Woodpecker + 配置 forgejo.nas 镜像),或改用 pre-push / 服务端 hook 强制 `make manifest`;两者都不做时,期望 1 仍不成立。 3. 复核我对 HEAD `98b605b` 的复现(`make manifest` → `git diff --exit-code -- manifest.json` = 0;`make check` = 0)。 4. 复核反向验证(改模板不重建 → 门禁 EXIT=1 / 兜底 EXIT=2)。 5. 决定本轮未推送的 `README.md` Provenance 段是否由 fixer 侧补提(本轮因 30 分钟超时未提交)。 6. yuvuCli 侧「渲染输出显示 `revision` + 来源 commit」仍是跨仓后续项。诊断 §4 的取舍(manifest 不嵌 `source_commit`)我认可:与 `client/client.go:457` 的严格解码、以及「重建+diff」确定性门禁都相容。 **状态**:issue 保持 **open**,label 未改(仍 `needs-fix`)。本轮判定**未通过**——轮次被超时收割、无 ROUND-NOTES、无 commit;期望 1/3 虽有历史提交在 HEAD 上成立,但执行链(CI 接入)缺失,属「有门禁、无执行」的假绿风险。 (本评论中所有凭据/令牌均已 [REDACTED]。)
Author
Owner

第 31 次独立复验(cron 巡检轮 · 2026-09-28 15:5x CST)—— ✅ 通过并已合并(issue 保持 open)

车道:fix/res-1-manifest-lag tip 945b70c(worktree wr-1,基于 main a3a9f5d)。
复验方式:另一会话(非修复方)在宿主 VM 138 上亲自跑门禁 + 亲自做反向验证,不采信轮次自述。

1. 门禁(分支上实跑,全部 exit 0)

go build ./...                        rc=0
go test -count=1 -p 2 ./...           rc=0   (client ok / internal/resources ok / 2 包无测试文件 / 0 FAIL)
make check                            rc=0   (vendor-check + quality + shell-check + test + validate + build-manifest --check)
make validate                         rc=0   → "resource catalog, templates, and manifest are valid"

2. 反向验证(3 处,全部「红得指向缺陷」→ 还原后 sha256 与 HEAD 逐位一致 → 复绿)

变异 结果
模板漂移(改 templates/smoke/ffmpeg.yaml 不改 manifest)+ 保留修复 make validate rc=2:manifest.json is stale; run make manifest
删掉 cmd/check-resources/main.go 里的 CheckManifest(".") 调用(漂移仍在) make validate rc=0 → 说明缺陷确实未被捕获,新增检查是唯一拦截点
单元层把 CheckManifest 的字节比较改成 && false(恒不触发) TestCheckManifestDetectsDrift FAIL:expected drift to be reported as stale, got <nil>

还原后:templates/smoke/ffmpeg.yaml / cmd/check-resources/main.go / internal/resources/manifest.go 三者 sha256 == sha256(git show HEAD:<file>),git status --porcelain 仅剩未跟踪的 ROUND-NOTES-R1.md/TASKD-R1.md,make check 复绿 rc=0。

3. 合并(串行、--no-ff、合并后门禁复跑全绿才 push)

  • yuvuResources main:a3a9f5d → a4369ca2b1178d252941c40ee33310ab274bf3d6(git merge --no-ff fix/res-1-manifest-lag,无冲突)
  • 合并后在 main 上复跑 go build ./... rc=0、go test -count=1 -p 2 ./... rc=0、make check rc=0 → 才 git push
  • git ls-remote origin refs/heads/main = a4369ca2…,与本地 HEAD 逐位一致;manifest.json 内容未变(revision 语义保持)
  • 车道 worktree wr-1 已 git worktree remove --force 清理,lanes.json 该车道置 merged

4. 请验证这几点(PM/用户侧)

  1. make validate 现在会在模板/目录与 manifest.json 漂移时直接失败 —— 请确认这符合你期望的「提交即拦」语义(此前 make validate 只做结构契约校验,漂移只在 make check 尾部的 build-manifest --check 里被发现)。
  2. 请确认 make check 里 validate 与 build-manifest --check 的重复执行(两次都做新鲜度比较)可以接受;若要精简,需同步改 .woodpecker.yml:5 的注释后才可移除其一。
  3. 请确认 CLI 侧可见性这条是否要在本项目内推进 —— 本轮未做:client 消费方(yuvuCli)显示 manifest revision 与来源 commit 属跨仓,本仓只在 README 记录了 revision 作为权威溯源键。

5. 未完成 / 后续精修(明确不声称已解决)

  • 核心未解点:xm/yuvuResources 未注册到 Woodpecker(/api/repos 无此仓)⇒ .woodpecker.yml 的 manifest-guard 从不执行。「82e0dcc 未被拦」= 根本没有 pipeline,而非被 skip。这是本 issue 原始症状的根因之一,需平台侧(Woodpecker 注册 + 分支保护)才能闭环,仓库内不可自证。
  • 已知小瑕疵(未改,为保 manifest 字节不变):internal/resources/manifest.go 沿旧生成器的扩展名处理,过滤用 strings.ToLower(ext)、TrimSuffix 也用同一小写 ext,对 .YAML/.JSON 大写扩展名会把扩展名留进 name;当前仓无此类文件。
  • 本轮未部署、未升级任何节点(用户指示「先不部署」)。

证据位置:分支 fix/res-1-manifest-lag(tip 945b70c)、合并点 a4369ca、ROUND-NOTES-R1.md(随分支入库)。

## 第 31 次独立复验(cron 巡检轮 · 2026-09-28 15:5x CST)—— ✅ 通过并已合并(issue 保持 open) **车道**:`fix/res-1-manifest-lag` tip `945b70c`(worktree `wr-1`,基于 main `a3a9f5d`)。 **复验方式**:另一会话(非修复方)在宿主 VM 138 上亲自跑门禁 + 亲自做反向验证,不采信轮次自述。 ### 1. 门禁(分支上实跑,全部 exit 0) ``` go build ./... rc=0 go test -count=1 -p 2 ./... rc=0 (client ok / internal/resources ok / 2 包无测试文件 / 0 FAIL) make check rc=0 (vendor-check + quality + shell-check + test + validate + build-manifest --check) make validate rc=0 → "resource catalog, templates, and manifest are valid" ``` ### 2. 反向验证(3 处,全部「红得指向缺陷」→ 还原后 sha256 与 HEAD 逐位一致 → 复绿) | 变异 | 结果 | |---|---| | 模板漂移(改 `templates/smoke/ffmpeg.yaml` 不改 manifest)+ 保留修复 | `make validate` **rc=2**:`manifest.json is stale; run make manifest` | | 删掉 `cmd/check-resources/main.go` 里的 `CheckManifest(".")` 调用(漂移仍在) | `make validate` **rc=0** → 说明缺陷确实未被捕获,新增检查是唯一拦截点 | | 单元层把 `CheckManifest` 的字节比较改成 `&& false`(恒不触发) | `TestCheckManifestDetectsDrift` **FAIL**:`expected drift to be reported as stale, got <nil>` | 还原后:`templates/smoke/ffmpeg.yaml` / `cmd/check-resources/main.go` / `internal/resources/manifest.go` 三者 `sha256 == sha256(git show HEAD:<file>)`,`git status --porcelain` 仅剩未跟踪的 `ROUND-NOTES-R1.md`/`TASKD-R1.md`,`make check` 复绿 rc=0。 ### 3. 合并(串行、--no-ff、合并后门禁复跑全绿才 push) - yuvuResources main:`a3a9f5d` → **`a4369ca2b1178d252941c40ee33310ab274bf3d6`**(`git merge --no-ff fix/res-1-manifest-lag`,**无冲突**) - 合并后在 main 上复跑 `go build ./...` rc=0、`go test -count=1 -p 2 ./...` rc=0、`make check` rc=0 → 才 `git push` - `git ls-remote origin refs/heads/main` = `a4369ca2…`,与本地 HEAD 逐位一致;`manifest.json` 内容未变(revision 语义保持) - 车道 worktree `wr-1` 已 `git worktree remove --force` 清理,`lanes.json` 该车道置 `merged` ### 4. 请验证这几点(PM/用户侧) 1. `make validate` 现在会在模板/目录与 `manifest.json` 漂移时直接失败 —— 请确认这符合你期望的「提交即拦」语义(此前 `make validate` 只做结构契约校验,漂移只在 `make check` 尾部的 `build-manifest --check` 里被发现)。 2. 请确认 `make check` 里 `validate` 与 `build-manifest --check` 的**重复执行**(两次都做新鲜度比较)可以接受;若要精简,需同步改 `.woodpecker.yml:5` 的注释后才可移除其一。 3. 请确认 **CLI 侧可见性**这条是否要在本项目内推进 —— 本轮**未做**:`client` 消费方(yuvuCli)显示 manifest `revision` 与来源 commit 属跨仓,本仓只在 README 记录了 `revision` 作为权威溯源键。 ### 5. 未完成 / 后续精修(明确不声称已解决) - **核心未解点**:`xm/yuvuResources` **未注册到 Woodpecker**(`/api/repos` 无此仓)⇒ `.woodpecker.yml` 的 `manifest-guard` **从不执行**。「82e0dcc 未被拦」= 根本没有 pipeline,而非被 skip。这是本 issue 原始症状的根因之一,需平台侧(Woodpecker 注册 + 分支保护)才能闭环,仓库内不可自证。 - 已知小瑕疵(**未改**,为保 manifest 字节不变):`internal/resources/manifest.go` 沿旧生成器的扩展名处理,过滤用 `strings.ToLower(ext)`、`TrimSuffix` 也用同一小写 `ext`,对 `.YAML`/`.JSON` 大写扩展名会把扩展名留进 name;当前仓无此类文件。 - 本轮**未部署、未升级任何节点**(用户指示「先不部署」)。 **证据位置**:分支 `fix/res-1-manifest-lag`(tip `945b70c`)、合并点 `a4369ca`、`ROUND-NOTES-R1.md`(随分支入库)。
Author
Owner

✅ 真机验证通过(测试方 · 2026-09-28 19:55 CST)— 关闭

验证方式说明:我本地 clone 落后于 main(不含修复),差点据此误判门禁失效;改走 Forgejo main 归档 /repos/xm/yuvuResources/archive/main.tar.gz 解出干净树(含 vendor)后跑门禁。

问题 1「make validate 是否『提交即拦』」—— 通过(正/负向都做了)

  • 干净树:make validate → resource catalog, templates, and manifest are valid(新消息已含 manifest)exit 0
  • 制造字节级漂移(往 templates/maa/daily.yaml 追加一行注释):manifest ec73d339… vs 文件 93b9ce4f…
    → make validate → manifest.json is stale; run make manifest + exit 1 ✓
  • 还原后 → 再次 valid ✓
  • 对照:make check 尾部的 build-manifest --check 同样报 stale(两条路径都拦得住)

问题 2「make check 里重复执行可接受吗」—— 可接受
validate 与 build-manifest --check 都是确定性、无副作用、亚秒级本地比较;多花一次 go run 换取「单独调用 validate 也能拦」,值得保留(.woodpecker.yml:5 注释无需改)。

问题 3「CLI 侧可见性」—— 本轮未做,作为后续项
仓库侧门禁已闭环;客户端(yuvuCli)显示 manifest revision 仍缺。若需要"客户端能看到用的哪版模板",可另开一条(按约定我不擅自新增 issue)。

关闭。

## ✅ 真机验证通过(测试方 · 2026-09-28 19:55 CST)— 关闭 **验证方式说明**:我本地 clone 落后于 main(不含修复),差点据此误判门禁失效;改走 Forgejo **main 归档** `/repos/xm/yuvuResources/archive/main.tar.gz` 解出干净树(含 vendor)后跑门禁。 **问题 1「`make validate` 是否『提交即拦』」—— 通过(正/负向都做了)** - 干净树:`make validate` → `resource catalog, templates, and manifest are valid`(**新消息已含 manifest**)exit 0 - 制造**字节级**漂移(往 `templates/maa/daily.yaml` 追加一行注释):manifest `ec73d339…` vs 文件 `93b9ce4f…` → `make validate` → **`manifest.json is stale; run make manifest`** + **exit 1** ✓ - 还原后 → 再次 valid ✓ - 对照:`make check` 尾部的 `build-manifest --check` 同样报 stale(两条路径都拦得住) **问题 2「`make check` 里重复执行可接受吗」—— 可接受** `validate` 与 `build-manifest --check` 都是确定性、无副作用、亚秒级本地比较;多花一次 `go run` 换取「单独调用 validate 也能拦」,值得保留(`.woodpecker.yml:5` 注释无需改)。 **问题 3「CLI 侧可见性」—— 本轮未做,作为后续项** 仓库侧门禁已闭环;客户端(yuvuCli)显示 manifest revision 仍缺。若需要"客户端能看到用的哪版模板",可另开一条(按约定我不擅自新增 issue)。 关闭。
xm closed this issue 2026-09-28 19:46:17 +08:00
Sign in to join this conversation.
No description provided.