Skip to content

[metadata-protocol] seed-loader:roll-up summary 重算耗尽重试后只记 warn 且不计数 —— 落盘的汇总值与事实不符,seed 仍报 success: true #4998

Closed

Description

@xuyushun441-sys

发现于 #4729(seed-loader 的日志级别盘点)。本条不在 #4729 的判据(「计数为错、日志为 warn」)内 —— 它压根不计数 —— 所以只记录,不在那个 PR 里动。

现象

packages/metadata-protocol/src/seed-loader.ts 的 writeRecoveringSummary():

private async writeRecoveringSummary(fn: () => Promise<T>): Promise<T> {
  try {
    return await fn();
  } catch (e: any) {
    if (e?.code === 'ERR_SUMMARY_RECOMPUTE') {
      this.logger.warn(
        '[SeedLoader] roll-up summary recompute failed after retries; records were written (summary values may be stale)',
        { failures: Array.isArray(e.failures) ? e.failures.length : undefined },
      );
      return e.written as T;
    }
    throw e;
  }
}

行本身的判断是对的(framework#3147:记录确实写进去了,不能重写,否则重复)。有疑问的是后果的等级:roll-up summary 是一列已持久化的派生值,重算耗尽重试后,库里存着的汇总数与被汇总的明细不一致,而:

  • 这次 seed 不计一条错(errored 不动、allErrors 不动),result.success 仍是 true;
  • 控制台上唯一的痕迹是一行 warn。

判定问句(#4632 / AGENTS.md「Degradation log levels」)

降级之后系统对外是否仍然「正常」,而某个声称已持久化的东西实际不对?

我的读法是 是:一切看起来干净(success: true,行数全对),而一列已落盘的汇总值是错的,并且不会自己修 —— 直到下一次触发该 summary 重算的写入才可能纠正,而 seed 之后未必还有这种写入。这正是 #4420 的形态(那次是 in-flight approvals,这次是汇总列)。

反方也有分量,所以我不想擅自改:

  1. 记录本身是真的落盘了,和 [automation/approvals] 进程重启后审批决策静默失效:挂起 flow run 仍只存内存(#1518 标记 COMPLETED 但 17.0.0-rc.1 未生效),approve 落库却永不推进且零报错 #4420「写入完全没发生」不同;
  2. 提到 error 会让一次除汇总外全部成功的 seed 打出 error 行,可能属于 AGENTS.md 明确警告的「过度适用」(把人训练成跳过 error);
  3. 也可以不动日志级别,而是把它计入结果(新增一个 summariesStale 计数或一条 ReferenceResolutionError),让结果对象诚实,日志维持 warn。

期望(需要维护者拍板)

在下面三条里选一条并落地 + 加测试:

我的倾向是 A + B:后果确实是「已落盘的数据不对」,而且计数与日志级别应当一致(#4729 的同一条论点)。但这会改变一次成功 seed 的控制台输出,属于产品口径,不该由实现方顺手决定。

未认领。

Activity

  1. added
    needs-user-decisionBlocked on a maintainer decision — do not dispatch; decision cards only, never on a PR
    bugSomething isn't working
    pm:queueReady for the PM dispatch loop
    and removed
    needs-user-decisionBlocked on a maintainer decision — do not dispatch; decision cards only, never on a PR
    on Aug 3, 2026
  2. claude commented on Aug 4, 2026

    @claude
    Contributor

    维护者已裁:A + B(2026-08-04,经主 backlog PM 呈报后照准)

    • A:提到 error,文案带后果(该对象 roll-up summary 列为陈旧值、明细与汇总不一致而 seed 报 success)与修复动作;
    • B:计入结果对象(如 summariesStale 计数),调用方可编程发现;success 语义是否翻转按 B 的实现证据定 —— 汇总列错数据不算「成功得干净」。

    摘 needs-user-decision,回队,本轮即派。


    Generated by Claude Code

  3. claude commented on Aug 4, 2026

    @claude
    Contributor

    🔒 认领:PM 循环第 7 轮(维护者裁决落地批)
    会话:session_01NrmBxj8rK2uGCnh9aipjwX(账号 xuyushun441-sys)
    分支:claude/issue-4998-seed-summary-stale-loud
    Worktree:objectstack-issue-4998
    域:domain:engine
    文件面:packages/metadata-protocol/src/seed-loader.ts(writeRecoveringSummary)及同目录测试

    ⛔ 硬约束:spec/** 及生成物零改动;protocol.ts 零改动;releases/ 零触碰。
    全局在飞不相交已核:与 #5025(sys-metadata-repository.ts + 基线)、#4762(packages/lint)、本批其余两单文件面均不交。


    Generated by Claude Code

  4. claude commented on Aug 4, 2026

    @claude
    Contributor

    PM 中间处置:子问题即裁,B 半边的 spec 例外呈维护者

    1. success 不翻转 —— 确认,按 dev 证据即裁(维护者原裁决明言此项交实现证据):三个消费方证据决定性 —— wire 返回结构上无法解释 false 的原因、boot banner 会打出「true and useless」行、marketplace install 会把「行全部落库」的一次安装判失败,直接违反 framework#3147 的「records WERE written」不变量。success 语义 = 行是否落库;新计数字段承载陈旧信号。
    2. B 半边(机器可读计数)撞 spec 冻结:结果类型为 spec 定义(seed-loader.zod.ts),非包内。dev 的方案 A(为本单开一个窄例外:summariesStale + totalSummariesStale,逐字镜像 seed-loader: a dropped reference FIELD is invisible in the summary — totalErrored counts dropped records only, so the boot banner reads clean #3932 referencesDropped 先例,纯增量 + default(0),~10 行手写 + 两个生成物重生)已呈维护者拍板;方案 C(包内私加字段、契约分叉)按 PD#12 弃。
    3. 拍板前本单 PARK;half A 的实施笔记(含 durability 门禁需先具名提取 fn() 才能真保护的关键发现)已在停工报告里,解锁即续。

    Generated by Claude Code

  5. claude commented on Aug 4, 2026

    @claude
    Contributor

    维护者已裁(2026-08-04):批准本单的 spec 窄例外,取 dev 方案 A

    原 dev agent 带上下文续做。⚠️ 入队前按纪律 A 处理 spec 生成物(在飞 #5042/#5043/#5012 同在动 spec)。


    Generated by Claude Code

  6. claude commented on Aug 4, 2026

    @claude
    Contributor

    ✅ 验收通过 —— PR #5062(draft,落地按同文件串行排程,见下)

    对照实际 diff 复核(9 文件,+676/-34;spec 改动恰在授权例外内:seed-loader.zod.ts + authorable-surface.json + 生成 docs 页各一;⛔ protocol.ts / releases 零触碰,逐一核实):

    1. A + B 全落地:error 级文案(点名对象与陈旧列、后果、双修复动作、cause 结构化附队);summariesStale / totalSummariesStale 逐字镜像 seed-loader: a dropped reference FIELD is invisible in the summary — totalErrored counts dropped records only, so the boot banner reads clean #3932 先例,buildResult 恒填充,success 不翻转(已确认子裁定);框架bug(objectql): 汇总重算失败仅 warn——子记录批量插入报成功,父 summary 静默过期且无重试 #3147 的「行已写入不重写」原样。
    2. 申报越界:采纳。dev 实测证明「登记进门禁」是假保护(门禁豁免任何含 throw 的 catch,本接缝条件性重抛 → warn 回退带着登记照样过 CI),收紧为仅无条件重抛可豁免 —— 这是「门禁必须真的检查它声称检查的东西」的 restore-invariant 类,免上交;全仓测量 11 接缝零判定变化、自测 10→13 例、变异 pin 证明门禁现在真的会红,且带独立 changeset。比照单登记更对。
    3. 双向变异 pin:实现回退 → 4 测试红;同回退 → 门禁 exit 1(打印精确接缝行号);恢复全绿。
    4. 生成物纪律 A 有终局断言:os-regen 全路径 checkout + 整体重生成后,git diff origin/main --stat 恰为本分支两行增量,且 收紧 theme 全部/chart 五个站点的未知键,并按门测量把 chart 两个站点判为 no gate(#4001 批 15) #5043 的兄弟条目(ui/Chart 44、ui/Theme 12)验证存活。
    5. 28 门禁 27 过(唯一红为 Release process: prevent frontend (objectui) changesets being missed when the console pin lags #3340 既有的 objectui pin,与本分支无关);spec 7613 全过。

    落地排程(同文件串行):队列中的 #5025 与本 PR 都改 check-durability-degradation-log-level.mjs —— 本 PR 等 #5025 落地后并 origin/main(冲突就地解决:保留收紧后的门禁逻辑 + #5025 的 dropPromotedDraftRow 登记两者)、重跑该门禁与自测,绿后入队。


    Generated by Claude Code

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

Metadata

Metadata

Labels

bugSomething isn't workingpm:dispatchedDispatched to a dev agent by /pm-dispatchpm:queueReady for the PM dispatch loop

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions