Skip to content

fix(collaboration): recover pending requests beyond the first inbox page - #4880

Open
Duang777 wants to merge 7 commits into
loopx-project:mainfrom
Duang777:codex/semantic-handoff-continuity
Open

Duang777 wants to merge 7 commits into
loopx-project:mainfrom
Duang777:codex/semantic-handoff-continuity

Conversation

@Duang777

Copy link
Copy Markdown
Contributor

Goal And Delivered Outcome

Deferred requests awaiting conclusions can fill the first 20 inbox slots indefinitely. Receivers see has_more but cannot retrieve request 21 through either the CLI or scoped MCP.

This change adds next_cursor, manager-inbox read --cursor, and optional read_context(cursor=...). The integration regression retrieves 45 requests in pages of 20/20/5 after restart, preserves the later semantic brief, and returns one later conclusion to its requester without concluding the first 20 requests.

Related to #4339 and challenge #4340. Intended base: main.

Scope And Continuation

Complete within the local receiver pagination scope. The existing collaboration inbox owns the cursor; it binds the resolved runtime root, Goal and Agent without adding storage or authority. Existing calls still return the first page, now with next_cursor. Invalid cursors and unreadable directories fail explicitly. Read receipts follow response preparation and cover returned requests only.

Pages are live, not snapshots. New arrivals before the cursor require a fresh scan. Peer-result consumption remains independent. The RFC checkpoint records this bounded A20 contribution and A5/A13 restart evidence; managed cross-day execution, live Lark qualification and the remaining M1–M4 work stay with #4339. No storage promotion, shared Goal amendment, worker scheduling or lease transfer is claimed.

Future-facing pass: keep cursor validation and position selection in inbox.py, with thin CLI/MCP adapters and no parallel index.

Validation

  • Tested revision: 8506dbc8a1666c09228f3379686681b1579e5cc7.
  • Run state: finished.
  • Input classes: synthetic.
Check kind Result Public-safe evidence / limitation
regression_parity passed Baseline fails with "pending request 21 has no recovery cursor"; changed code passes the same real CLI regression.
real_entrypoint passed tests/test_inbox_pagination.py: CLI subprocesses and MCP stdio restart, 20/20/5 pages, exact read receipts, scope rejection, live revocation, stopped-Goal reads, removed anchor, new arrivals and conclusion return.
integration passed 69 tests across inbox pagination, peer collaboration, MCP and manager context handoff/roundtrip/tracking.
static passed Ruff on changed Python files and git diff --check; public/private candidate scan clean.
integration passed Standard canary premerge on the eight changed paths: 19 selected checks passed, including real CLI output budgets and public-boundary checks; no failures or warnings.

The first canary attempt lacked the locked TypeScript dependencies; those were installed before rerunning. Staging the new test during that run also triggered its worktree-change guard. Final qualification passed against the fixed commits with no concurrent repository writes.

Frontend / Visual Evidence

UI impact: none. This changes receiver CLI/MCP reads. Owner-facing handoff status already has offset pagination; its tracking and original-conversation return tests pass. No packaged frontend or live Lark journey was run, and neither is claimed qualified by this change.

Type of Change

  • Bug fix
  • Documentation update
  • Test update

LoopX Area

  • Control plane (goals, todos, quota, scheduler, registry, runtime)
  • Host or runtime integration

Technical Direction

Semantic handoff RFC: local receiver portion of A20; bounded A5/A13 restart evidence.

Shared-authority RFC fixture impact

N/A. Existing file-backed collaboration records remain in place; this does not claim TypeScript migration or shared-authority promotion.

Boundary Checklist

  • Diff and PR contain no private state, credentials, raw traces, internal links or local machine paths.
  • No maintainer-owned benchmark work duplicated.
  • Change stays scoped to the linked challenge's receiver recovery gap.
  • UI impact is marked none.
  • Every commit includes a DCO sign-off.

Signed-off-by: duanjialing.777 <duanjialing.777@bytedance.com>
Signed-off-by: duanjialing.777 <duanjialing.777@bytedance.com>
…f-continuity

Signed-off-by: duanjialing.777 <duanjialing.777@bytedance.com>
…f-continuity

Signed-off-by: duanjialing.777 <duanjialing.777@bytedance.com>
@Duang777

Copy link
Copy Markdown
Contributor Author

Synced the latest main into exact head 1e3da65f26365817db0145fc252ead510f4dee8b without conflicts.

Fresh local validation on that head:

  • uv run --extra test python -m pytest -q tests/test_inbox_pagination.py: 11 passed
  • uv run --extra test loopx canary premerge --from-git-diff: 19 selected checks passed, 0 failures/warnings, public boundary clean
  • DCO trailers present on every PR commit

CI is rerunning for the updated head. @huangruiteng Once it is green, this control-plane change is ready for maintainer review and merge.

@Duang777

Copy link
Copy Markdown
Contributor Author

CI follow-up on exact head 1e3da65f26365817db0145fc252ead510f4dee8b:

  • 23 checks passed. The only primary failure is stage2c (e2e 1) at s2c2.parity_equal: cycle 3 reported that the candidate head did not match the primary. merge-gate is red only because of that job.
  • This PR does not change the authority/runtime-shadow paths exercised by the row.
  • The same main revision passed this job in run 35697868629.
  • The exact failing row passed twice locally on this PR head: 38.52s and 37.89s.
  • The failed-job artifact contains only the same JUnit assertion; no second stable failure signature.

This evidence points to an isolated concurrency failure, but I am not bypassing it. My account cannot rerun repository Actions (Must have admin rights to Repository). @huangruiteng Please rerun failed jobs for run 35707481100. If the row fails again, I will treat it as a reproducible authority-test defect rather than rerunning again.

…f-continuity

Signed-off-by: duanjialing.777 <duanjialing.777@bytedance.com>
@Duang777

Copy link
Copy Markdown
Contributor Author

Synced current main into exact head 2546c5bf75917edfd42367a5aa8d618edfb2dd9d without conflicts. The focused inbox pagination suite still passes 11/11. This update starts a fresh CI run, including the previously isolated Stage 2C row.

…f-continuity

Signed-off-by: duanjialing.777 <duanjialing.777@bytedance.com>
…f-continuity

Signed-off-by: duanjialing.777 <duanjialing.777@bytedance.com>
@Duang777

Copy link
Copy Markdown
Contributor Author

Synced latest main@952c1c0ae into exact head 1c146abea16ab0e795309ceef2bf4d404536b86a without conflicts. Fresh focused validation: inbox pagination 11/11 and Ruff passed. The superseded head also passed both Stage 2C e2e jobs, including the previously unstable parity row. New exact-head CI is starting.

@huangruiteng huangruiteng 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.

动机

这个 PR 修的是一个会稳定饿死后续协作请求的恢复缺口:manager inbox 只读取按 request id 排序后的前 20 条;只要这些条目仍处于 deferred,排在第 21 条之后的 pending request 就无法被 operator 看见,更谈不上决定或恢复。Issue #4339 允许把 reply/recovery 做成独立的 M3 切片;本 PR 没有把 review、claim 或 authority 扩进来,边界是成立的。

改动思路

实现选择了 live cursor pagination,而不是把整份 inbox 做快照:cursor 由 schema version、scope digest 和上一页最后一个 request id 组成;scope 同时绑定 runtime root、goal id 和 agent id。这样调用方可以逐页恢复已有请求,同时不能把另一个 goal/agent 的 cursor 当作本页授权。新到达且排序在 cursor 之前的请求不会被当前 traversal 自动吸收,文档明确要求从无 cursor 的第一页重新扫描,这个取舍是可观察且可恢复的。

具体改动

  • collaboration/inbox.py 为 pending inbox 增加 cursor 解码、scope 校验、稳定的 20+1 分页以及 has_more / next_cursor
  • manager_inbox.py--cursor 限定在 read action;decision/reply action 不能借 cursor 改变写入对象。
  • collaboration MCP 的 read_context(cursor=...) 复用同一个 inbox contract,并在每次调用时重新校验 agent registration。
  • manager-context 与 collaboration 文档说明 live traversal、restart 语义以及 cursor 不授予 authority。
  • 新增覆盖多页读取、completed/deferred 混排、页间完成、页间新增、malformed cursor、scope mismatch、malformed filename 和 restart 的回归测试。

关键代码讲解

PendingRequestInbox.pending() 先用固定字段计算 scope digest,再对 cursor 做 exact schema/scope/64-hex 校验。遍历仍沿用 request id 的既有排序;只有在 entry identity 与文件名一致且 request 未完成时才计入候选页。收集到 21 条后只返回前 20 条,并以第 20 条生成下一页 cursor,因此不会靠全量 materialization 才能判断 has_more。更重要的是,read receipt 仍在 input readiness 与 peer return preparation 之后记录,分页没有把“看到了文件”偷换成“已成功处理请求”。

对主干的风险

主要残余风险来自 live pagination 本身:翻页过程中新增且排序在当前 anchor 之前的 request 不会出现在本次 traversal。但这不是静默丢失,文档明确了 restart 规则,测试也覆盖了该反例。cursor 只携带 navigation state,不携带 decision、claim 或 write authority;invalid scope、invalid filename 和 identity mismatch 都会在产生 read receipt 前 fail closed。当前 head 相对最新主干仅落后两个不相交提交,未发现相邻冲突。

验证结果:相关 Python suites 62 passed;changed Python files 的 Ruff 通过;补齐 TypeScript parser dependencies 后 semantic vocabulary smoke 通过;loopx canary premerge --from-git-diff 19/19 通过(10 catalog canaries、8 risk-profile smokes、public-boundary check),无 skip/failure。

我的整体评价

这是一组完整、可回滚且与 issue 边界相称的恢复修复。它解决的是可复现的 starvation,而不是引入新的协作 authority;状态、错误与重扫语义都有代码和文档双重约束。未发现需要阻塞合并的 correctness、authority、default-off 或 domain-neutrality 问题,我赞成在保持当前 exact head 的前提下合入。

English verdict: APPROVE - head 1c146ab; scoped live cursors recover pending requests beyond the first 20 without granting decision authority; 62 focused tests, Ruff, semantic vocabulary smoke, and all 19 selected premerge canaries passed.

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