Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/kb-gate/MANIFEST.sha256
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
5f6e269fbbb951f9a49c40474a3d71c556ac389f5ebd5545f0ac762f85361723 README.md
77d88b9671927ab95bc6ac9ed57aaa24226423e151843381c2a3fa90cd0cafde config.json
e8157d90270e9f437b364e9ef95bc0603c80c6421fa591953525387cc4f5d4e0 kb_gate.py
7ae4a3ff0372e54d4a9e5efc3887c2a00e9004b138215901d4c4d8c1ae5a1588 kb_gate.py
5743c4a6943c291073c5344d408eaec28e8bc7440a8ee113365588728ded5e8a l1.py
39f69aa816b83b673443601d38e57040521664c5aca407154ba40a8a35bc61d9 lifecycle.py
b0d0fab0210870f989da80f7ffba3978dbf723f4f087025524d1963c4081a009 ops.py
Expand Down
13 changes: 13 additions & 0 deletions .github/kb-gate/kb_gate.py
Original file line number Diff line number Diff line change
Expand Up @@ -544,6 +544,19 @@ def _human_approval_problems(ctx: Context, pr: dict, verdict: dict, head_sha: st
problems.append(f"review {review_id} is by someone the verdict does not name")
else:
approvers.add(login)
if approvers:
# a later review by the same person (changes requested, dismissal)
# withdraws the approval even though the bound review still reads APPROVED
latest: dict[str, dict] = {}
for review in ctx.github.get_all(f"/repos/{ctx.repository}/pulls/{number}/reviews"):
login = str((review.get("user") or {}).get("login") or "").lower()
if login and review.get("state") in ("APPROVED", "CHANGES_REQUESTED", "DISMISSED"):
latest[login] = review
for login in sorted(approvers):
review = latest.get(login) or {}
if review.get("state") != "APPROVED" or review.get("commit_id") != head_sha:
problems.append(f"{login}'s latest review no longer approves this head")
approvers.discard(login)
# knowledge maintainers = the CODEOWNERS of the gate itself. Governed pages
# deliberately have no code owners (that would force a review on every auto
# PR); paths outside the whitelist get GitHub's native code-owner review.
Expand Down
19 changes: 19 additions & 0 deletions doc/architecture/SPEC/kb_service.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,3 +108,22 @@ stdlib + PyYAML + `cryptography`(`kb` extra)+ `.adapters` + `.knowledge_serv
中断后再次执行会找到它而不会重复暂存)。只有重建**通过**质量门才取代旧 PR:旧变更集进入 `superseding`,`close` 项
过期即重发,直到观测到 PR 已关闭才记为 `superseded`(不计入被人工推翻的熔断);重建未通过、操作无法再应用或没有
可重放的操作 → `rebuild_failed` 并转人工,旧 PR 保持打开。其他失败(变更本身有问题)→ `gate_failed` 并转人工一次。

## 2026-09-28 外部知识 PR(来源④)与 human-approved 判定
`external.poll_external`(调度器按 intake 间隔、全局未暂停时调用,需持有租约)处理知识仓库中**非服务创建**、非 draft、
触碰 `knowledge/` 的打开 PR,每个 head 在每条路径(auto / human)上只评一次(auto 路径转人工的 head 在维护者审批后
无需新推送即可按 human 路径重新评判):
- `kb:human-approved` 且知识维护者(main 上 `.github/kb-gate/` 的 CODEOWNERS)对**当前 head** 的审批仍有效(同一人的
后续审阅覆盖之前的)→ 只在受治理页面上跑 L1(审批替代白名单与 L2,不替代其余 L1)→ 签发 `human-approved` 判定,
绑定这些审阅。
- 否则全部路径须为受治理页面 → 以**当前 main 加上 PR 改动**完整过质量门(L1、L2、一致性)→ 通过则签发 `auto` 判定。
PR 的前像必须等于 main(否则队列落地的改动与签名不同),不等则请作者 rebase。
与服务自己的 PR 一样,`auto` 判定要求当前通过的评审校准;否则记为 `calibration_required`,校准恢复后才重新评判
(期间不重复调用付费评审)。维护者审批读取全部分页的审阅,后续页上的撤回同样生效。
- 其余情况(跨多个仓库、白名单外路径未经审批、L1 失败、质量门未通过)转人工,每个 head 一次。
- 判定清单直接取自 git(`merge-base..head` 的完整原始 diff),覆盖白名单外路径;`context_base_sha` 为评判时的 main。
- 暂存为 `external` 变更集后走普通合并流程。作者推送新 head → `head_changed`(不转人工);上下文失效 → `stale_context`;
两者都在下次轮询时重新评判。签发后维护者撤回审批(最新审阅不再批准该 head)→ 转人工并下发 `pause`(出队 + draft);
在 pause 回执成功前保持原状态(继续占用队列名额),回执后才记为 `approval_withdrawn`,剩余审批不会让同一 head 重新暂存。外部 PR 没有操作列表,L1 发现的退役/删除规则写入 `retirements`/`purges`,合并后同样进入
退役账本(之后的发版巡检据此 purge)。作者关闭自己的 PR 不计入熔断。只触碰非受治理知识路径的 PR 归入 `general`(若其接收
人工 PR),否则归入第一个接收人工 PR 的仓库。
4 changes: 4 additions & 0 deletions doc/architecture/SPEC/knowledge_service.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,3 +70,7 @@ L1 的索引检查允许为目录中已存在但未列入索引的页面补链
只接受单侧改动的三方合并(更严格,不更宽松)。
- 测试:`test_kb_gate_verifier.py`(重放/过期/伪造、清单漏项、块表不全、混合路径与可执行位、暂停清单、
上下文失效、状态发布、人工审批撤销、merge group 逐段与前序同目录 PR、验证包新鲜与自包含、独立运行)。

## 2026-09-28 human-approved:最新审阅
验证器除核对签名绑定的审阅仍为 APPROVED 外,还读取该 PR 的全部审阅:每位被引用审阅者的**最新**审阅必须仍批准当前 head;
之后的 changes requested 或 dismiss 使该审批失效(即使被绑定的那条审阅仍显示 APPROVED)。
Loading
Loading