fix: 上游巡检收窄集合对比范围并支持已审查暂缓

Collections install only their declared children: the client copies each selected child path at the pinned ref. Yet `outdated` compared the whole upstream repository, so CLI sources, end-to-end tests and changesets forced repins. Compare the declared child paths plus root license/notice files instead; undeclared upstream skills are still reported as `new-skill`.

A pin kept on purpose after review was reported again every week, so the tracking issue could never close. A reviewed `upstream-health-hold.json` beside `entry.json` now reports its listed `upstream-path-change`/`outdated` findings as `held` (not actionable) while the pin and the installed-scope content at the reviewed upstream head are unchanged. Otherwise the findings return with an actionable `stale-hold`. Broken, unreachable, `new-skill` and `unpinned` findings cannot be held. CI tests require every hold to be well-formed and to match its entry's `source.ref`. A network error while checking a reviewed head stays `unreachable`.

`outdated` rows in the tracking issue now link to the GitHub compare view. The summary JSON reports the held count, and the closing comment mentions remaining holds. Both READMEs document the comparison scope, the hold format and the links.

Validation: 42 upstream-health, 10 collection-generator, 51 catalog-metadata and 19 i18n tests pass. Catalog metadata, i18n (0 errors, 106 existing warnings) and translation-freshness checks pass. actionlint and `git diff --check` are clean. A live run over 111 entries reports no broken or unknown entries, and humanlayer-skills is no longer `outdated`. A temporary geo-optimizer hold turned both of its findings into `held` with `actionable: false`; it is not committed.

Refs #213.
This commit is contained in:
2026-10-18 18:35:38 +08:00
parent a514b55b68
commit 10cb7656db
5 changed files with 442 additions and 33 deletions

View File

@@ -237,9 +237,23 @@ uv run scripts/catalog/check_upstream_health.py
集合检查需要 Git 和网络。可变来源集合会被报告并跳过,因为无法保证生成清单可复现。省略 `--check` 会进入写入模式;提交前应同时检查重新生成的子技能和对应 sidecar 事实。
上游健康检查只读,不改写条目;出现 `gone`、`bad-branch`、`bad-ref` 或 `bad-path` 时以非零状态退出。`unreachable` 表示网络错误,不等于确认失效。[上游健康工作流](.github/workflows/upstream-health.yml)每周运行一次,并维护唯一一个 `upstream-health` Issue;修复条目和更新 `source.ref` 仍需通过经过评审的 PR。
上游健康检查只读,不改写条目;出现 `gone`、`bad-branch`、`bad-ref` 或 `bad-path` 时以非零状态退出。`unreachable` 表示网络错误,不等于确认失效。[上游健康工作流](.github/workflows/upstream-health.yml)每周运行一次,并维护唯一一个 `upstream-health` Issue;对托管在 GitHub 的上游,Issue 中的 `outdated` 行会链接到 `<ref>...<head>` 对比页面。修复条目和更新 `source.ref` 仍需通过经过评审的 PR。
路径检查以实际安装的快照为准。只有分支头删除路径、固定版本仍可用时,报告 `upstream-path-change`。`outdated` 表示快照内容不同,不表示一定发布了新版本;文件树完全相同的提交不会触发更新提醒。单技能子目录指针比较 `source.path` 和仓库根的许可证、声明文件,不因无关的资讯数据或网站更新反复要求改动固定提交。`--summary-file <路径>` 将工作流使用的 `broken`、`actionable` 和 `unknown` 判定写入 JSON。未固定版本仍属于待处理事项;网络状态未知时保留跟踪 Issue。
路径检查以实际安装的快照为准。只有分支头删除路径、固定版本仍可用时,报告 `upstream-path-change`。`outdated` 表示安装内容不同,不表示一定发布了新版本;文件树完全相同的提交不会触发更新提醒。比较范围与安装时复制的内容一致:单技能子目录指针比较 `source.path`,集合比较已声明的子技能路径,两者都包含仓库根的 `LICENSE*`、`NOTICE*` 和 `COPYING*` 文件。因此,无关的资讯数据、网站、CLI 源码、测试或 changeset 更新不会反复要求改动固定提交;未声明的上游技能仍单独报告为 `new-skill`。位于仓库根目录的单技能、智能体和团队比较整个快照。`--summary-file <路径>` 将工作流使用的 `broken`、`actionable` 和 `unknown` 判定以及 `held` 发现数量写入 JSON。未固定版本仍属于待处理事项;网络状态未知时保留跟踪 Issue。
如果保留当前固定版本是经过审阅的决定,在 `entry.json` 旁添加 `<kind>/<id>/upstream-health-hold.json`:
```json
{
"statuses": ["upstream-path-change", "outdated"],
"ref": "<40 位十六进制的固定 source.ref>",
"head": "<40 位十六进制的已审阅上游提交>",
"reviewedAt": "YYYY-MM-DD",
"reason": "保留当前固定版本的原因。"
}
```
只有 `upstream-path-change` 和 `outdated` 可以暂缓;失效状态、`unreachable`、`new-skill` 和 `unpinned` 一律不能暂缓。暂缓记录仅在 `ref` 等于条目的 `source.ref`,且上游分支头与 `head` 在安装范围内的内容完全相同时生效。被暂缓的发现报告为 `held`,列入“Reviewed holds”区块,不属于待处理事项,因此跟踪 Issue 可以关闭;关闭评论会说明仍有多少条被暂缓的发现。如果固定版本已变更、上游在安装范围内有新改动、已审阅的提交已不存在、文件无效,或已不存在被暂缓的发现,暂缓记录即失效:原有发现(如有)重新出现,并附带一条待处理的 `stale-hold`,要求重新审阅或删除该记录。检查已审阅提交时遇到网络错误会报告为 `unreachable`,不视为暂缓失效。CI 测试要求每个暂缓文件格式正确,且其 `ref` 与条目的 `source.ref` 一致,因此更新固定版本时必须同步更新或删除对应的暂缓文件。暂缓记录用于留存经过审阅的决定,不能用来掩盖已失效的条目。
[校验工作流](.github/workflows/i18n-validate.yml)是 CI 行为的权威来源。它会检测相关路径,纯文档改动可能跳过目录校验。跳过后显示成功的任务,不代表 Markdown 链接或中英文文档已被检查;这些内容仍需单独审查。