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
18 changes: 18 additions & 0 deletions doc/architecture/SPEC/kb_service.md
Original file line number Diff line number Diff line change
Expand Up @@ -241,3 +241,21 @@ issue(同一报告只开一个),标签不存在时不带标签重试,绝
发布器记住每个 PR 已发布的最新修订,较旧的项不会覆盖较新的评论;服务在账本(全局 `findings:<PR>`,每个 PR 一条,与其涉及的仓库
范围无关)记下最新一条直至发布器确认送达,过期仍未送达的以相同内容与原修订号重新签发(与 PR 当前状态无关),因此旧发现永远
不会覆盖新的;发布器的修订记录原子写入,损坏时视为无记录。

## 2026-09-29 v8:来历检查与撤回
`audit`(原每日审计)改为每个调度 tick 运行,沿 main 的第一父链检查每个触碰 `knowledge/` 的提交:可信(账本记录的合并 SHA,或只携带
已记录 head 知识变化的双亲合并)、待回执(合并项仍在等待回执的 head,下一 tick 再看)、已处置(精确撤回已合并)、未知。
- 未知提交:暂停其涉及的仓库(触及仓库范围之外则全部暂停),记录 `unknown:<sha>`,告警,并把其内容作为新候选事件(`unrecorded`)
送回 intake;对受治理路径生成撤回 PR(恢复为第一父内容,由发布器构建、永不自动合并;`open_revert_pr` 属于总可执行项)。
路径之后又被修改(会冲突)或涉及非受治理路径时不生成撤回、转人工。无租约时记为 `revert_pending`,由下一次持有租约的检查补发。
- 撤回 PR 由人合并:只有 PR 合并的正是发布器构建的撤回提交、且合并提交在受治理路径上的变化恰为撤回路径并恢复到前像,才记录
`disposed:<sha>` 处置配对;不精确的撤回合并本身也是未知提交。关闭撤回 PR 则保持未处置并告警。
- 存在未处置的未知提交时不激活任何快照(G5 例外);可信列表(合并 SHA 与处置配对)写入签名控制记录的 `provenance`,发布器合并前
核对自当前激活快照以来 main 上每个受治理知识提交都可信(或是其自己的合并),否则不合并(瞬时,服务随即暂停并撤回)。
- 精确性按树条目(模式 + 内容)比较;手工撤回同样被识别:与某提交共享知识路径的未处置未知提交(传递闭包,先前的部分撤回也是其中之一)
构成一组;若该提交只改动这组涉及的路径,且之后这组触及的每条知识路径(不限受治理路径)都恢复到最早一个提交之前的树条目
(按祖先关系排序),则整组被处置。未知记录保存完整路径列表与全部知识路径的前像,冲突检查覆盖所有路径。已处置的未知提交只在其处置撤回属于被检查的历史时
才可信(main 回退到撤回之前会使其重新成为未知);只要涉及的任一仓库范围为私有上游,就不开公开撤回 PR、不生成候选事件,只转人工。结算撤回前先拉取,避免把新合并的撤回误判为未知。
- 激活本身(`activate()`,含 `kb activate`)核对从当前激活快照到目标 SHA 的每个知识提交都可信(首次激活除外),否则
`ActivationError`;调度器在激活前做同样的检查并只记录 `activation_blocked`。入 intake 的候选事件带上该提交的 diff。
- 尚未实现:`kb accept-unknown`(接受未知提交内容而不撤回),目前通过合并精确撤回(服务开出的或手工的)解除。
4 changes: 3 additions & 1 deletion doc/features/knowledge-service.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,9 @@ infermatrix-copilot kb rollback --to <sha> # 回指到较早的快照(下一
`main` 与 PR head 的合并树上运行本地门禁,通过才 `gh pr merge`(每仓库同时至多 1 个)→ 合并后激活新快照。
本地门禁拒绝的变更从不合并:上下文变化则在当前 main 上重建;服务自己的变更被质量门或本地门禁拒绝时,由生成器按
理由精炼后整体复检,至多 2 轮,仍失败则留在人工队列(不合并)。他人的知识 PR 每天检查一次:结果写在该 PR 上唯一一条
“知识质量门”评论里(原地更新),未通过则不合并,作者修改后次日复检。发版巡检在上游新 release 后运行
“知识质量门”评论里(原地更新),未通过则不合并,作者修改后次日复检。
有人绕过门禁直接合并/推送知识变更时,服务立即暂停该仓库、停止激活新快照、告警,并开出撤回 PR(不自动合并);
合并精确的撤回 PR 并 `kb resume` 后恢复,被撤回的内容会作为新候选重新过门禁。发版巡检在上游新 release 后运行
T1/T2/T3 与 purge,每个规则页一个变更集,全部经过质量门。

评审服务读取知识:将 `KNOWLEDGE_ROOT` 指向 `$KB_STATE_DIR/active`。
Expand Down
15 changes: 12 additions & 3 deletions src/infermatrix_copilot/kb_service/activate.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,11 +135,20 @@ def switch_active(state_dir: Path, snapshot: Path) -> None:
os.replace(tmp, link)


def activate(rt, sha: str, *, locked: bool = False) -> Path:
"""Build, verify and switch to the snapshot of knowledge at ``sha``."""
def activate(rt, sha: str, *, locked: bool = False, verify_provenance: bool = True) -> Path:
"""Build, verify and switch to the snapshot of knowledge at ``sha``. Every
knowledge commit from the active snapshot up to ``sha`` must have passed
the gate (design v8): nothing that bypassed it is ever served, whoever
asks (the scheduler, or `kb activate`)."""
if not locked:
with activation_lock(rt.state_dir):
return activate(rt, sha, locked=True)
return activate(rt, sha, locked=True, verify_provenance=verify_provenance)
if verify_provenance:
from .audit import provenance_problems

problems = provenance_problems(rt, sha)
if problems:
raise ActivationError("provenance: " + "; ".join(problems[:5]))
files = rt.knowledge.knowledge_files(sha)
extra = rt.knowledge.top_level_knowledge(sha)
snapshot = build_snapshot(rt.state_dir, sha, files, extra=extra)
Expand Down
Loading
Loading