Skip to content

fix(periodic-report): classify the coverage caveat as supporting coverage - #4830

Open
huangruiteng wants to merge 2 commits into
mainfrom
codex/steward-coverage-fact-not-a-risk-20260921
Open

huangruiteng wants to merge 2 commits into
mainfrom
codex/steward-coverage-fact-not-a-risk-20260921

Conversation

@huangruiteng

Copy link
Copy Markdown
Collaborator

动机

一份日历周报会追加一条有界覆盖说明(标题「本期证据覆盖范围」),让读者知道这一期只读了本 agent 仍可读的记录、空结果不等于没有进展。它此前被标为 content_kind=risk,于是 project_progress 的映射把它逐条放进 风险与阻塞;当这一期没有别的风险时,编译出的头条会直接写成:

当前风险:本期证据覆盖范围。

即把「我们只覆盖了这些证据」讲成「本期的主要风险」。base/head 实测(同一探针):

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 内容类型,并让它落在 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 不做。

验证

  • 288 条 periodic-report 相邻用例 + 4 条新用例 = 292 passed(capabilities/extensions/presentation 三处 periodic_report 套件)。
  • base 反例:同一探针在 origin/main 2f47b765e 上复现「risk/risks/头条风险」与「primary 覆盖项被接受」,head 上分别变为 coverage/supporting/无风险头条与拒绝。
  • ruff check 干净。

…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 huangruiteng left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 类型只有 runtimedelivery_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)。

关键代码讲解

  1. loopx/capabilities/periodic_report/adapters.py:25 _ITEM_CONTENT_KINDS / _SUPPORTING_CONTENT_KINDS —— coverage 同时进入闭集与 supporting 集,于是"覆盖说明当主内容"在类型层不可表达;其他类型一字未改。
  2. loopx/capabilities/periodic_report/project_progress.py:20 _SECTION_BY_CONTENT_KIND / _SUPPORTING_CONTENT_KINDS —— coverage 映射到 ("supporting_evidence", 50) 并计入 supporting,risk 仍是 ("risks", 30),映射对闭集保持全函数。
  3. 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_isolationnot_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.

@huangruiteng

Copy link
Copy Markdown
Collaborator Author

Merge-readiness recheck — exact head 3ce392c841ba0b669ea178cee616404db23a3541

The existing detailed APPROVE conclusion is still valid for this exact head, and there are no unresolved review threads. This is a bounded readiness update, not a duplicate review.

loopx pr-review --check-merge-readiness 4830@3ce392c841ba0b669ea178cee616404db23a3541 currently returns ready=false because GitHub reports merge_state=BEHIND (merge_state_requires_update). Update/rebase the branch onto current main; the resulting head is a new exact head and must be reviewed and qualified again before merge.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant