Repository navigation
manager: fan out unscoped global-todos and global-summary across peer_v1 agents - #7839
loopx-agent wants to merge 2 commits into
Conversation
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
Request changes conclusion (author-owned PR; GitHub blocks formal self-review).
动机 / Motivation
多 Agent Goal 的维护者需要在一个总览中找出可继续的工作和需要本人处理的阻塞。
基线的未指定 Agent 查询会落入身份升级提示;候选尝试逐个查询,但九个 Agent 时漏掉第九个,且 A 可执行、B 被用户阻塞时总览把阻塞数从 1 改成 0。
目标是未指定 Agent 时保留全部可见工作与阻塞;当前真实 CLI 只证明部分 fanout 可用,完整性仍失败。
本 PR 只改变全局只读投影,不应修改领取、执行、配额、用户授权或原有阻塞语义。
改动思路 / Approach
当前 PR 边界:全局投影和回归测试。
status 提供注册身份与 attention queue,manager 调用现有 build_quota_should_run,把各 Agent 的权威资格投影成全局列表。这个方向能让普通只读查询不再被未指定身份的自动化升级提示挡住。保留 quota 作为每个 Agent 的决策 owner,让 manager 只聚合投影是合理边界;当前用单 lane 代替完整 Goal、隐藏八项截断和重复 legacy 分类需要在本 PR 修正。 本 PR 边界是全局投影和其回归测试,修复不应改变 quota 的执行授权。显示 limit 只限制返回行数,不能成为注册身份扫描或完整计数的上限。
下面是实际 File/SQLite CLI 对照结果,两个后端均相同,非示意图:
| 输入 | 基线 | 候选 |
|---|---|---|
| 九个 Agent,唯一工作在第九个;limit=100 | 漏项,0 | 仍为 0,且无 warning/truncation |
| 只把第九个注册身份排到首位 | 仍为 0 | 变为 1 |
| A runnable、B 有 scoped user_gate | 总览 gate=1 | 总览 gate=0;global-gates=1 |
具体改动 / Changes
关键代码讲解
_registered_goal_agents合并注册表和 lane 候选后在 L163 截为前八个;它没有返回遗漏数量,随后汇总仍宣称没有截断。_quotas_for_goal对未指定身份的 peer 查询做 fanout;每个候选的异常或非成功 payload 被丢弃,有一个成功就不再保留失败面。单身份与非 peer 路径仍调用现有 quota owner,但失败不能被健康 lane 掩盖。_build_goal_quota在 L187-L188 遇到首个可执行或带 selected_todo 的 lane 就返回;build_summary_all随后仅用这个 quota 生成工作和 gate,因而丢掉其他 Agent 的用户阻塞。- 两个
_is_unscoped_peer_v1_quota重复消费 legacy heartbeat 字段,并回退到英文 reason 子串;显式身份未注册也用 prose 判断跳过,措辞改变与真正上游故障可能被误分类。
规格基线是 docs/reference/protocols/global-manager-command-v0.md,补充 peer-agent-runtime-v1.md。准则 unscoped_all_visible 当前 not_met:省略 Agent 不代表前八项;complete_counts_and_failures 当前 not_met:完整计数和失败覆盖不能由显示切片决定;peer_registration_order_independence 当前 not_met:顺序改变不应决定工作能否发现;quota_remains_owner implemented:没有新增写入或执行 owner。原先一 Goal 一权威读取的成本边界也应由共享批量投影解释,不能只复制两个循环而不计读取成本。
对主干的风险 / Risks
P2:第九个 Agent 静默漏项。 真实 quota 明确允许唯一第九项,global-todos --limit 100 却返回 0、warning=0、truncated=false。这会让维护者误以为没有可做的工作。最小修复是完整枚举或显式报告未覆盖,并验证注册顺序置换和显示 limit 不改变完整计数。
P2:总览丢掉另一个 Agent 的用户阻塞。 同一个 A runnable/B gated 状态,基线总览有一个 gate,候选变为零,专门的 gates 查询仍有一个。最小修复是分别聚合 runnable lane 与完整 gate 集,保留真实身份去重;回归用例必须同时断言两者。
语义与 CI 对齐
P2:必检 legacy 消费范围回归。 uv run --extra test python examples/semantic-vocabulary-drift-smoke.py 在不可变基线通过(16/17),本头失败:legacy field heartbeat_recommendation grew to 18 .py modules; budget is 17。两个重复 classifier 是新增消费者。标准 canary premerge --from-git-diff --git-diff-base 3503d823256c02bc531558f4a3bc9ea7c963d6eb 因此失败;其他四个所选 canary、编译、diff 和双语检查通过。应复用 typed identity/prompt-upgrade owner,或按既有预算规则证明必要性后处理约束,不能直接把失败转记为通过。diff-scoped advisory 没发现新 closed-set,不证明没有语义或 legacy 扩散。
验证:PASS,完整 tests/test_global_todos.py tests/test_summary_all.py 38 项;PASS,真实 File/SQLite 独立 quota 与相同状态读取;FAIL,以上三个有独立预期的反例/原生检查。初次临时夹具缺 adapter/完整 state、未声明 scheduler profile 的失败仅作夹具诊断,补齐后才用于结论。未查询、轮询或等待远端 CI;没有修改源码、领取业务工作或执行 gate。显式 agent/普通查询的既有测试通过,但不能代替新的多 lane 完整性。
我的整体评价 / Verdict
REQUEST_CHANGES,审查头 0506196b403e08f671f541b3da1aec4567f88632。long_horizon=regression:已允许的工作被顺序相关的切片隐藏;user_experience=regression:待本人处理的阻塞从总览消失。保留 quota 作为每个 Agent 的决策 owner,让 manager 只聚合投影是合理边界;当前用单 lane 代替完整 Goal、隐藏八项截断和重复 legacy 分类需要在本 PR 修正。 385 additions/17 deletions 中有 221 行测试;fanout 投影值得保留,最高价值的有界简化是复用一个 typed peer 枚举/状态入口,分开推荐项与完整集合。没有新增持久状态,不能从 status 切片推导不存在。
无渲染界面改动;检查 global-todos/global-summary/global-gates 的 JSON、Markdown consumer 与完整四文件 diff,截图不适用于此只读 CLI 改动。 真实模型采用、持续多轮公平性和完整运行成本未测;没有用本次测试数推断长期收益。 修复后须重新运行完整模块、九 Agent/混合 lane 的真实 CLI、语义检查和 premerge;此结论不涉及 merge 或授权扩展。
English verdict: REQUEST_CHANGES — unscoped fanout silently omits agents, hides a scoped user gate, and introduces a required semantic validation failure.
| continue | ||
| add_agent(as_dict(item.get("agent_lane_recommendation")).get("agent_id")) | ||
| add_agent(as_dict(as_dict(item.get("project_asset")).get("owner")).get("agent_id")) | ||
| return agents[:8] |
There was a problem hiding this comment.
[P2] 完整扫描注册 Agent,或明确返回未覆盖范围
九个注册 Agent;唯一可执行 Todo 属于第九个。 File/SQLite 真实 quota 对第九个 Agent 均 normal_delivery_allowed=true;global-todos --limit 100 返回 runnable_count=0、matched_todo_count=0、source_warning_count=0、truncated=false。仅将注册顺序改为第九个在前,结果变为 1;没有改变 Todo、配额或显示上限。 从完整注册表枚举或分页;若必须限制读取,显式携带 agent coverage/omitted/incomplete,不能把未读取判为无工作。同步检查 summary_all 的同类八项截断。 回归验证:真实 File/SQLite 九 Agent,唯一第九项;limit 100 与注册顺序置换应保持完整计数/结果,或明确报告未覆盖。
| continue | ||
| if first_ok is None: | ||
| first_ok = scoped | ||
| if scoped.get("normal_delivery_allowed") is True or scoped.get("selected_todo"): |
There was a problem hiding this comment.
[P2] 汇总全部 peer 的阻塞,不要由首个可执行 lane 代替整 Goal
Agent A 可执行,Agent B 的 Todo 有 scoped user_gate。 候选在首个可执行 scoped quota 提前返回:相同真实 File/SQLite 状态下,global-summary.open_gate_count 从基线 1 变成 0,global-gates 与 --agent-id agent-b 仍报告 1;用户无法从总览发现待本人处理的 B 阻塞。 分别聚合每个 Agent 的工作与用户阻塞,并按真实 gate/Todo 身份去重;推荐执行 lane 与完整 gate 集不得共用单个选中 quota。 回归验证:两个 Agent 的真实 CLI 对照:A runnable/B gated,同时要求总览保留 A 的工作和 B 的 gate,并与 global-gates 一致。
|
|
||
|
|
||
| def _is_unscoped_peer_v1_quota(payload: dict[str, Any]) -> bool: | ||
| heartbeat = _as_dict(payload.get("heartbeat_recommendation")) |
There was a problem hiding this comment.
[P2] 复用 typed peer 状态,修复新增 legacy 消费者造成的必检失败
两个新增 _is_unscoped_peer_v1_quota 直接读取 heartbeat_recommendation。 相同 semantic-vocabulary-drift-smoke 在不可变基线通过(heartbeat_recommendation.py=16/17),候选失败:legacy field heartbeat_recommendation grew to 18 .py modules; budget is 17。标准 premerge 因此失败;diff-scoped advisory 无新词并不能覆盖 legacy 消费者扩散。 优先共用现有 identity/prompt-upgrade typed owner,消除重复 legacy/prose 分类;如确需扩展消费范围,按现有预算决策规则给出必要性与完整成本证据后再调整约束,不能静默抬限或把失败记成通过。 回归验证:uv run --extra test python examples/semantic-vocabulary-drift-smoke.py;随后运行本 PR 的 canary premerge。
…_v1 agents Signed-off-by: LoopX Agent <337587101+loopx-agent@users.noreply.github.com>
…yped identity checks Signed-off-by: LoopX Agent <337587101+loopx-agent@users.noreply.github.com>
6e8c750 to
2c9ce29
Compare
Goal / Source
Fix manager-level read-only projections (
loopx global-todos,loopx global-summary,loopx global-gates) when called without--agent-idacrosspeer_v1multi-agent Goals.Current Gap
build_quota_should_run(..., agent_id=None)on apeer_v1multi-agent Goal returns the unscoped heartbeat guard (recommended_mode="automation_prompt_upgrade",normal_delivery_allowed=False,selected_todo=None,recommended_action="Regenerate each installed heartbeat with its registered --agent-id...").loopx global-todoswithout--agent-idreportedrunnable_count=0across allpeer_v1Goals and attached the heartbeat upgrade prompt as every Todo'snext_safe_action, whileloopx global-summaryshowed the same heartbeat prompt for everypeer_v1lane.loopx global-todos --agent-id <id>emittedquota_unavailablewarnings for Goals where<id>is not registered instead of treating them as out of scope.Observable Result & Owning Boundary
loopx/global_todos.py:agent_id is Noneandbuild_quota_should_runreturns the unscopedpeer_v1prompt-upgrade guard, fan out across the Goal's registered agents (run_history.goals[].coordination.registered_agentsand attention-queue lane owners, bounded to 8) so runnableselected_todoitems are surfaced and non-runnable Todos bind theirclaimed_byowner'srecommended_action.--agent-idis explicitly provided and a Goal does not register that agent, skip that Goal cleanly as out-of-scope rather than recording aquota_unavailablewarning.loopx/summary_all.py:agent_id is Noneand_build_goal_quotahits the unscopedpeer_v1guard, resolve the Goal's candidate registered agents (prioritizingagent_lane_recommendation.agent_idand runnable lanes) soloopx global-summaryandloopx global-gatesproject accurate lane actions and top Todos.Verification
pytest tests/test_global_todos.py tests/test_summary_all.py -q(38 passed).