fix(authority): recover canonical Todo projection during refresh - #4961
Conversation
Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
huangruiteng
left a comment
There was a problem hiding this comment.
Request changes conclusion (author-owned PR; GitHub blocks formal self-review)
Reviewed exact head: fa245069c60cb10e95a615d0e7a9543e0e5faece
动机
已提升到 canonical Todo authority 的 Goal,普通 refresh-state 或同一 Turn 重放可能在业务提交成功后仍留下缺失/过期的 Markdown Todo 区。继续从 Markdown 诊断缺口会误报待办扩展,或隐藏可执行前沿。该 PR 要让刷新顺手恢复显示,而不重做 Todo 写入、quota 结算或历史事件。
改动思路
方案复用现有 provider 快照、journal-backed projection outbox 和机器区渲染,不增加第二个队列/ACK。规划阶段携带完整 canonical 快照,持久发布前重新确认 provider revision;TS 决定 pinned/latest 与三次尝试上限,Python 保留锁、渲染和发布。这个归属方向合理,pinned 不追新 head,失败保持 pending。
具体改动
关键代码讲解
refresh_state_run在已提交刷新和 replay 返回处调用recover_refresh_todo_projection,并将 canonical Todo 字段传给缺口诊断;空 canonical 分组不会退回旧 Markdown。project_current_canonical_todos可复用规划快照渲染,但仍通过新的 provider readback 确认是否需要重试;旧业务提交不重放。confirmProjectionReadback给出finish/retry的 typed 决策;文档和 268 行 refresh 回归测试覆盖恢复、失败与重叠。
本地聚焦验证:41 个 Python 测试、7 个 TS 测试及 git diff --check 通过。没有在这些路径上复现新的代码缺陷。
对主干的风险
当前 exact head 的必需集成检查仍为红:Frontstage Pages 的 showcase catalog smoke 因 README 语句断言失败;此后 main 的 #4969 已修该 smoke,说明本分支需要吸收主干后重测。minimum-Node 检查另有 4 个 SQLite deferred-lease 用例失败(不在本 PR 改动路径),merge-gate 也失败。不能把这些失败直接归因于本补丁,但也不能把局部通过当作可合并证据。请先同步当前 main,对新 exact head 重跑必需检查;若 minimum-Node 仍红,定位并修复/隔离该 lane 后再复审。保持本 PR 的刷新、重放和 revision-overlap 回归覆盖。
我的整体评价
实现边界和已有局部证据支持这个恢复方向;本次结论仅因当前 head 的必需集成验证未闭合而请求修改,不要求增加新的恢复机制。相邻重构审视:现有 outbox 已足够,无需再抽象。新 head 与检查读回后可复审。
English verdict: REQUEST_CHANGES - At fa24506 the focused 41 Python/7 TS tests pass, but required Frontstage and minimum-Node checks remain red; sync current main and revalidate the exact head before merge.
…ction-delivery-0924 The only conflicts were the shared-authority RFC's cadence paragraphs in English and Chinese: main replaced the older five-package estimate with the 2026-09-23 seven-boundary decomposition, while this branch recorded its own 2026-09-24 baseline reconciliation. Resolution keeps main's current decomposition and keeps this slice's checkpoint, updated to name boundary 4 and the now-merged snapshot pagination, so neither statement is lost and the superseded count is not restored. Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
…t page
The refreshed main's canonical snapshot conformance still built the request
readback as `{provider_revision, changed}`, while the adjusted contract decodes
`provider_revision`, `changed`, `attempt` and `target`, so the two cases that
exercise the projection confirmation failed on a decode error instead of the
expected `canonical_snapshot_changed` rejection. The shipped producer and both
TypeScript entrypoints already send the typed shape, so the conformance request
is updated to it and the pagination reference names the typed fields.
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)
Reviewed exact head bb940c3fcd8991c5ffb273fc81817333cbf74a6f against base ed2fa2ee24c612144dfea50d5e4373eb672aed89.
动机
上一轮评审在 fa245069c 上的结论不是新的代码缺陷,而是必需集成验证未闭合:当前 head 的 Frontstage Pages showcase catalog smoke 为红(main 的 #4969 已修该 smoke),minimum-Node lane 另有 4 个 SQLite deferred-lease 用例失败,merge-gate 随之失败。本轮要做的就是把分支同步到当前 main、对新 exact head 重跑必需检查,并在同步后处理真实的集成差异。PR 的目标不变:已提交的普通 refresh-state 与同 Turn 重放要顺手恢复缺失/过期的 Markdown Todo 区,而不重做 Todo 写入、quota 结算或历史事件。
改动思路
本轮没有新增恢复机制,只做「同步 + 集成对齐」。同步后的唯一真实差异是跨 PR 契约:main 的 canonical snapshot conformance(来自已合并的一致性分页工作)仍用两字段 {provider_revision, changed} 构造 projection_readback,而本 PR 已把该读回收紧为带 attempt / target 的 typed confirmation;产品侧 Python producer 与两个 TypeScript 入口都已经是四字段形状,因此把 conformance 请求对齐到 typed 形状,而不是放宽解码器去猜调用方意图(默认 latest 会静默重定向一个 pinned 请求)。
具体改动
- 合入当前
main(69 个提交)。冲突只有双语 RFC 的「节奏/边界」段落:保留 main 的 2026-09-23「七个明确 PR 边界」分解,同时保留本 PR 的 2026-09-24 基线核对,改写为指向表中第 4 项(投影恢复与客户端闭合)、并把已合并的 #4922 记为已合并,不再恢复被取代的「5–8 个包」表述。 - 集成修复:
tests/control_plane_ts/canonical_snapshot_conformance.ts的两处请求补上 typed 读回(attempt: 1,target: "latest"),使「continuation 绑定 query/Goal/incarnation/revision」与「projection confirmation 属于同一 snapshot」两个用例重新走到预期的canonical_snapshot_changed判定,而不是在解码处抛错。 - 文档:
docs/reference/canonical-snapshot-pagination.md说明projection_readback的四个 typed 字段及其 pinned/latest 意图与尝试预算含义。 - 未改动任何产品语义、持久格式、CLI/Lark 入口或打包前端资源;本 PR 的 Python/TS 产品代码与上一轮 head 相同。
对主干的风险
上一轮的两条红都可解释且已在本机闭合:Frontstage showcase catalog smoke 随 main #4969 合并后通过;minimum-Node lane 在精确匹配 CI 的 pinned Node 22.22.3(LOOPX_TEST_REQUIRE_SQLITE_QUALIFIED=1)下 14/14 通过,说明 main 抬高 Node 下限到 WAL-fixed SQLite runtime 后该 lane 已恢复。真实隔离 PostgreSQL 16.15 上:provider conformance 292/292、ladder 行 s2b.postgresql_conformance_live pass=1 fail=0、service admission 10/10(全新 service 数据库,含要求的 authorized-tenant/restored-incarnation 断言)。
完整 TypeScript 套件在本机为 3264/3277,13 项失败均已逐条归因,无一项指向本 diff:11 项来自 todo_continuation.test.ts 写死 python3(本机是 Python 3.9,CI 会准备 3.11),1 项来自复用旧 PostgreSQL service 数据库(重建数据库后 10/10),1 项 sqlite_capacity 的 capacity rehearsal 在未修改的 origin/main 上以相同方式失败。本轮仍按本 Goal 的 wait_for_ci=false 未等待远端 CI。change-quality receipt:cqr_aaf211d3e1a02f88dffd(decision=pass)。
语义与边界
行为变更范围与上一轮一致:只有已提交的 promoted refresh 会修复 Todo 区,legacy 与 dry-run 不变,非 Todo 叙述保留,缺失文档只恢复 Todo 区;展示失败保持 pending 与成功刷新并存,恢复不重放业务提交。相邻重构审视:现有 projection outbox 已足够,本轮不需要新的抽象。
我的整体评价
APPROVE:请求修改的唯一原因是同步与必需验证未闭合,本 head 合入当前 main 后,两条红分别由上游修复与同步后的重跑闭合,并顺带修掉了同步暴露出的真实跨 PR 契约差异(conformance 仍用旧的两字段读回)。改动仍是单主题、可回滚,未扩大 PR 声明的交付边界。
English verdict: APPROVE - exact head bb940c3fcd8991c5ffb273fc81817333cbf74a6f merges current main, resolves the bilingual RFC cadence conflict without restoring the superseded estimate, aligns the canonical snapshot conformance request with the typed projection_readback the shipped producer already sends, and closes the previously red required checks: Frontstage showcase smoke passes, the pinned minimum-Node lane is 14/14, real isolated PostgreSQL 16.15 gives 292/292 conformance, ladder pass=1/fail=0 and 10/10 service admission; the 13 local full-suite failures are attributed to host Python 3.9, a reused service database and one pre-existing origin/main capacity rehearsal failure. Receipt cqr_aaf211d3e1a02f88dffd.
…ction-delivery-0924
huangruiteng
left a comment
There was a problem hiding this comment.
Approval conclusion (author-owned PR; GitHub blocks formal self-approval)
Reviewed exact head 80b7f6bf8de37e5286f1f189dcc9c59814b4c482 against base b2ddbd5f6fe7318de756a3a10d428168a116251f.
动机
上一轮评审在 fa245069c 上请求修改的原因不是新的代码缺陷,而是必需集成验证未闭合:Frontstage Pages showcase catalog smoke 为红(main 的 #4969 已修),minimum-Node lane 另有 4 个 SQLite deferred-lease 用例失败。本轮把分支同步到当前 main 并对新 exact head 重跑必需检查,同时处理同步暴露出的真实跨 PR 契约差异。PR 目标不变:已提交的普通 refresh-state 与同 Turn 重放恢复缺失/过期的 Markdown Todo 区,而不重做 Todo 写入、quota 结算或历史事件。
改动思路
不新增恢复机制,只做「同步 + 集成对齐」。同步后的唯一真实差异是跨 PR 契约:main 的一致性分页 conformance 仍用两字段 {provider_revision, changed} 构造 projection_readback,而本 PR 已把它收紧为带 attempt / target 的 typed confirmation,产品侧 Python producer 与两个 TypeScript 入口都已是四字段形状。因此对齐 conformance 请求,而不是放宽解码器去猜调用方意图——把缺失的 target 默认成 latest 会静默重定向一个 pinned 请求。
具体改动
- 合入当前
main两次(先 69 个提交到一致性分页与 Node 下限抬升之后的 head,再b2ddbd5f6:#4898 shadow-management 与 #4944 goal-instance M2)。第二次为无冲突自动合并。 - 唯一冲突在双语 RFC 的「节奏/边界」段落:保留 main 的 2026-09-23「七个明确 PR 边界」分解,同时保留本 PR 的 2026-09-24 基线核对,改写为指向表中第 4 项(投影恢复与客户端闭合),并把已合并的 #4922 记为已合并,不恢复被取代的「5–8 个包」表述。
- 集成修复:
tests/control_plane_ts/canonical_snapshot_conformance.ts的两处请求补上 typed 读回(attempt: 1,target: "latest"),使「continuation 绑定 query/Goal/incarnation/revision」与「projection confirmation 属于同一 snapshot」回到预期的canonical_snapshot_changed判定,而不是在解码处抛错。 - 文档:
docs/reference/canonical-snapshot-pagination.md说明projection_readback的四个 typed 字段及其 pinned/latest 意图与尝试预算。 - 未改动产品语义、持久格式、CLI/Lark 入口或打包前端资源;本 PR 的 Python/TS 产品代码与上一轮 head 相同。
对主干的风险
上一轮的两条红都已在同步后的 head 上闭合:Frontstage showcase catalog smoke 通过;minimum-Node lane 在精确匹配 CI 的 pinned Node 22.22.3(LOOPX_TEST_REQUIRE_SQLITE_QUALIFIED=1)下 14/14 通过,说明 main 抬高 Node 下限到 WAL-fixed SQLite runtime 后该 lane 已恢复;merge-gate 依赖的其余必需分片在本轮重跑中亦无失败。
真实隔离 PostgreSQL 16.15:provider conformance 292/292、ladder 行 s2b.postgresql_conformance_live pass=1 fail=0、service admission 10/10(全新 service 数据库,含要求的 authorized-tenant/restored-incarnation 断言)。本 head 另行通过:typecheck:control-plane;刷新/投影相关 Python 聚焦套件 114 用例;docs-governance-smoke;loopx canary premerge 19 项全通过。
本轮早先 head 的完整 TypeScript 套件为 3264/3277,13 项失败已逐条归因且无一项指向本 diff:11 项来自 todo_continuation.test.ts 写死 python3(本机是 Python 3.9,CI 准备 3.11),1 项来自复用旧 PostgreSQL service 数据库(重建后 10/10),1 项 sqlite_capacity rehearsal 在未修改的 origin/main 上以相同方式失败。仍按本 Goal 的 wait_for_ci=false 未等待远端 CI。change-quality receipt:cqr_1c40e5d096de870a6b4a(decision=pass)。
语义与边界
行为变更范围未变:只有已提交的 promoted refresh 修复 Todo 区,legacy 与 dry-run 不变,非 Todo 叙述保留,缺失文档只恢复 Todo 区;展示失败保持 pending 与成功刷新并存,恢复不重放业务提交。相邻重构审视:现有 projection outbox 已足够,本轮不需要新抽象。
我的整体评价
APPROVE:请求修改的唯一原因是同步与必需验证未闭合;本 head 合入当前 main 后两条红分别由上游修复与重跑闭合,并修掉了同步暴露的真实跨 PR 契约差异(conformance 仍用两字段读回)。改动单主题、可回滚,未扩大 PR 声明的交付边界。
English verdict: APPROVE - exact head 80b7f6bf8de37e5286f1f189dcc9c59814b4c482 merges current main (including #4898/#4944), resolves the bilingual RFC cadence conflict without restoring the superseded estimate, aligns the canonical snapshot conformance request with the typed projection_readback the shipped producer sends, and closes the previously red required checks: Frontstage showcase smoke passes, the pinned minimum-Node lane is 14/14, real isolated PostgreSQL 16.15 gives 292/292 conformance, ladder pass=1/fail=0 and 10/10 service admission, with typecheck, 114 focused Python cases, docs governance and the 19-check canary green. Receipt cqr_1c40e5d096de870a6b4a.
|
Self-repair and merged decision record (admin-bypass merge, maintainer-authorized).
Repair content:
Validation at the merged head:
|
…readmodel-0924 Two conflicts. The effect-runtime handler registry conflicted on imports only, so both sides keep their handlers. The shared-authority RFC conflicted on the delivery-count checkpoint: main carries the 2026-09-23 seven-boundary decomposition while this branch recorded its own dependency reconciliation. Resolution keeps main's decomposition, updates the reconciliation with the now-merged #4922/#4960/#4961 and the still-in-review #4931, and states that the estimate is updated after the combined head is accepted instead of restoring the superseded five-to-eight package range. Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
Problem and behavior
A promoted Goal can have committed canonical Todos but stale or missing Markdown. Ordinary
refresh-stateand same-Turn replay did not recover that display. Refresh planning read canonical Todos, but the missing-work diagnostic read Markdown again, producing either a false expansion request or a hidden empty frontier.This closes the refresh caller's recovery gap under #4574 and the shared-authority L5/D1 / TypeScript T3 checkpoints:
pendingalongside successful refresh; recovery does not repeat Todo mutations, quota settlement or replayed run history.The existing Todo projection owner is sufficient: no new capability, provider, persisted ACK, RPC method or schema version. The adjacent refactor removes Python retry policy and duplicate Markdown-based Todo diagnosis. CLI JSON/Markdown and Turn use the same boundary; no settings or packaged frontend assets change, and external-delivery authorization remains unchanged.
Validation
Remaining boundary
This is the refresh recovery slice, not full L5 consumer qualification, a background drainer or a provider-default switch. Successful confirmation is a point-in-time observation; another writer may advance immediately afterward. Recovery adds durable display work and confirmation IO, with no latency-improvement claim.
Updated English/Chinese RFCs retain an estimated 5–8 cohesive delivery packages for remaining caller/executor fences, consumer qualification, SQLite D2, whole-Goal migration and default/retirement. They reconcile merged #4870/#4888/#4920 and still-open #4922/#4931, including the failing and missing D2 evidence in #4224. PostgreSQL deployment qualification remains separate. Rendering and validated import/export are not slated for indiscriminate Python deletion.