fix(periodic-report): classify the coverage caveat as supporting coverage - #4830
huangruiteng wants to merge 2 commits into
Conversation
…rage A calendar report appends a bounded coverage caveat so the reader knows the window reads only this agent's still-readable records. It was labelled content_kind=risk, so the project-progress mapping itemized it under 风险与阻塞 and, when the window had no other risk, the compiled headline said "当前风险:本期证据覆盖范围". Add a typed coverage kind that belongs to supporting evidence, require supporting visibility for it, and build the caveat through one helper the report path calls. Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
Assert the caveat's classification and supporting visibility, that the adapter routes it to supporting evidence while a genuine risk still reaches 风险与阻塞, that the rendered report keeps it out of the risks block, and that a primary coverage item is refused by the material contract. Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
huangruiteng
left a comment
There was a problem hiding this comment.
Approval conclusion (author-owned PR; GitHub blocks formal self-approval)
精确 head:3ce392c841ba0b669ea178cee616404db23a3541(base main 2f47b765e)。无阻断发现,建议合并;合并决定留给 maintainer。
动机
按 problem_context:这一刀闭合 loopx-meta 泳道行 todo_cfab4f4acee4 记录的读者可见缺陷。日历周报会追加一条有界覆盖说明(「本期证据覆盖范围」),但该 fact 被标为 content_kind=risk,于是 project_progress 的映射把它逐条放进 风险与阻塞;当这一期没有别的风险时,编译出的头条直接写成 当前风险:本期证据覆盖范围。。base/head 用同一探针实测(base 通过 PYTHONPATH 指向 origin/main 2f47b765e):
base: caveat alone -> risks ['risk'] / supporting [] summary 当前风险:本期证据覆盖范围。
base: with a real risk -> risks ['risk','risk'] caveat inside the risks block: True
head: caveat alone -> risks [] / supporting ['coverage'] summary null
head: with a real risk -> risks ['risk'] / supporting ['coverage'] caveat inside the risks block: False
受影响的是读报告的人:一期没有真实阻塞的报告会被读成"有风险"。行里给出的验收是四条——归类为 coverage 或支撑证据、分区与可见性规则保持一致、真实 risk 事实不变、修法保持域中立——本 head 逐条满足,因此 problem_context 记为 goal_achieved。
改动思路
按 architecture_flow / repository_reuse / walkthroughs:
- 这条事实描述的是报告自身的证据边界,语义上属于支撑证据,不是项目风险。仓储已有的 supporting 类型只有
runtime与delivery_receipt,两者分别表示别的含义,把覆盖说明塞进任一个都是在类型字段里写一句假话;因此新增一个诚实的coverage类型,落在supporting_evidence。 - 词汇表是闭集:
adapters.py拥有类型集合与「supporting 类型必须visibility=supporting」这条规则,project_progress.py拥有类型→分区映射。两侧各加一行即可,无需新模块、新表、新 schema。 - 正向路径:
consume -> fact 列表 -> _cadence_coverage_fact -> project_progress 映射 -> supporting_evidence -> 文档与渲染产物。反向路径:声明coverage却给 primary 可见性,在材料契约处直接报visibility must be supporting for coverage content,不会静默降级,也不会为未知类型编造分区。
具体改动
按 changed_line_classification / symbol_map:生产改动 3 个文件(adapters.py +2/-1、project_progress.py +2/-1、pending_intent.py +25/-6),测试新增 1 个文件(+117/-0)。
关键代码讲解
loopx/capabilities/periodic_report/adapters.py:25_ITEM_CONTENT_KINDS/_SUPPORTING_CONTENT_KINDS——coverage同时进入闭集与 supporting 集,于是"覆盖说明当主内容"在类型层不可表达;其他类型一字未改。loopx/capabilities/periodic_report/project_progress.py:20_SECTION_BY_CONTENT_KIND/_SUPPORTING_CONTENT_KINDS——coverage映射到("supporting_evidence", 50)并计入 supporting,risk仍是("risks", 30),映射对闭集保持全函数。loopx/capabilities/periodic_report/pending_intent.py:658_cadence_coverage_fact—— 原先内联的字面量收成一个由出报路径(同文件 1213 行)调用的 helper,返回content_kind="coverage"+visibility="supporting",source_ref仍由窗口 id 派生,事实保持可归属。
对主干的风险
按 failure_analysis / walkthroughs.negative / validation_matrix / scope_fit:
- 最强回归场景:消费者自带一份旧的闭集(或字面匹配该 fact 的
content_kind),遇到coverage会拒绝。影响面是这一条 fact、它的分区与它所在的增量指纹;仓库内没有第二份闭集副本(rg content_kind只命中这两张表、fact 构造与展示层)。 - 增量指纹包含
content_kind,所以已存在的calendar_coverage事实身份会变一次、可能被重新发布一次——这是一次性影响,已在本评审与 PR 描述中写明,不做隐藏迁移。 - 真实 risk 事实不变:同一套断言同时覆盖"真实风险仍在 风险与阻塞"与"覆盖说明已不在该块内";288 条相邻 periodic-report 用例原样通过。
- 生效调用点:fact helper 在出报路径上被调用;词汇表与映射被每次材料构建读取(非仅测试可达的 helper)。
- 证据边界(诚实记录):适配器、文档构建器与 markdown 渲染器都是真件,但探针是用 projection 驱动的,没有重跑一次真实的定时出报投递;我也没有跑全量仓库套件。
我的整体评价
按 observable_semantics / code_volume / change_proportionality / default_off_isolation / authority_semantics:
- 三条对比行分别是"只有覆盖说明""覆盖说明 + 真实风险""primary 覆盖项":前两条展示分区与头条的变化,第三条展示类型规则真的生效(base 接受、head 拒绝)。判定码、投递路径、结算与模板完全未动,记为
intentional_change_validated。 - 规模与收益相称:两张三行表各加一项 + 一个 helper 取代内联字面量 + 4 条聚焦断言;无新模块、依赖、配置、状态或 CLI 面。维护成本只是"新增类型时要同时改两处表与映射"。
- 隔离性:无 opt-in/default-off 语义,
default_off_isolation记not_applicable;没有新增或修改任何被自动加载的指令面。 - authority:没有放宽任何权限——材料契约只增不减,仍会拒绝不合法材料,名称与范围一致。
- 类型/域中立/义务表述:判定基于闭集枚举而非子串或标题启发式;新增词与错误句只提 content kind 与 visibility,不含 goal/产品/benchmark 措辞;可见性规则由机器强制,docstring 只解释理由。
- 结论:无阻断性 finding。残余风险三条:(1) 增量指纹的一次性变化;(2) 闭集新增值对旧版本/外部副本的兼容边界;(3) 证据是有界的(真实适配器与渲染器 + 292 条 periodic-report 用例),未重跑真实定时投递与全量套件。
English verdict: APPROVE - reviewed head 3ce392c classifies the calendar coverage caveat as supporting coverage with a typed visibility rule, keeps genuine risks and every other report path unchanged, and is backed by 4 focused assertions, 292 periodic-report cases, a reproduced base/head reader-visible counterfactual, and an explicit statement of the incremental-fingerprint and old-vocabulary compatibility limits.
Merge-readiness recheck — exact head
|
动机
一份日历周报会追加一条有界覆盖说明(标题「本期证据覆盖范围」),让读者知道这一期只读了本 agent 仍可读的记录、空结果不等于没有进展。它此前被标为
content_kind=risk,于是project_progress的映射把它逐条放进 风险与阻塞;当这一期没有别的风险时,编译出的头条会直接写成:即把「我们只覆盖了这些证据」讲成「本期的主要风险」。base/head 实测(同一探针):
改动思路
这条事实描述的是报告自身的覆盖边界,属于支撑证据,不是项目风险。因此新增一个类型化的
coverage内容类型,并让它落在supporting_evidence;同时把它加入「必须 supporting 可见性」的集合,使「覆盖说明当作主内容」在类型层就不可表达。事实的构造收进一个由出报路径调用的 helper,分类与文案各有一处所有者。具体改动
loopx/capabilities/periodic_report/adapters.py:_ITEM_CONTENT_KINDS增加coverage,_SUPPORTING_CONTENT_KINDS增加coverage(于是visibility必须是supporting)。loopx/capabilities/periodic_report/project_progress.py:_SECTION_BY_CONTENT_KIND["coverage"] = ("supporting_evidence", 50),并加入同一 supporting 集合。loopx/capabilities/periodic_report/pending_intent.py:新增_cadence_coverage_fact(cadence_window),事实改为content_kind="coverage"+visibility="supporting",出报路径调用它(原先内联的字面量删除)。tests/capabilities/test_periodic_report_coverage_fact.py:4 条聚焦断言(分类、分区归属、渲染后不落在风险块、primary 覆盖项被拒)。风险边界
risk用法照旧合法)。content_kind,所以已存在的calendar_coverage事实身份会变一次,可能被增量层重新发布一次;这是预期的一次性影响。risk事实不变(测试同时断言两种事实的归位)。risk之外其他类型与分区的耦合没有被这次改动重新设计;本 PR 不做。验证
origin/main 2f47b765e上复现「risk/risks/头条风险」与「primary 覆盖项被接受」,head 上分别变为 coverage/supporting/无风险头条与拒绝。ruff check干净。