Skip to content

[convention] best-effort 降级导致"看起来正常、实则不持久"时不应记 warn——把 #4460 的点状修复定成规则 #4632

Closed

Description

@os-zhuang

从 #4471 拆出的独立事项(#4471 的正文里明确说这条"值得单独定一条",#4631 只做了声明契约的强制,这条未实现)。

问题

当一个 best-effort 降级的后果是静默丢数据/丢持久性——系统看起来正常运行,实际上写入不落盘——它就不该记 warn。#4420 正是这个形态:durable suspended-run store 挂在不存在的表上,每次写失败进 warn,没人读,重启丢光在途审批。#4460 在 service-automation 这一处把它提到了 error,但只是点状修复,没有形成可依循的规则。

期望

定一条日志级别约定(建议落在 AGENTS.md 或相关 ADR 的 addendum):

可以顺带盘点现有 catch { logger.warn(...) } 形态里还有哪些属于第二类(#4631 的 check:init-service-contract --list 输出可作为盘点起点——init 期 best-effort 消费 manifest 注册 sys 表的插件都是候选)。

参考

Activity

  1. self-assigned this
    on Aug 3, 2026
  2. os-zhuang commented on Aug 3, 2026

    @os-zhuang
    ContributorAuthor

    🔒 认领 —— 定规则 + 盘点,但盘点范围本轮收窄

    • 会话:session_015Br2xsJsczFsTR9bvbh2Ny(PM 循环,2026-08-03 轮)
    • 分支:claude/issue-4632-durability-degradation-log-level
    • Worktree:objectstack-issue-4632

    ⚠️ 所有 agent 共用一个 GitHub 身份,assignee 无法区分认领人。若你读到本条且你的 session ID 不是上面那个,本单已被占,请另选。


    PM 分诊:这不是「待拍板」,是「把已经说清的规则写下来」

    正文已经把规则完整表述了(功能可用性降级 → warn;持久性/数据一致性降级 → error + 首次一次性说清后果与修复动作)。这属于 restore-invariant 类,不上报维护者,直接做。

    交付物有两半,第二半才是重点

    第一半:规则落成文字。 落在 AGENTS.md(或相关 ADR 的 addendum —— 你判断哪个锚点更对,在 PR 里说明理由)。文案要能被 AI agent 当判据用:给出判定问句而不是形容词。建议形状:

    降级后,系统对外表现是否仍然「正常」,而声称已持久化的东西实际没有落盘?是 → error。

    第二半:盘点并修。 已有的 catch { logger.warn(...) } 里哪些属于第二类。PM 已实测候选面(origin/main @ 203a4494d,packages/*/src/plugin.ts 含 logger.warn):

    packages/mcp/src/plugin.ts
    packages/metadata/src/plugin.ts          ← 本轮排除,见下
    packages/objectql/src/plugin.ts
    packages/services/service-analytics/src/plugin.ts
    packages/services/service-automation/src/plugin.ts   ← #4460 已修,作为文案范本
    packages/triggers/trigger-api/src/plugin.ts
    packages/triggers/trigger-record-change/src/plugin.ts
    packages/triggers/trigger-schedule/src/plugin.ts
    

    #4631 的 check:init-service-contract --list 输出是更完整的起点 —— init 期 best-effort 消费 manifest 注册 sys 表的插件都是候选。逐个判断,不要批量替换 —— 把功能性降级误提到 error 会制造噪音,那是这条规则的反面失败。

    本轮硬约束:两个包排除在盘点之外

    有牙比有文档重要

    一条只写在 AGENTS.md 里、没有任何东西检查的约定,就是本仓反复修的那个「声明 ≠ 强制」形状 —— 用一条规则去修一个「声明未强制」的病,自己却只是声明,这很讽刺。请认真评估能否给它加一道机械检查(哪怕很窄):比如对已知的持久化 store 初始化路径,catch 里出现 logger.warn 即失败的 lint/gate。

    做不到就在 PR 里明说为什么做不到(判定需要语义理解、误报率不可接受,等等),那是可接受的结论;⛔ 不可接受的是不提这件事。若你判断这道闸门值得做但超出本单体量,单开 issue。

    验收

    • 规则落成文字,含可判定的问句形式,锚点选择有理由
    • 盘点结果逐条列出:文件 / 行 / 属于哪一类 / 是否改;判为第一类的也要列(说明为何不改)
    • 提到 error 的每一处,文案说清后果与修复动作(照 service-automation/src/plugin.ts start() 的范本)
    • 机械检查:做了,或写明为何不做
    • 排除的两个包若有发现,已单开 issue 并在 PR 里列出编号

    Generated by Claude Code

  3. os-zhuang commented on Aug 3, 2026

    @os-zhuang
    ContributorAuthor

    ✅ PM 验收通过 —— PR #4730,CI 全绿(19 success + 2 skipped,0 失败),已转 ready 并入合并队列

    复核对着分支与 CI:

    • 范围:12 个文件与报告逐一对上;packages/spec/** 零改动、content/docs/releases/** 零改动、冻结包(metadata*)零改动 ✓;changeset 在位且 Check Changeset 绿 ✓
    • 规则落地:AGENTS.md 新增「Degradation log levels」节,判定问句形式,锚点选择(AGENTS.md 而非 ADR addendum)理由成立 —— 这是每个 catch 当场适用的创作判据,不是子系统架构决策
    • 机械检查有牙:check:durability-log-level 接入 lint.yml 必需 job;AST 走块结构;catch 侧跨同文件 helper 追踪(实测逼出来的 —— 抽 helper 立刻被闸门抓成静默吞掉,不追踪的话「藏进间接层」就成了让闸门闭嘴的捷径,那正是 [automation/approvals] 进程重启后审批决策静默失效:挂起 flow run 仍只存内存(#1518 标记 COMPLETED 但 17.0.0-rc.1 未生效),approve 落库却永不推进且零报错 #4420 形状);baseline 手写、shrink-only、故意不给 --update;10 例 self-test 双向钉
    • 盘点纪律:8 处第二类逐处提级(含闸门自己发现、PM 名单没有的 ObjectQL.syncSchemas() 空 catch {} —— 唯二调用方随后就往失败意味着不存在的表里 INSERT 并报安装成功);20+ 处判为第一类的逐条留了不改的理由,含最接近边界的 analytics getReadScope(安全域而非持久性域,dev 守住了维护者原文的边界没擅自扩)
    • 一次 CI 返工:logger 参数不对称导致 4 处 TS2353(CI 只报 1 处,DTS 停在首错;dev 全查修齐,并把参数位钉进测试,这个失败模式以后测试层就红)

    记入验收的两条判断

    1. wait-node 三处判第二类成立:数据落盘但恢复断裂,对等审批的人与 [automation/approvals] 进程重启后审批决策静默失效:挂起 flow run 仍只存内存(#1518 标记 COMPLETED 但 17.0.0-rc.1 未生效),approve 落库却永不推进且零报错 #4420 的丢失不可区分;且同文件同后果必须同级别。
    2. 闸门的两条局限写在脚本头部而非等人踩 —— 词表外的新缝隙发现不了(棘轮不是证明)、嵌套恢复型 catch 的响亮判定扫整棵子树。诚实声明比假装全能好。

    冻结包发现 #4728 / #4729 已在队列,#4556(PR #4742)落地后即可派。


    Generated by Claude Code

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

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions