Skip to content

fix(hosts): tolerate Windows ctime skew in the rollout same-read fence - #8772

Open
BigDataDZ wants to merge 1 commit into
loopx-project:mainfrom
BigDataDZ:codex/rollout-ctime-fence-20261114
Open

BigDataDZ wants to merge 1 commit into
loopx-project:mainfrom
BigDataDZ:codex/rollout-ctime-fence-20261114

Conversation

@BigDataDZ

Copy link
Copy Markdown
Contributor

Motivation / 动机

#8604 审计将 codex_app_thread_activity.py:249 列为 SUSCEPTIBLE(Deferred):_rollout_activity 读取后在同一打开描述符的两次 fstat 之间,只要同 size 且 mtime 或 ctime 变化,就驱逐 cursor 并返回 RECORD_UNRECOGNIZED。Windows 上未变更 rollout 的纯 ctime 偏差会因此被误判为同尺寸重写。

Change / 变更

Regression / 回归

tests/test_host_thread_activity.py::test_same_size_read_fence_metadata_policy——真实 observe_codex_threads 路径、真实 rollout fixture,stat 边界注入单一字段偏移(2 平台 × 2 字段 × 3 身份可用性,12 例):

  • Windows + 仅 ctime + 完整卷/文件身份 → 识别结果保持(IDLE + last_turn_ended_at 精确);
  • POSIX ctime、任何 mtime 变化、或卷/文件索引缺失 → 均维持 RECORD_UNRECOGNIZED 驱逐。

Validation / 验证

基于 main 1cdd9bbef,真实 Windows 运行:

  • uv run --extra test python -m pytest -q tests/test_host_thread_activity.py -k same_size_read_fence_metadata_policy → 12 passed
  • uv run --extra test python -m pytest -q tests/test_host_thread_activity.py tests/test_codex_rollout_cursor.py → 138 passed(确认未改动的 cursor 跨时政策行为不变)

Addresses the codex_app_thread_activity site deferred by #8604. Same family as #8761 (authority_source_capture).

The post-read fence in _rollout_activity evicted the cursor with
RECORD_UNRECOGNIZED whenever two fstat observations of one open
rollout descriptor showed the same size with a changed ctime. On
Windows that is metadata noise, not a same-size rewrite. Keep POSIX
ctime in the fence and drop it on Windows only when both observations
carry a usable volume/file index, matching the policy materials and
cold-source backup already follow.

The rollout cursor's own cross-time and persisted ctime checks are
deliberately unchanged; they remain mutation evidence per the loopx-project#8604
audit deferral.

Signed-off-by: BigDataDZ <[email protected]>

@loopx-agent loopx-agent left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewer: model_agent · gpt-6.1-sol · OpenAI · runtime_reported · reasoning_effort=max

复审提交 7030348f3002890b92aeb7044e1f8616831b86f4,实际分叉 1cdd9bbefd1d849ac8aa733bd3d80bc13ad0b722,对照主干 74ca883d5bd3e4bc64671bac54210eac9e97ed05。

[P2] 放宽 ctime 后会把已改写的 rollout 报为空闲。 同一打开文件读出结束标记后,写入方等长替换为开始标记并恢复原来的 mtime,卷号、文件索引、大小与 mtime 保持,最后一次 ctime 不同。 本机真实文件与 SQLite 线程索引走同一个 Windows 比较分支。基线返回 unknown 并显示缺少观察,候选返回 idle 且交付窗口显示 fresh。恢复普通读取后,同一文件显示 turn_open。POSIX 与 mtime 确实改变的对照仍返回 unknown。 实现位置

动机 / Motivation

查看已绑定 Codex 线程活动和最近交付窗口的用户,需要可靠地区分空闲、运行中与无法观察。 Windows 上未改写的 rollout 出现纯 ctime 偏差时,原读取会返回 unknown。候选用完整卷和文件索引、大小及 mtime 保留可识别结果。 真实 rollout 和 SQLite 线程索引上,候选的 Windows 比较分支通过了只改变 ctime 的稳定文件。POSIX ctime、缺失文件身份、mtime 变化及未读的 append 均保持原判定。 变更限于 Codex 线程观察及其消费者看到的活动状态。跨观察游标、持久缓存格式和调度授权沿原合同。

改动思路 / Approach

把 Windows 元数据容差与本次已解析事实的复核放在同一次读取内。沿用读取预算、既有游标和原错误分类。 只有完整文件身份且本次用于状态的记录能在预算内复核时,才发布被放宽的状态观察。 materials 和 cold source backup 已按文件身份处理 Windows ctime 偏差。rollout 已有读取预算、记录锚点和基于解析事实的核验。其证据期与备份不同。 在忽略 Windows ctime 的分支发布结果前,在读取预算内用新鲜字节复验支撑本次状态的实际 marker 和最近事件,包含从 forward 游标选择的记录;无法证实时返回 unknown。用纯 ctime 偏差、等尺寸改写、mtime 变化及 append 作成对测试,并在受支持的 Windows 版本运行。

具体改动 / Changes

2 个文件,增加 57 行,删除 1 行。 本轮按主干的 docs/integrations/attached-agent-session-broker.md 核对「绑定线程活动的状态和证据」和「不确定观测保持 unknown」。后者的失败可与已通过的行为并存。#8604 审计 把 Codex rollout 单次读取判定和跨次游标列为两个处置边界。

  • _rollout_activity负责决定进入该分支的条件。同尺寸 Windows 读取在完整身份时不再因单一 ctime 偏差退出。状态、游标与存储契约没有新增字段。
  • observe_codex_threads 是本次实际验证的调用链,回读使用原结果类型。
  • _verify_facts仍是原规则的一部分。materials 和 cold source backup 已按文件身份处理 Windows ctime 偏差。rollout 已有读取预算、记录锚点和基于解析事实的核验。其证据期与备份不同。 关联合同或实现

对主干的风险 / Risks

分叉基线 126 项通过,精确候选 138 项通过。Ruff、DCO、diff、双语检查及与当前主干的模拟合并通过。 本机真实文件与 SQLite 线程索引走同一个 Windows 比较分支。基线返回 unknown 并显示缺少观察,候选返回 idle 且交付窗口显示 fresh。恢复普通读取后,同一文件显示 turn_open。POSIX 与 mtime 确实改变的对照仍返回 unknown。 反例在 macOS 上用真实文件与 SQLite,通过注入平台选项走 Windows 比较分支。未独立验证原生 Windows、打包宿主或托管 CI。 原生 Windows 对照应记录 Python 版本和硬盘类型。Python 对 st_ctime 的 Windows 语义有版本限定,Win32 允许文件保存方设置时间戳。Python stat 文档 · Win32 SetFileTime

我的整体评价 / Verdict

请求修改。保留已验证的正向修复,同时补上上述反例。在真实观察快照形成后、最终 fstat 前,等长改写结束标记,恢复 mtime。对照稳定 ctime 偏差应读到 idle,而改写应使本轮退回 unknown。

English verdict: REQUEST_CHANGES at 7030348. Tolerating ctime-only skew fixes the stable-file case. With the Windows comparison selected on macOS, a real same-size rewrite that restores mtime can still publish the old idle state and a fresh delivery window. A subsequent read sees the open turn.

# descriptor is metadata noise, not a same-size rewrite; drop
# ctime from this one-read fence only when both observations
# carry a usable volume/file index.
fence_ctime = os.name != "nt" or not (stat.st_dev and stat.st_ino and end.st_dev and end.st_ino)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] 放宽 ctime 后会把已改写的 rollout 报为空闲。 本机真实文件与 SQLite 线程索引走同一个 Windows 比较分支。基线返回 unknown 并显示缺少观察,候选返回 idle 且交付窗口显示 fresh。恢复普通读取后,同一文件显示 turn_open。POSIX 与 mtime 确实改变的对照仍返回 unknown。 在忽略 Windows ctime 的分支发布结果前,在读取预算内用新鲜字节复验支撑本次状态的实际 marker 和最近事件,包含从 forward 游标选择的记录;无法证实时返回 unknown。用纯 ctime 偏差、等尺寸改写、mtime 变化及 append 作成对测试,并在受支持的 Windows 版本运行。

This branch has not been deployed

No deployments
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.

2 participants