diff --git a/AGENTS.md b/AGENTS.md index 496b123f4..6f1d5ff3c 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -283,6 +283,65 @@ AGENTS.md 的「只跑受影响的包」指的是**用上面的路径过滤缩 - **不必为了合并去 rebase 其他在途分支** —— 队列自己会在当前 `main` 上重建,旧版「串行合并、合下一个前先 rebase 在途分支」那套编排已是历史。**但队列只拦得住文本冲突和 CI 看得见的破坏**:两个各自全绿的 PR 仍可能**语义冲突**(改了同一约定的两端;一边删掉了另一边刚开始用的导出)。所以动**共享面**(barrel/注册表/公共类型/跨包约定)时,合并前扫一眼在途 PR(`gh pr list`),有交叠就在 PR 正文里写清交叠点与取并集的办法(先例:PR #3458 对 #3456 同文件交叠的说明)。 - ruleset 的**具体配置**(谁可绕过、required checks 清单)本文不写 —— 从仓内读不到,别照抄任何推断。上面几条写的都是实测到的可观测行为。 +### ⚠️ Actions workflow 注册表:`list_workflows` 回答不了「本仓到底跑不跑 X」 + +这条已经造成过实际损害(objectui#6069):一个 agent 被要求**删掉**一条虚假的安全工具声明,却被一张 +建立在注册表读数上的卡**指去写上另一条同样虚假的安全工具声明**。那条虚假声明写在 #5408 的 dispatch +评论里(不在它的 diff 里),而 #5408 已随 PR #5963 合并。它没有酿成更大的事,只因为实施的 dev 拿 +`main` 核对了替换文本,而不是信任那张卡。 + +**注册表按「该 workflow 在任意 ref 上的第一次运行」建条目 —— 与默认分支无关,条目此后一直留着。** +不是 push 建的,也不是合进 `main` 建的。实测:四个样本、跨越七个月,注册表条目的 `created_at` 与该 +workflow **最早一次 run** 的 `created_at` **精确到秒相同**;push 被一个决定性的负例排除 —— +`pre-install-import-graph.yml` 推上分支后在**未注册状态下停了 7 分 45 秒**,直到 PR 打开、第一次 run +被调度的那一刻,条目才出现。 + +于是:**一个 workflow 文件只要在任何 PR 分支上跑过一次,就永久登记在册** —— 哪怕它从未进过 `main`, +哪怕那条分支早已废弃。2026-08-24 复测(`c677fe3b8`):在册的文件型条目 32 个(另有 4 个 `dynamic/*`), +`main` 上的 workflow 文件 26 个,**「在册但不在 `main`」6 个,「在 `main` 但不在册」0 个** —— 分歧是 +单向的。 + +**`state: "active"` 的意思是「没有被 disable」。它不是关于 `main` 的任何断言。** 这就是那个 false +friend 的全部:读到 `active` 就以为「这个扫描在本仓生效」,是把「曾经跑过一次」当成了「现在在跑」。 + +⛔ **别据此写一个「注册表 vs `main`」的交叉校验门禁 ——「应该在册」没有可靠定义。** 「在册但不在 +`main`」正是**在 PR 分支上跑过一个新 workflow 的正常结果**:每一个新增 workflow 的 PR 在合并前都会造 +出这样一条。活例子:`pre-install-import-graph.yml` 于 `21:41Z` 注册,本轮测量开始时它是「在册但不在 +`main`」的第 7 条;测量进行到一半,它随 PR #6159 于 `22:58Z` 合并进 `main`,这一条自己就消失了 —— 在 +那 77 分钟里开着的门禁,会红在一个完全健康的 PR 上。反方向「在 `main` 但不在册」则结构性地近乎恒空: +在 `main` 上的 workflow 会跑,而一跑就注册,只有「合并到首次运行」之间的时间窗能填充它,那是竞态不是 +缺陷。要把「废弃」和「在途」分开,只能靠一个分支存活性的猜测 —— 正是这张卡自己警告过的那种猜测。 + +⚠️ **删除方向本仓没有数据,别外推。** 「workflow 文件从默认分支被删掉之后,注册表条目会怎样」在本仓 +**从未发生过、也未经测试**:`git log origin/main --diff-filter=D --name-only -- '.github/workflows/*'` +返回**空**,而 `main` 历史上出现过的路径集合与今天在册的完全一致(复测:26 = 26)。所以上面那句「条 +目此后一直留着」只对**从未进过 `main`** 的文件成立 —— 它们根本没有「从默认分支删除」这个事件可供触 +发。⛔ 别把它读成关于删除行为的结论。 + +⚠️ **API 与人类看到的 Actions 标签页是否一致,本仓无法确定 —— 这是个未解问题,不是已答问题。** +`https://github.com/objectstack-ai/objectui/actions` 与 `api.github.com` 对这些会话都返回 **403**, +MCP 工具是唯一能到达的注册表视图,所以两者的差异既没被证实也没被排除。 + +#### ⭐ 通用规则:相信任何「不存在」之前,先把 `total_count` 和返回数组的长度比一下 + +**这不是 workflow 专属的 —— 它对每一个分页列表都成立。** `list_workflows` **忽略 `per_page`**,固定 +返回 30 条,同时在**同一个 JSON body 里**如实报告真实的 `total_count`。实测:`total_count: 36`,第 1 +页 30 条,第 2 页 6 条,`30 + 6 = 36` —— **并集**才是完整的。 + +只读数组、不读计数,一次截断的列表就变成一份「确信的缺席」。#6069 那张卡本身就是这么错的:它的整个 +论点正是「枚举会给出自信的错误答案」,而它自己只读了 36 条里的 30 条,把两个**已注册**的 workflow +写成了「注册表看不见它们」。**从一页被截断的结果里读出来的「没有」,根本不是一次读数。** + +#### 「本仓到底跑不跑 X?」—— 一条命令,不查注册表,不上 CI + +```bash +git cat-file -e origin/main:.github/workflows/X.yml # 退出 0 = 真的在 main 上,真的会跑 +git cat-file -e origin/main:.github/workflows/ci.yml # 阳性对照:必须解析成功 +``` + +**阳性对照不是可选项。** 没有它,一个打错的路径和一次真实的缺席给出完全相同的退出码,而你会把前者读成 +后者。 + ### ⛔ 受管面(governed surface):agent 起草,人类合并 维护者裁决(2026-08-18),**原文照录、不翻译** —— 提问明确点名了本仓: