Skip to content

fix(authority): stabilize resume evaluation identity - #4831

Open
huangruiteng wants to merge 1 commit into
mainfrom
codex/stable-authority-resume-evaluation
Open

huangruiteng wants to merge 1 commit into
mainfrom
codex/stable-authority-resume-evaluation

Conversation

@huangruiteng

Copy link
Copy Markdown
Collaborator

Summary

  • exclude only resume_condition.evaluated_at from runtime-shadow parity and source-partition semantic digests
  • keep full prepared outbox bytes and supplied projections byte-for-byte verified
  • use the same identity rule in the TypeScript authority owner and Python capture codec
  • document the bilingual contract and reusable self-repair pattern

Why

resume_condition.evaluated_at is computed from the reader clock. Re-reading unchanged durable Todo state therefore changed the authority digest, so an immediately matched bootstrap could drift without a writer. The same unstable field also made the next captured write fail with source_partition_continuity_unproved.

The decision fields remain authoritative: readiness, satisfied, reason, generation, target, and every other Todo or lease fact still change the digest.

Validation

  • npm run typecheck:control-plane
  • focused TypeScript authority/outbox suite: 29 passed
  • focused Python drain suite: 15 passed
  • file authority conformance suite: 184 passed
  • loopx canary premerge --from-git-diff --goal-id finance-research-goal: 17/17 selected checks passed, public-boundary clean, no warnings or manual holds

Product entry points

This changes the existing coordination-shadow CLI/control-plane read and capture path without changing request or projection shape. No frontend or Lark control changes are needed because no user-editable setting or new action is introduced; those surfaces continue consuming the same shared projection and typed receipts.

Upgrade recovery

A pending entry created with the old digest semantics must not be reinterpreted or blindly replayed. Operators should archive that pre-promotion shadow lineage with the existing rollback flow, bootstrap a fresh lineage from the unchanged primary source, and qualify new captured operations before promotion.

Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
@huangruiteng
huangruiteng force-pushed the codex/stable-authority-resume-evaluation branch from 45707f5 to e0ca1b8 Compare September 20, 2026 20:12
@huangruiteng

Copy link
Copy Markdown
Collaborator Author

Rebased onto current main at exact head e0ca1b8. Fresh local validation: control-plane typecheck passed; focused TypeScript authority/outbox 29/29 passed; Python drain/native E2E 66/66 passed; LoopX premerge gate 17/17 passed with public-boundary clean and no manual holds. Per repository policy this control-plane PR remains maintainer-review required; no self-merge was attempted.

@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)

评审 exact head:e0ca1b87a30f7fc0244f693ecc13de5c7a0d573c

动机

这个 PR 修复的是 authority identity 把查询时钟误当成持久事实的问题。resume_condition.evaluated_at 由读路径按当前时钟重新计算;旧实现把它放进 runtime-shadow 的 partition/head digest 后,同一份未发生写入的 Todo 状态会在每次读取时产生新 identity,导致 bootstrap 后的只读 inspect 报 drifted,并可能让下一次合法 capture 以 source_partition_continuity_unproved 停住。

我用相同的隔离 Goal、file-v0 backend 和 public coordination-shadow CLI 对 base/head 做了反事实验证:base 09f10c4e37b89c6ed25f2f2354f89d641662e83c 在 bootstrap 后连续两次 inspect 都是 drifted,且 expected digest 每次变化;本 head 连续两次都是 matched,expected 与 observed digest 稳定一致。这个结果证明修复的是实际入口上的确定性缺陷,不只是让 helper 单测变绿。

改动思路

实现边界是合理的:TypeScript local_authority_shadow.ts 仍是 parity、continuity 和 commit 的决策 owner;Python local_authority_shadow_projection.py 只在 source-owned outbox capture 边界镜像同一个 codec。两边都仅从 Todo identity view 中移除 resume_condition.evaluated_at,不改写原 projection,也不移除 satisfied、readiness、reason、generation、target 或其他 Todo/lease 事实。

这比只修 inspect 更完整:inspect 与 writer continuity 必须共用同一 identity,否则只读状态看似恢复,下一次 writer 仍会失败;也比冻结读时钟更稳,因为语义边界被明确表达为“决策事实”与“查询观察”。完整 prepared outbox bytes、传入 projection、cursor、receipt 与 provider revision 仍按原规则验证。

具体改动

生产代码共两处边界:

  1. TypeScript 新增 todoAuthorityIdentityViewpartitionAuthorityIdentityView 和导出的 localAuthorityShadowPartitionDigest,并让 localAuthorityShadowHeadDigestvalidateEntryIdentityvalidateSourceContinuity 使用同一规范化规则。
  2. Python 新增 _stable_todospartition_comparison_view,让 partition_digest/head_digest 与 TypeScript authority owner 保持一致。

关键代码讲解

  • todoAuthorityIdentityView:clone 单个 Todo,仅在 resume_condition 为对象时删除精确键 evaluated_at;不会通过 substring/prose heuristics 扩大忽略范围。
  • localAuthorityShadowPartitionDigest:只对 partition === "todos" 应用稳定 identity,lease partition 保持原语义。
  • partition_comparison_view:Python capture codec 的对应实现;跨语言测试直接比较相同 projection 的 digest,避免双 runtime 漂移。
  • validateSourceContinuity:继续要求 previous digest 精确匹配,并要求非 no-op 的新 digest 不同,因此真实 decision mutation 仍不能伪装成无变化。

测试与文档也覆盖了对应契约:Python/TypeScript 都证明“仅时钟变化相等、satisfied 变化不等”;outbox 测试覆盖时钟变化后的下一次真实 Todo mutation;双语 RFC 与 self-repair pattern 说明这个 identity 和恢复边界。

对主干的风险

最重要的兼容风险是 digest 含义发生变化:旧的 pre-promotion lineage 若历史 receipt 中包含旧的完整 Todo digest,新版本 qualification 可能拒绝它,不能把旧 receipt 静默重解释成新语义。这个 PR 没有隐藏该差异:当前 RFC 仍把真实 promotion 保持在未满足门禁状态;对尚未 promotion 的候选 lineage,现有 revision-fenced rollback 会归档 candidate,再从仍然 authoritative 的 legacy source 做 fresh bootstrap。这里不会改写或损坏原始 Todo/lease 数据,也没有自动 promote。

我验证了以下证据:

  • npm run typecheck:control-plane:通过;
  • 绑定受支持 Python 3.13 的 TypeScript authority/outbox suite:29/29 通过;
  • Python public CLI/runtime-shadow/cursor recovery E2E:38/38 通过(518.49s);
  • 同一 synthetic fixture 的 base/head 真实 CLI 对照:base 漂移,head 连续 matched;
  • loopx canary premerge --from-git-diff --goal-id finance-research-goal:17/17 selected checks 通过,public boundary clean,无 warning/manual hold。

远端 CI 未拉取或等待,因为当前 capability packet 明确 wait_for_ci=false;本地 required validation 没有失败或跳过。最初用系统 python3 跑跨语言子进程时,因解释器过旧不支持项目使用的 dataclass(slots=True) 导致 2 个环境失败;按项目约定设置 LOOPX_TEST_PYTHON 到 checkout 的 Python 3.13 后同套 29 个用例全部通过,这不是被忽略的产品失败。

语义与 CI 对齐

这是对既有 runtime-shadow authority identity vocabulary 的有意扩展,不是另起一套状态权威。规范化依据是独立事实:evaluated_at 是读时观察,而 evaluated decision 是持久语义。风险 profile、typed-state、domain-neutrality、default-off 与 guidance/obligation lens 均未发现阻塞项;尤其 feature-off 路径不创建 shadow state、不改变 CLI 请求形状,也不影响普通 Goal。

我的整体评价

结论:可批准。这个 PR 在正确 owner 中用最小跨语言改动修复了可复现的真实路径缺陷,同时保留了完整字节/投影验证与所有决策字段的 fail-closed 语义。没有引入第二份 authority、配置开关、状态字段或 speculative framework。

Future-facing pass:当前的两个小 identity-view helper 正好对应真实 Python capture / TypeScript authority 边界,不宜再抽成跨语言生成框架;更大的 promotion/migration 工作仍应留在既有 D2/D3 门禁和显式 cutover 计划中。本 PR 的 residual risk 仅是旧 pre-promotion digest lineage 需要走现有显式 recovery,不能把它当成已 promotion 数据的在线迁移方案。

English verdict: APPROVE - exact head e0ca1b87a30f7fc0244f693ecc13de5c7a0d573c; base/head public-CLI reproduction confirmed the clock-only drift fix, supported by 29 TypeScript/cross-runtime tests, 38 Python CLI/runtime-shadow E2E tests, control-plane typecheck, and 17/17 premerge canaries; old pre-promotion digest lineages still require explicit rollback/rebootstrap and no promotion authority is granted.

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