Skip to content

fix(chat): keep completed-history pages independent across Goals - #6496

Merged
huangruiteng merged 4 commits into
loopx-project:mainfrom
hhyykk:codex/completed-history-lock-isolation
Oct 20, 2026
Merged

huangruiteng merged 4 commits into
loopx-project:mainfrom
hhyykk:codex/completed-history-lock-isolation

Conversation

@hhyykk

@hhyykk hhyykk commented Oct 15, 2026 •

Copy link
Copy Markdown
Collaborator

Author revision 4948b9fe8db0e150c85787e5a5f7a7d59d7ff82a includes target main 6e8688d8d90f1c5a99fadf81def8e4ca2e79c925. The final upstream delta changes documentation and tests only; product bytes and the focused test sources behind the validation below are unchanged.

A slow completed-history source read must not block another Goal's cached pages. Preserve the existing cache owner and perform source preparation outside its lock.

This revision integrates current main, resolves the browser-scenario catalog conflict, and canonicalizes the fixture's temporary root before constructing its registry and source paths. The existing browser scenario now runs its backend under an aliased temporary directory, so it must observe the real slow-read synchronization event before checking independent pagination and 503 recovery.

Validation: Python Ruff and JavaScript syntax checks pass. Eleven cache checks pass; six HTTP/backend cases are blocked by local runtime/socket permissions. A private socket-boundary substitute executes the actual fixture against aliased paths: fixed source emits slow-read and preserves the source files; the original lexical-path mutation misses that event. The real browser/HTTP journey is not qualified in this sandbox.

No pagination limit, retained-cache budget, source authority or write permission changes. This author revision is ready for renewed CI and review; it is not merge approval.

Remote CI: the chat-bundle browser job stops at Personal workspace prefers the registered Goal display name before the history scenario. The same assertion reproduces on current main; the dashboard tree is unchanged. This remains a CI blocker and does not qualify the aliased-temp browser journey.

Signed-off-by: aihop <4408344+hhyykk@users.noreply.github.com>
Signed-off-by: aihop <4408344+hhyykk@users.noreply.github.com>

@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; model=gpt-6.1-sol; provider=OpenAI; declaration_source=runtime_reported; reasoning_effort=xhigh

Reviewed exact head: 6496@b052979293b873235bd50f1b8cdd3481c0b662dc.

动机

在一个 Goal 中翻阅完成历史、同时另一个 Goal 仍在读取数据的用户。 旧共享缓存把源读取放在全局锁内,另一 Goal 的已缓存下一页也会等待;本头先在锁外准备数据,独立分页可以先返回。 真实 HTTP 对照与打包页面验证支持锁隔离和 503 后重试,新增浏览器夹具却在符号链接临时目录下失去慢读同步。 先修正新增夹具的路径身份比较并在别名临时目录下复验;保留当前源码隔离结果和未完成的合并门禁。 不证明生产延迟、并发准备数据的峰值内存、PostgreSQL、安装态或 Windows 桌面;其他工作区 API 使用合成夹具。

改动思路

继续使用原 CompletedTodoPages,只缩短其互斥区:首次读取和编码大小计算可以在锁外完成;检查旧 cursor、清理过期项、驱逐和发布新快照仍在同一锁内。无需每 Goal 的锁表或第二份缓存。保留既有缓存/回执 owner 和类型化消费者;这次问题不需要新增框架。当前结论限定为源码与真实本地读取/回执链路;夹具、跨版本部署、安装态和长期效果按实际证据分别判断。

这属于既有 Python 呈现/IO 缓存,Todo 权威和 TypeScript 页面决定没有迁移。依据变更前 docs/architecture/rfcs/goal-workspace-surface-v0.md,不可变版本 0b4df8a117a96176651aa6d019209fbdefb1539e,核验 2. Problem and motivation 中的来源隔离不变量,以及 5.5 All-work rail 的原生历史分页边界;本 PR 不完成整个工作区 RFC。

具体改动

  1. loopx/chat_completed_todos.py:88 的 page 在无 cursor 时先 load()、算编码字节并拒绝超大结果,再进入锁。已有 cursor 不重新读源;scope、offset、过期与缓存发布的原检查仍串行执行。五分钟 TTL 从实际发布开始,慢读取不会立即耗尽新 cursor 的寿命。
  2. 同一缓存服务完成任务、已验收报告和 Explore 结果;三个真实消费者均已检查。40 行页、8 份快照及 16 MiB 保留编码数据上限不变;这些上限没有变成并发 loader 的峰值内存准入保证。
  3. 新增五个并发/TTL 用例覆盖有/无缓存的独立读、并发数量/字节预算和发布时钟;原完成历史、Explore 与 managed-research-team 套件合计 28 passed、0 skipped。
  4. 新的浏览器场景接入既有 catalog,另用真实 ChatHTTPServer/Todo 文件提供持有源读取、503 与恢复控制。所有五个路径都已读完;新增可复用验证有价值,但路径同步存在下述平台缺陷。

独立验证使用同一私有夹具及真实 HTTP/Markdown:不可变基线的 B 第二页在 A 持有源读取期间保持 pending,释放 A 后返回;本头在同样状态下已返回正确 40 行。随后从本头重新构建的 Chat 页面实测,A 仍被持有时能看到 B 的第 44 项;503 后已读行仍可见,重试到第 0 项、共 85 项,输入哈希不变且没有 POST、Turn 或 action apply。桌面保留 6 个虚拟 DOM 行;390×844 页面可读最后一项、无横向溢出。其他工作区 API 是合成夹具,摘要计数并非此次真实历史后端的资格化内容。

上述正向隔离验证在私有夹具中把临时根路径规范化,两臂一致;提交的原夹具另行原样执行,不能把私有修正冒充本头已修复。作者公开比较材料已读,cache owner 的 base/head 哈希与本次 source 相符,但其毫秒值不是我的独立性能测量,不据此宣称生产 SLO。

风险 canary 的 5 个直接检查与 6 个选中检查均无阻塞执行失败,含全树 semantic 和显式路径边界检查;开发期 advisory 先于全树检查。整体合并门禁仍报过期的精确范围质量回执,没有拿旧回执证明本头可合并。使用显式关闭 Node compile cache 的环境;未查询或等待远程 CI。

对主干的风险

[P2] 让新增慢读夹具比较同一个规范路径。 examples/personal-workspace-browser/completed_history_fixture.py:15 保留 Path(directory) 的字面路径,第 37 行却用它与生产读取端已经 resolve 的 state.md 路径比较。临时目录经过符号链接时,两者指向同一文件却不相等,例如 macOS 常见的 /var 别名。

以合成的符号链接 TMPDIR 直接启动未修改的提交夹具,真实 slow Goal GET 在 release 前就退出成功、返回 85 行,而且没有发出 slow-read。生产解析器返回的实际路径与夹具目标 resolve 后相同、字面值不同。新增 JS 场景等待这个事件,因而会超时,而不是验证宣称的锁隔离;28 项 Python 测试没有覆盖这个入口。

最小修复是构造 registry/目标路径前对临时根统一 .resolve(),或在持有回调中比较规范路径身份,并补一个 symlink TMPDIR 回归。保留真实持有、独立分页、503 重试与零写入断言,不通过延长超时或跳过平台分支掩盖同步缺失。我的私有规范路径对照已经证明核心缓存修复可工作,这不替代提交修复和原场景复验。

并发准备数据会提高在途内存峰值,这次只证明保留缓存预算与来源隔离;没有给出生产 soak、物理内存准入或自然负载吞吐结论。手机完整 DOM 的既有响应式行为也未被这处 Python 改动改变,不将桌面虚拟化断言扩大成手机 DOM 上限承诺。

我的整体评价

当前精确头 REQUEST_CHANGES:原缓存的锁隔离修复有真实入口支持,新增验证方向也合适;阻塞是新夹具在别名临时目录下不能进入其关键同步点。前瞻检查支持保持一个 cache owner、只把准备过程移出锁;无需新增锁管理框架。修正夹具并按新头复验后再给结论,安装态、内存峰值与合并门禁仍单独保留。

English verdict: REQUEST_CHANGES - b052979293b873235bd50f1b8cdd3481c0b662dc fixes the real shared-cache wait and passes 28 focused tests, but the added browser backend compares a lexical temp root with resolved production paths. A symlinked TMPDIR makes its slow GET finish without the synchronization event, so the new scenario times out. Canonicalize the fixture path and retain the real isolation/recovery checks.

@mergify

mergify Bot commented Oct 20, 2026

Copy link
Copy Markdown

This pull request has merge conflicts with main and cannot be merged
until they are resolved. Please rebase or merge the base branch, @hhyykk.

Choose the remote for the base repository, not an out-of-date fork.
For a fork clone, first inspect git remote -v; upstream must point
to https://github.com/loopx-project/loopx.git. If it is absent, add it
with git remote add upstream https://github.com/loopx-project/loopx.git.
Then run:

git fetch upstream
git rebase upstream/main
# Resolve each conflict, git add the resolved files, then git rebase --continue.
git push --force-with-lease origin HEAD

For a same-repository clone whose origin points to
https://github.com/loopx-project/loopx.git, use origin instead of
upstream for fetch/rebase. If you prefer merging the base, use
git merge <base-remote>/main and push normally.

Keep the DCO Signed-off-by trailer on every commit when you rebase.
https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/syncing-a-fork

@mergify mergify Bot added the needs-rebase Mergify: the pull request has merge conflicts with its base branch label Oct 20, 2026
Signed-off-by: aihop <4408344+hhyykk@users.noreply.github.com>
@hhyykk
hhyykk requested a review from songoow as a code owner October 20, 2026 13:33
@mergify mergify Bot removed the needs-rebase Mergify: the pull request has merge conflicts with its base branch label Oct 20, 2026
…ry-lock-isolation

Signed-off-by: aihop <4408344+hhyykk@users.noreply.github.com>

@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

Exact head: 6496@4948b9fe8db0e150c85787e5a5f7a7d59d7ff82a · actual merge base: 6e8688d8d90f1c5a99fadf81def8e4ca2e79c925.

动机

同时查看多个 Goal 完成历史的用户。

A 的历史源读取仍未返回时,旧共享锁也会挡住 B 的缓存下一页;本头把准备数据移到锁外,B 可以先读到后续记录。

真实 HTTP 对照和当前打包页面支持独立翻页、503 后保留已读行并继续到第 85 条;新增别名临时目录夹具已进入真实慢读同步点。

本片不完成整个 Goal 工作区、自然负载吞吐、峰值内存准入、Windows 或正式安装验收。

整个工作区和正式安装资格仍由原 RFC 的既有验收保留;本片只关闭共享缓存隔离及其回归夹具。

改动思路

复用原 CompletedTodoPages,只把真实读取和编码计算移到锁外;缓存发布、scope/cursor、过期和驱逐继续归同一 owner。 当前 PR 的边界是独立历史读取、既有分页和别名目录回归验证;不改变 Todo 权威或用户操作权限。

直接不改会保留已复现的跨 Goal 等待;新增每 Goal 锁表没有必要。原来源校验、分页快照和过期检查仍有同一个 owner,读源失败不会夺走另一份已缓存历史的进度。当前仅把准备阶段移出去,没有缓存 Todo 权威,也没有改变 CLI、调度、扣额或已有写权限。

依据变更前接受的 docs/architecture/rfcs/goal-workspace-surface-v0.md,spec_revision=6e8688d8d90f1c5a99fadf81def8e4ca2e79c925,逐项核对 Invariants、5.5 All-work rail 和 V9 No side effects。原 RFC 的整个工作区和其他验收未因此关闭。此前关于产品旅程的经验只用于核对真实用户路径;它不是额外权限或必须完成整个 RFC 的新门。

具体改动

  • CompletedTodoPages.page 将首次 load()、编码大小计算和单快照过大拒绝移到锁外;scope/cursor、TTL、驱逐和快照发布仍在锁内。TTL 从真实发布时开始。已有 cursor 继续读取同一份快照,不重新加载来源。
  • main 在构造 registry 和目标文件前 resolve 临时根。提交中的真实后端原样运行在别名 TMPDIR 下,确实发出 slow-read;还原字面路径比较的私有反例不发该事件,旧阻断已由实际入口证实修复。
  • completedHistoryIsolationScenario 注册到既有 catalog,主动使用别名临时目录,保留独立翻页、503、恢复、完整末页和零写入断言。它是可复用的回归场景,没有另建测试框架。
  • 全部目标相对变更为 5 文件 +287/-4,其中产品 +6/-4,余下 +281 是回归测试和浏览器夹具。作者开头“only documentation and tests”的表述不能代表实际 diff:缓存运行代码仍有上述改动,本评审按真实完整范围判断。

独立同输入真实 HTTP 对照:A 的文件读取被同步点持有时,当前不可变基线 B 的缓存下一页仍等待;新头已经返回正确的后续 40 行,A 仍 pending。释放 A 后两边都正常完成,源指纹相同。两边同样保留 503 及完整错误,恢复后返回原分页内容。

当前头 28 项 Python 测试、不可变基线的普通 23 项、邻接来源读取的 19 项均通过,零 skip。覆盖 4087 行稳定分页、File/SQLite 归档和 Agent 过滤、错误 Origin、scope/TTL、并发份数/字节预算;GoalSourceReader 自己的外层来源锁未改变,不把这项修复扩大成远端同源并行承诺。

从当前头重新构建的 Chat 页面通过 ego-browser 手动执行同一用户旅程:1512×982 下 A 持有时 B 已看到 task44;503 后 task5 等已读行保留,重试到 task0/共85条;桌面只保留6个可见历史 DOM 行。390×844 下末项可读,页面宽390且无横向溢出。历史后端是真实提交夹具,其他工作区 API 是仓库合成事实;这不是完整 catalog 的成功声明。最初私有脚本选中了隐藏的响应式区域,未完成翻页,那次失败保留;改用实际可见区域后完成原用例,未修改产品源码。

对主干的风险

没有复现当前头阻塞缺陷。保留 40 行分页、8 份/16 MiB 保留编码快照上限;并发准备会增加在途内存,该保留预算不是峰值进程内存准入保证。原 Goal 结果逐页验收、Explore 历史/发现和来源读取消费者都已检查;源故障、陈旧 cursor 和关联来源访问仍由既有 owner 处理。

当前精确头 premerge 为6个直接检查和6个选中检查全过,Ruff 与两个 JS 语法检查也通过。差异语义 advisory 先执行,再由全树检查覆盖其支持的载体;空 advisory 不宣称无任何新语义。源文件与 registry 保持原指纹,后端 POST、Turn 和 action apply 均为0。没有读取或等待 CI,也不把作者报告的其他页面断言当成本轮独立归因。

我的整体评价

APPROVE 当前精确头。 原缓存隔离修复、别名目录夹具和错误后继续读取形成完整可复验的小切口。复用原 CompletedTodoPages,只把真实读取和编码计算移到锁外;缓存发布、scope/cursor、过期和驱逐继续归同一 owner。 当前 PR 的边界是独立历史读取、既有分页和别名目录回归验证;不改变 Todo 权威或用户操作权限。

long_horizon 与 user_experience 在该历史读取路径改善:独立 Goal 可继续、失败可恢复,用户不需新增配置、重复输入或确认。既有上下文和授权已足够,新增必需交互为0。自然负载、现场安装、Windows 与整个父 RFC 仍保留各自边界;批准不授予合并或清除旧 review 的权限。

English verdict: APPROVE at 4948b9f. The unchanged submitted backend now reaches the real held-read event under an aliased temp root. Real base/head HTTP evidence, a lexical-path counterexample, 28 current tests plus 19 adjacent-reader tests, and the freshly built desktop/narrow-page recovery journey support independent paging and zero writes. Natural-load memory, Windows and installed adoption are not claimed.

@huangruiteng
huangruiteng merged commit 4ac980e into loopx-project:main Oct 20, 2026
28 of 40 checks passed
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.

3 participants