| 项 | 内容 |
|---|---|
| 状态 | 已采纳(Accepted) |
| 日期 | 2026-10-18(初版)· 2026-10-21(门包从 3 个扩到 5 个) |
| 背景 | 现有规则查的全是写法(用什么词、import 什么、goroutine 怎么起、回调怎么声明、errors 怎么包),没有一条查「本仓自己的门面有没有被自己改胖」。「保持门面,别再在本仓加逻辑」写在散文里——散文不是门禁。 |
| 决策 | 新增 harness-facade-stays-facade(error 级):门包只允许四种声明(类型别名、常量别名、单条上游转发函数、允许集合内的 import),判据走 go/ast(结构性问题逐行正则拿不到),执行体在 archcheck/facade.go,配置在 policy 的 facades 段。 |
| 后果 | 「加真逻辑」三者必居其一(要新类型、要多条语句、或要新依赖),所以规则不能被「顺手写两行」绕过去;转门面的调用面逐字兼容是硬要求(类型别名 = 编译期同一类型,宿主的 errors.As 判定链继续有效);当前例外数 = 0。 |
| 依据 | architecture-policy.yaml 的 facades 段 + archcheck/facade.go;能力边界见 docs/OAGENTKIT-OVERLAP.md。 |
> 一句话结论:门包只许转发、不许长胖——门面一旦自己长出实现,就成了与上游并存的第二份真相。
> ⚠️ 本文件正文原样搬自 README「门面包不可变(2026-10-18 补齐)」一节。其中出现的少数词面 > 是被引用的反例(首轮门禁抓出的硬编码字面量及其现行替代形态),不是本仓的用法。
门面包不可变(2026-10-18 补齐)
| 规则 | 级别 | 拦什么 |
|---|---|---|
harness-facade-stays-facade | error | dispatch/policy/reminder 三个门面包长出实现(声明新类型、给类型挂方法、函数体超过一条语句、调用非上游包、import 非允许依赖) |
为什么单独一条:现有七条规则查的全是写法(用什么词、import 什么、 goroutine 怎么起、回调怎么声明、errors 怎么包),没有一条查「本仓自己的门面有没有 被自己改胖」。docs/OAGENTKIT-OVERLAP.md 里那句 「保持门面,别再在本仓加逻辑」是散文——散文不是门禁。真有人往 policy/ 里加 一份实现,规则不会响,结果是与上游并存的第二份实现。
为什么用 AST 而不是正则:正则逐行看文本,判不出「一个函数体是不是只有一条 上游转发」,而这条纪律恰恰是结构性的。执行体在 archcheck/facade.go(go/ast), 不走 rules 段的正则表。门面包只允许四种声明:类型别名、常量别名、单条上游转发函数、 以及允许集合内的 import。「加真逻辑」三者必居其一(要新类型、要多条语句、或要新依赖), 所以规则不能被「顺手写两行」绕过去。五条判定路径均已反向验证(注入违规 → 退出码 1)。
例外必须显式登记(policy exceptions 段:rule + path + line 三元组精确豁免 + 必须写 until 与拆除条件)。当前例外数 = 0。
> 首轮门禁曾抓出 protocol/report_render.go 两处硬编码运维中文(AgentGuidance > 哨兵名 + 默认报告标题),均已清偿并有测试钉住:
| 原硬编码 | 现形态 | 宿主怎么用 |
|---|---|---|
AgentGuidance = "运维任务调度Agent" | Report.Guidance 结构化置位 + SetGuidanceAgentNames() 命名注册 | 装配期 protocol.SetGuidanceAgentNames("你的引导声位名"),或逐条报告置 Guidance: true(推荐) |
title = "运维诊断报告" | RenderOptions.DefaultTitle + 中性兜底「诊断报告」 | protocol.RenderViewWith(r, view, protocol.RenderOptions{}.WithTitle("你的品牌标题")) |
RenderView / Render 签名不变,老调用零漂移。