Repository navigation
fix(coordination): tolerate Windows ctime skew in source lease reads - #8761
loopx-agent merged 2 commits into
Conversation
|
windows-powershell 失败与本 PR 无关(跨 PR 既有故障) 本 PR 的 同一签名在其他 PR 上同样出现(例:#8758,失败步骤、两条异常完全一致),且失败点位于 pinned base 基线读取,不在本 PR 的 diff( |
loopx-agent
left a comment
There was a problem hiding this comment.
Reviewer: model_agent · gpt-6.1-sol · OpenAI · runtime_reported · reasoning_effort=max
评审 625459784c6186b587f4e40df16b25c5bdb72037,请求修改。目标分支头 45cfd0c86d8f24d630ab66ad7f76784faa21c3f6。基线 1cdd9bbefd1d849ac8aa733bd3d80bc13ad0b722,实时主干 4604f938b612c5da0d8a3485ce563bea922fc14e。 当前主干的合并树 55b17147eb8caa89074b9bb320b75c2c3ce32328 无冲突。
[P2] Windows ctime 容错须通过最终的 lease 重读。 在真实 bootstrap 的前置采集及最终同源重读中,用同一稳定文件,只让路径和描述符的 ctime 视图不同。 在真实 CLI 上,前置 Python 读取与 TS 重读均只注入 ctime 差异时,当前提交仍返回 source_changed_retry;没有成功的 bootstrap 或权威快照。只注入 TS,同样失败;只注入 Python,当前提交能写入原租约的快照。 对同一条生产路径的 TS sourceLeaseBytes 使用对应平台策略;仅在 Windows 的卷/文件身份全程已证实时放宽 ctime。保持身份、文件类型、大小、mtime、字节摘要和锁,并用真实 CLI 验证两层均只有 ctime 偏差时能成功,以及实际来源变化时拒绝。 源代码
动机 / Motivation
在 Windows 上创建或复验本地 coordination shadow 的维护者。 运维人员用 coordination-shadow bootstrap 建立本地影子时,Windows 文件在路径查询和描述符查询中可能给出不同 ctime,即使租约字节、身份、mtime 和大小都没变。 主干在 Python 捕获阶段可能因纯 ctime 差异拒绝 unchanged 文件。 反复重试仍不能建立影子,也不能从当前状态判断是文件真变了还是平台读数不同。 稳定租约应通过前置读取与最终同源校验;真实内容或身份变化仍应在任何权威写入前拒绝。 只修复同一次 lease 读取的稳定性;保持已有同源 bytes digest、锁、身份、常规文件、禁链接和启用边界。
改动思路 / Approach
保留 Python 采集和 TypeScript 持锁校验的职责;让两层对同一档平台不变量保持一致。 只修复同一次 lease 读取的稳定性;保持已有同源 bytes digest、锁、身份、常规文件、禁链接和启用边界。 主干两层均依赖混用的时间戳。Python 的最小局部修补可以减少一处误判;但对用户报告为修复时,还需要覆盖其实际 TS 读回。用现有读取器处理相同原则,不加新设置或 provider。 Python 采集提供原租约字节和摘要。现有 TypeScript writer 持锁对源文件、目录清单和摘要重新验证,且最后决定是否可提交。
新增输入观察只发生于已启用的 本地 shadow 引导;不会启动 provider 或迁移现有数据。两个语言的检查不能各自放宽到不同范围。正常 bootstrap、旧损坏来源和关闭时的拒绝未新增权限。
具体改动 / Changes
2 个文件(+84/−2)。生产是一个已有 Python 采集器;测试新增 30 个 stat 边界场景。TS 校验行在主干和 head 中相同。 现有同源校验协议 与问题清单 #8604 规定源复验;Windows ctime 政策对照 #8599。 采用规范版本 4604f938b612c5da0d8a3485ce563bea922fc14e,来源 docs/reference/reviewed-coordination-promotion.md。
| 检查点 | 可观察要求 | 结果 |
|---|---|---|
windows_full_identity |
稳定 lease 在两层都有 ctime 差异 | 未满足 |
genuine_change_remains_denied |
身份或内容变化要保留拒绝 | 通过 |
untouched_other_platform |
无偏差与 POSIX 路径保持 | 通过 |
关键代码讲解
- _source_lease_bytes:采集未变租约与摘要的输入。Windows 完整身份允许 ctime-only;mtime、身份和长度继续约束。
- _build_runtime_shadow_source_snapshot:把 lease bytes 绑定到清单。每个成员使用实际 SHA-256,不发布未经采集的数据。
- sourceLeaseBytes:持锁校验再次读源文件。无条件比较 ctime,复现与 Python 新策略不一致。
- verifyShadowSourceSnapshot:核对清单及投影。只有当前清单和字节摘要相同才到写入。
对主干的风险 / Risks
同一条未变 lease 仅在 Python 观察中出现 ctime 偏差时,主干拒绝,候选的真实 bootstrap 提交成功;正常租约两边均成功。POSIX ctime 改变和 Windows 策略下 mtime 改变仍拒绝;缺卷/文件标识、真实元数据变化和不安全路径另有本地回归覆盖。 在真实 CLI 上,前置 Python 读取与 TS 重读均只注入 ctime 差异时,当前提交仍返回 source_changed_retry;没有成功的 bootstrap 或权威快照。只注入 TS,同样失败;只注入 Python,当前提交能写入原租约的快照。
候选 151 项、当前主干 121 项通过;Ruff、diff、DCO 与双语检查通过,当前主干合并树无冲突。
语义与 CI 对齐
真实命令使用隔离源和存储;模拟条件只改变时间读数。没有把实验结果说成原生 Windows 已验证。 在 macOS 真实 CLI 与真实文件 I/O 上定点注入两层元数据偏差;未独立运行原生 Windows。作者报告的 Windows 30 项测试覆盖 Python read policy;其排序用例失败单独归于 #8762,不能证明当前端到端通过。未查询托管 CI。
我的整体评价 / Verdict
REQUEST_CHANGES。对同一条生产路径的 TS sourceLeaseBytes 使用对应平台策略;仅在 Windows 的卷/文件身份全程已证实时放宽 ctime。保持身份、文件类型、大小、mtime、字节摘要和锁,并用真实 CLI 验证两层均只有 ctime 偏差时能成功,以及实际来源变化时拒绝。 当前评审的交付边界是 CLI、宿主文本入口和持久读回。无变化的产品页面不需要首屏截图。
English verdict: REQUEST_CHANGES at 6254597. The Python lease read now tolerates Windows-style ctime skew with complete identity, but the same CLI transaction still rejects that stable lease during the mandatory TypeScript source recheck.
| # Tolerate Windows ctime-only skew only with a volume and file index | ||
| # in every observation; POSIX keeps ctime in the lease fence. | ||
| stability_fields: tuple[str, ...] = ("st_mtime_ns",) | ||
| if os.name != "nt" or not all( |
There was a problem hiding this comment.
[P2] Windows ctime 容错须通过最终的 lease 重读。 在真实 bootstrap 的前置采集及最终同源重读中,用同一稳定文件,只让路径和描述符的 ctime 视图不同。 在真实 CLI 上,前置 Python 读取与 TS 重读均只注入 ctime 差异时,当前提交仍返回 source_changed_retry;没有成功的 bootstrap 或权威快照。只注入 TS,同样失败;只注入 Python,当前提交能写入原租约的快照。 对同一条生产路径的 TS sourceLeaseBytes 使用对应平台策略;仅在 Windows 的卷/文件身份全程已证实时放宽 ctime。保持身份、文件类型、大小、mtime、字节摘要和锁,并用真实 CLI 验证两层均只有 ctime 偏差时能成功,以及实际来源变化时拒绝。
_source_lease_bytes compared st_ctime_ns unconditionally across its path lstat / descriptor fstat / final path lstat observations, so a Windows ctime-only skew on an unchanged lease file raised source_changed_retry without any byte change. Apply the policy already established for materials and cold-source backup: keep POSIX ctime in the lease fence, and tolerate Windows ctime skew only when every observation carries a complete volume/file identity. The regression matrix changes exactly one metadata field at one stat boundary: Windows ctime alone is accepted, POSIX ctime and any dev/ino/size/mtime change is rejected on both policies, and missing volume/file indexes fail closed to the ctime fence. Signed-off-by: BigDataDZ <[email protected]>
The Python capture layer tolerates Windows ctime-only skew with a complete volume/file identity, but the same CLI transaction still rejected that stable lease in the mandatory TypeScript recheck: sourceLeaseBytes compared ctimeMs unconditionally across its path and descriptor observations. Apply the identical platform policy to the TS fence so both layers of one bootstrap agree. The regression drives a real bootstrapCoordinationRuntimeShadow in an isolated child with node:fs/promises wrapped at the stat boundary: a ctime-only skew on an applied bootstrap passes both the admission and final recheck, an incomplete volume identity keeps ctime and fails closed, and an mtime skew still rejects. Signed-off-by: BigDataDZ <[email protected]>
6254597 to
8b201db
Compare
|
已修复:TS 复验层与 Python 采集层采用同一 ctime 政策 感谢评审指出端到端缺口——确认属实:Python 采集层放宽后,同一 bootstrap 的 TS 新提交
验证(真实 Windows):TS 新场景 4/4、全文件 23 pass / 0 fail(1 个既有平台跳过)、Python 30 例矩阵 rebase 后复跑全过。 说明:评审要求的"两层同时只注入 ctime 差异"在真实 CLI 单进程里无法从外部各自注入(Python 层在宿主进程、TS 层在 Node 子进程),故以两层各自的同政策注入 + 同一真实 bootstrap 端到端(TS 层)组合覆盖;两层政策字节级一致(同一条件、同一身份守卫),不再存在单侧放宽的窗口。 |
There was a problem hiding this comment.
Reviewer: model_agent · gpt-6.1-sol · OpenAI · runtime_reported · reasoning_effort=max
评审提交 8b201db8eeb6f04bbb8f15ce6064d7b493c0230d,分叉基线 4604f938b612c5da0d8a3485ce563bea922fc14e。
批准当前提交。 上一轮发现的最终重读缺口已修复。用真实 CLI 同时让 Python 和 TypeScript 读到 ctime 差异,候选成功建立影子副本,重放沿用原游标。上一轮评审
动机 / Motivation
在 Windows 上建立本地协调状态影子副本的维护者会遇到这个问题。 同一份租约内容没变时,文件路径查询和已打开文件查询的 ctime 仍可能不同。原实现把这类差异当作源已变化,要求操作者重试。 用同一份稳定租约模拟两层 ctime 差异,候选版本能建立影子副本,读回结果匹配,同一个操作重放沿用已有结果。 这次修复覆盖已有的本地影子引导及来源复核,权限与写入继续由原有配置和事务决定。
改动思路 / Approach
两个现有读取点采用同一平台条件,省去额外协议、设置和兼容状态。 这次修复覆盖已有的本地影子引导及来源复核,权限与写入继续由原有配置和事务决定。 改动落在现有 Python 采集和 TypeScript 持锁重读。两处都参与一次引导,单改单侧仍会误拒。 Python 先采集原文件和摘要,TypeScript 在既有锁下按同一规则重新读取文件并比较实际字节,复核通过才提交。
具体改动 / Changes
以 4604f938b612c5da0d8a3485ce563bea922fc14e 上的 docs/reference/reviewed-coordination-promotion.md 为准。四个文件共 +188/−5,其中生产代码 +15/−4。Windows 需要路径和描述符的观察都提供卷标识和文件索引。身份不完整时继续比较 ctime,POSIX 维持原比较。同源复核协议 · 问题 #8604
| 检查点 | 独立观察 |
|---|---|
windows_full_identity |
基线拒绝。候选写下游标 1,读回 matched。重复同一请求返回 replayed。 |
genuine_change_remains_denied |
同长度字节变化、mtime 变化、有 ctime 偏差但缺少卷号,以及真实路径被目录替换均被拒。 |
untouched_other_platform |
普通来源两版均成功,POSIX ctime 偏差和关闭配置仍被拒。 |
- Python 采集从真实描述符取得租约字节,生成跨运行时核对的来源见证。_source_lease_bytes
- TS 重读追加同一平台条件,随后仍逐文件验证清单和摘要。sourceLeaseBytes · verifyShadowSourceSnapshot
对主干的风险 / Risks
ctime 有偏差且身份不完整时仍返回 source_changed_retry。mtime 差异和实际同长度字节变化也返回此错误。实际把目录换到租约路径也被拒绝。各拒绝样本的隔离运行目录只有原来源文件。 无偏差时基线和候选都通过。POSIX 的 ctime 差异仍被拒绝。未启用时两版在来源读取前返回 coordination_shadow_not_enabled。 Python 三组回归基线 121 项、候选 151 项通过。TypeScript shadow suite 基线 20 项、候选 24 项通过。两版经独立 CLI 对照,Ruff、DCO、diff check、RFC 双语 diff 和本地主干合并树检查通过。
语义与 CI 对齐
Windows 平台选择与 ctime 差异在 macOS 上定点注入,文件 I/O、CLI、产品代码和 File provider 为实际执行。原生 Windows 结果只参考作者自测。本轮未独立运行原生 Windows 或查询托管 CI。
我的整体评价 / Verdict
批准。完整来源恢复了原有引导与状态读回,变更来源仍会被原事务拒绝。当前影子写入后源仍是主权威。原生 Windows 的实测范围如上,合并资格走仓库现有检查。
English verdict: APPROVE at 8b201db. The real CLI now completes and replays a stable bootstrap with Windows-style ctime skew in both readers. The CLI still rejects ctime skew when volume identity is missing. It also rejects modified bytes and actual path replacement.
Motivation / 动机
Issue #8604 的审计把
authority_source_capture.py的两处 ctime 比较列为 SUSCEPTIBLE(Deferred):_source_lease_bytes在 pathlstat→ descriptorfstat→ final pathlstat三次观察之间无条件比较st_ctime_ns,Windows 上未变更 lease 文件的纯 ctime 偏差会误抛source_changed_retry。本 PR 把 #8599 已确立并合并的 Windows ctime 政策应用到 source lease 读取围栏。Change / 变更
loopx/control_plane/coordination/authority_source_capture.py:POSIX 保留 ctime 参与 lease 围栏;Windows 仅当三次观察都带有完整卷/文件索引(st_dev/st_ino非零)时容忍 ctime-only 偏差,索引不完整时 fail-closed 保留 ctime 比较。O_NOFOLLOW守卫全部保留,比较语义与原先逐字段等价(仅 ctime 的参与按平台政策条件化)。Regression / 回归
tests/control_plane/test_shadow_registry_source.py::test_lease_read_identity_change_policy——真实capture()路径上、stat 边界注入单一字段偏移,2 平台 × 5 字段 × 3 身份可用性共 30 例:sha256精确;st_dev/st_ino/st_size/st_mtime_ns变化、或卷/文件索引缺失 → 双平台均拒绝source_changed_retry。Validation / 验证
基于
main1cdd9bbef,真实 Windows 运行:uv run --extra test python -m pytest -q tests/control_plane/test_shadow_registry_source.py -k lease_read_identity_change_policy→ 30 passeduv run --extra test python -m pytest -q tests/control_plane/test_shadow_registry_source.py→ 55 passed, 1 failed(test_source_snapshot_preserves_inventory_without_projecting_orphan_leases:WindowsPath比较大小写折叠导致的既有排序失败,已验证在未修改main上同样失败,与本 PR 无关,不在此处理)uv run --extra test python -m pytest -q tests/architecture/test_settlement_receipt_source_boundaries.py tests/control_plane/test_canonical_lease_inspection.py→ 95 passedAddresses the
authority_source_capturesites deferred by #8604; the remaining seven deferred modules are untouched.