Skip to content

fix(lark): preserve context without granting Turn authority - #4319

Merged
huangruiteng merged 5 commits into
mainfrom
codex/lark-manager-context-capture
Sep 14, 2026
Merged

huangruiteng merged 5 commits into
mainfrom
codex/lark-manager-context-capture

Conversation

@huangruiteng

@huangruiteng huangruiteng commented Sep 13, 2026 •

Copy link
Copy Markdown
Collaborator

Motivation / 动机

A configured Manager group could not provide useful conversation context because unaddressed messages were rejected before entering the private runtime inbox. At the same time, recovering old history must never replay an earlier Bot mention as a new authorized Turn.

已配置的管家群此前会在消息进入私有 runtime inbox 前拒绝未寻址内容,导致群聊上下文不完整;但补采历史也绝不能把旧的真实 mention 重放为新 Turn。

RFC alignment / RFC 对齐

This is an early M3 Lark adapter slice under the merged capable-manager semantic-handoff RFC (#4330), with A10 as the eventual journey anchor.

  • A context-only message is an adapter-owned Observation/material. It is not a WorkRequest, Assessment, Todo, claim, or delivery receipt.
  • Only a provider-native mention or verified reply authorizes the current Turn.
  • History catch-up preserves original addressing as provenance but clears live attention/reply authority, so urgency, settlement and prompt injection agree.
  • The existing inbox, cursor and material-review ledger remain Lark transport/context owners. They do not become the M2 collaboration lifecycle database.
  • Frontend and Lark consume the same captured-context health state; no second UI or permission source is added.
  • The 8-item / 4,000-character budget bounds one Turn projection only. Durable context retention/expiry/compaction remains an explicit follow-up and prevents this PR from claiming long-running M3/A10 completion.

本 PR 只把 Lark 可见上下文收窄成 M3 adapter 行为;不实现 M2 request/assessment/result owner,也不把一条群消息或 Codex 消息冒充已交付工作。

Behavior / 行为

  • one unique valid Manager binding may persist unaddressed non-self messages as context_only without model, reply, reaction, ACK, Todo or other effect;
  • an authorized Turn performs bounded history sync, injects up to 8 items / 4,000 characters, and settles consumed material after verified response;
  • recovered historical mentions are normalized to material-only while their provider addressing provenance remains inspectable;
  • self messages, other chats, invalid routing and ambiguous bindings remain fail-closed;
  • provider history failure degrades accurately without blocking the current authorized Turn.

Delivery receipt / 交付回执

  • Base: f4d7c9d
  • Head: 75d1524
  • Milestone / acceptance: early M3 adapter; A10 partial
  • Owner: Lark event inbox + turn-start cursor + material-review settlement
  • M2 collaboration owner: unchanged and not implemented here
  • TS T-card: not applicable; no shared control-plane writer is added
  • Authority D-card: not applicable; no Goal/provider authority promotion or default changes
  • Known remaining gate: bounded durable context retention with explicit discard reason and duplicate/restart safety

Validation / 验证

  • 154 Lark runtime, connection and turn-start tests passed on the rebased head.
  • Historical native-mention regression proves reply_due=false, attention_required_count=0, material review succeeds, and pending context is settled.
  • Maintainability ratchet: 8 passed.
  • Ruff and diff hygiene passed.
  • Dashboard production and packaged chat builds passed with the pinned frontend toolchain; packaged personal-workspace browser smoke passed (navigation-sorting, chat-recovery and typed-actions).

This changes Lark authority behavior and retains an open retention gate. It remains review-required and is not a self-merge candidate.

@huangruiteng
huangruiteng force-pushed the codex/lark-manager-context-capture branch 3 times, most recently from 1428654 to 18c633c Compare September 13, 2026 07:51
@huangruiteng

Copy link
Copy Markdown
Collaborator Author

CI found the post-rebase goal_topic_runtime module over its 1500-line maintainability budget. I moved bounded manager context selection, prompt composition, history sync, and context settlement into a dedicated manager_context owner module without changing authority semantics.

Validation on exact head e96d2fd:

  • PR-owned Lark context/runtime tests plus manager delivery/parser coverage: 161 passed
  • maintainability ratchet: 8 passed
  • Ruff and git diff --check: passed

The branch remains review-required because it changes manager/Lark authority behavior.

@huangruiteng huangruiteng left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

English verdict: REQUEST_CHANGES — the capture/authority split is well scoped, but historical Bot mentions remain actionable and cannot be settled by the new context-only path.

动机

本次 review 针对精确 head e96d2fd9c6c01145a613458bb2ac593e37f80a73(base main)进行。PR 修复了 #4318 的核心问题:在唯一且有效的 Manager 群绑定下,将可见性与 Turn 权限拆开,允许未寻址群消息进入本地私有 inbox,只有 provider-native mention 或 verified reply 才能启动 Manager Turn。manager_context 的 8 条/4,000 字符边界、历史补采、无副作用 context-only 分支,以及 dashboard 状态都与目标一致。

不过“历史补采一律 context-only,包括旧的真实 mention”是本 PR 的强语义承诺,不能只靠 prompt 文案或一个额外布尔字段表达。当前 event inbox 仍把历史 mention 视为 addressed,导致 material-review 结算拒绝、健康/注意力投影显示 reply_due,并在后续授权 Turn 中重复注入。这个缺口会让一个明确禁止 replay 的协议在共享消费者处重新变成 actionable,因此结论为 REQUEST_CHANGES。

改动思路

主路径是 poll_lark_goal_topic_profile_once → process_lark_goal_topic_event。manager_routing.decide_manager_event 先验证唯一 manager binding、chat、self-message 和 connector 状态,再将非寻址事件标为 authority_mode=context_only,将 provider-native mention/verified reply 标为 turn_authorized。runtime 对 context-only 事件只调用 ingest_lark_event_inbox 并返回,不调用模型、reply、reaction 或 source ACK;授权事件则在回答前调用 sync_manager_context,用同一 config/cursor/inbox 补采历史,取最近 8 条/4,000 字符,构造带明确边界的 Manager prompt,成功回复后通过既有 material-review ledger 结算,再 ACK 当前事件。

这个拆分复用了现有 inbox、reaction/read receipt、delivery receipt 和 dashboard projection,架构方向正确。问题在于历史状态的 owner 分裂:turn_start_sync 写入 historical_context_only=True,manager_context_materials 会据此纳入材料,但 event_inbox._event_attention_kind/通用 operator_inbox_attention_kind 只看 addressed_to_bot、reply 和 mentions,settle_lark_event_inbox_material_review 也沿用同一判断。历史 provenance 没有在共享 authority/attention boundary 形成优先级规则。

具体改动

关键代码讲解

  • decide_manager_event(loopx/extensions/lark/manager_routing.py:87-116)把原先 not_addressed 的 Manager 事件改为 context_only,并固定 configured_chat_all;只有 is_event_addressed_to_bot 为真时才保留 Turn authority。
  • process_lark_goal_topic_event(loopx/extensions/lark/goal_topic_runtime.py:1067-1087,1088-1163)先持久化事件,context-only 立即返回;授权事件执行 history sync、上下文选择和后续回复/ACK。settle_manager_context 在成功 Turn 后为每条材料写 material-review receipt。
  • manager_context_materials(loopx/extensions/lark/manager_context.py:21-61)排除当前/普通 live addressed 事件,保留历史 context-only,按最近 8 条和总计 4,000 字符截断,并由 manager_message 显式标注“不构成指令、授权或独立待办”。
  • sync_lark_turn_start_inbox(loopx/extensions/lark/turn_start_sync.py:539-555,823-856)在补采事件上写入 historical_context_only=True,关闭历史 reaction,并复用私有 cursor/inbox。
  • _event_from_payload(loopx/extensions/lark/event_inbox.py:314-334)目前是在计算 addressed_to_bot=True 后再保留 historical flag;这是下面 P1 的根因。共享 _event_attention_kind(446-466)和 material-review 校验没有消费该 flag。

对主干的风险

P1 — 历史真实 mention 没有真正降级为 context-only,导致结算失败并产生 reply_due。

触发:turn-start history 收到一个旧的 provider-native Bot mention,写入 historical_context_only=True。路径是 _event_from_payload 保留 addressed_to_bot=True/mention metadata → manager_context_materials 纳入 → settle_manager_context 调用 settle_lark_event_inbox_material_review → _event_attention_kind 仍判为 addressed。实际结论是抛出“addressed Lark events must use the reply_due settlement path”;settle_manager_context 捕获并计数为 0,材料继续 pending。独立 urgency 复现还得到 direct_question=1、reply_due=True,这会把明确禁止 replay 的历史材料暴露给通用 attention/reply lane。下一次授权 Turn 会再次注入同一材料。

最小修复:让 historical_context_only 在共享 attention classifier 和 material-review settlement 中具有明确的最高优先级(或在 normalization 时把历史记录的 addressing flags 置为 false,同时把原始 mention 保存为独立 provenance 字段)。加入端到端回归:补采真实 mention,断言 reply_due=False/material-only,授权 Turn 后 settle_manager_context 成功写 ledger 与 processed readback,并覆盖重复投递与重启。不要只把 test 的 addressed_to_bot=True 继续作为预期而不验证下游消费者。

P2 — context-only inbox 没有持久化 retention 上限。

MANAGER_CONTEXT_ITEM_LIMIT=8 与 drain_limit=8 只限制一次 prompt/排水,不限制 .loopx/inbox 中已捕获且等待未来授权 Turn 的文件数量。若群里持续有非寻址消息但很少出现授权 mention,这些事件不会 source ACK/settle,会无限累积并把过期内容留在后续上下文候选中。建议补充有界 retention/expiry/compaction 及可观察的丢弃原因;该问题不改变当前 P1 结论,但应在同一 inbox owner 内处理。

验证结果:uv run --with pytest pytest -q tests/extensions/test_lark_goal_topic_runtime.py tests/extensions/test_lark_goal_topic_connections.py tests/extensions/test_lark_turn_start_sync.py 为 154 passed;Python compileall passed。远端精确 head 为 MERGEABLE、mergeStateStatus=BLOCKED,26 个 checks 成功;本地 ruff 不可用,未重复 lint。P1 由真实 event_inbox/urgency/settlement 边界复现,不是远端环境噪声。

我的整体评价

Manager capture/authority split、history cursor 复用、无副作用 context-only 分支和前端状态是有价值且范围合适的实现。live unaddressed capture 与后续 authorized prompt 的正向行为已有良好覆盖;但历史状态只在新 helper 中被识别,在共享 attention/settlement owner 中仍会恢复为 direct attention,形成 observable drift。请先修复历史 precedence、补齐 ledger/urgency/restart 回归,再在新的 exact head 上重跑远端 checks 和真实 Lark/browser readback;修复前不建议批准。

@huangruiteng
huangruiteng force-pushed the codex/lark-manager-context-capture branch from e96d2fd to db4bec3 Compare September 13, 2026 13:42
@huangruiteng huangruiteng changed the title fix(lark): separate manager context from Turn authority fix(lark): preserve context without granting Turn authority Sep 13, 2026
@huangruiteng

Copy link
Copy Markdown
Collaborator Author

RFC reconciliation at exact head db4bec3

Rebased onto main containing #4330 and reframed this PR as an early M3/A10 Lark Observation adapter, not a collaboration request owner.

The blocking historical-mention drift is fixed: provider addressing remains historical provenance, while live addressing/reply flags are cleared. The generic urgency projector and Lark material-review settlement now both keep a recovered native mention material-only. The end-to-end regression proves reply_due=false, no attention lane, successful settlement, and zero pending context after the authorized Turn.

Validation: 154 Lark runtime/connection/turn-start tests passed; maintainability ratchet 8 passed; Ruff and diff hygiene passed.

One gate remains explicit: 8 items / 4,000 characters bounds a Turn projection, not durable content retention. Retention/expiry/compaction with an observable discard reason and duplicate/restart safety is still required before long-running M3/A10 acceptance. Authority behavior and this gate keep the PR review-required; it is not self-merged.

@huangruiteng

Copy link
Copy Markdown
Collaborator Author

Post-#4344 rebase receipt / #4344 合入后回执:base f4d7c9d, exact head 75d1524. Local evidence: 154 Lark tests, 8 maintainability tests, Ruff/diff, dashboard/chat production build and packaged personal-workspace browser smoke all pass. RFC scope remains early M3/A10 Observation adapter; durable retention/expiry/compaction is still a gate. Independent Lark-authority review is required.

@huangruiteng
huangruiteng force-pushed the codex/lark-manager-context-capture branch 2 times, most recently from 50998fe to a5fbb99 Compare September 13, 2026 21:43
@huangruiteng
huangruiteng force-pushed the codex/lark-manager-context-capture branch 3 times, most recently from 60117c0 to 50cef49 Compare September 14, 2026 03:32

@huangruiteng huangruiteng left a comment •

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Approval conclusion (author-owned PR; GitHub blocks formal self-approval)

动机

本 PR 的目标是让已绑定的 Lark 管家群保留有用上下文,同时严格区分“被捕获的背景材料”和“可以驱动一次 Manager Turn 的授权消息”。此前实现虽然限制了单次 prompt 的条数和字符数,但 pending inbox 本身没有留存/过期边界;回复传输在崩溃重试后也可能重新选择更新的材料。另一个风险是 authority_mode 以裸字符串进入运行时,缺失或未知值可能落入授权分支。当前修复覆盖了这三个可复现的边界,并保持 M2 协作生命周期不在本 PR 范围内。

改动思路

入口仍是 process_lark_goal_topic_event,复用现有 Lark inbox、material-review、delivery receipt、cursor 和 ACK 所有权。manager_routing 只产生两个明确的 ManagerAuthorityMode 值;运行时对缺失/未知值 fail-closed。Manager 上下文由 manager_context 统一负责:先从完整 pending projection 做 7 天/32 条留存整理,再取最多 8 条、总计 4,000 字符的非权威材料。发送前把精确 message id 集合写入私有 delivery receipt;重试只恢复这组 id,材料不可用时保持当前事件 pending,绝不静默替换为新到材料。留存整理通过既有 material-review settlement 完成,并额外写入带 retention_expired/retention_overflow 原因的私有 receipt,便于观测和恢复。

具体改动

  • manager_routing.py 新增 ManagerAuthorityMode 与严格解析函数,保留现有 provider mention/reply 授权来源。
  • goal_topic_runtime.py 在任何 Manager 副作用前校验模式;接入留存 projection、精确上下文恢复、delivery receipt 的 context_material_ids,原有 reply verification、effect ACK 和 current-event ACK 顺序不变。
  • manager_context.py 抽出候选过滤/有序裁剪、7 天/32 条 retention/compaction、保护未完成 receipt 引用、可观测丢弃原因,以及重试时的 exact-id 恢复。
  • manager_reply_delivery.py 对 context_material_ids 做 message-id 格式、唯一性和 tamper 校验;旧 receipt 缺少该字段时仍可读取。
  • event_inbox.py 为内部 retention/retry caller 提供完整 projection 读取(limit=0),不改变默认公开 1..100 上限。
  • 测试覆盖未知/缺失模式、40 条 churn、过期/溢出 receipt、更新材料后的 exact-id retry、历史 mention 归一化和传输失败;文档与已打包 chat 资源同步于原 PR。

关键代码讲解

  1. ManagerAuthorityMode / parse_manager_authority_mode:只接受 context_only 或 turn_authorized,未知状态在进入 reaction、model、reply 之前返回 invalid_manager_authority_mode。
  2. compact_manager_context / manager_context_projection:按时间和稳定 message id 排序,先处理七天外材料,再处理超过 32 条的最旧材料;每次 settlement 都留下 material-review 与 retention 原因记录,并保护 pending/sent receipt 正在引用的 id。
  3. pending_delivery / restore_manager_context_route:发送前固化 context_material_ids,重试按 receipt 恢复全部原材料;缺失任何 id 返回 context_materials_unavailable、不 ACK 当前事件。

对主干的风险

这是行为型变更,影响只限于启用 Manager binding 的 Lark inbox;非 Manager、direct/async Goal Topic 和默认 disabled 路径保持原逻辑。留存 settlement 复用已有幂等 ledger,失败仍会保留 pending 状态。上下文 retention 是本地私有状态,不扩大通用 inbox/工作车道契约;prompt 中的 [context-only] 仍是指导性标记,真正的授权和留存边界由枚举、receipt 和 compaction 机器执行。完整 diff 的生产热点仍由 manager_context 承载,goal_topic_runtime.py 保持在 1,500 行 ratchet 上限。当前剩余风险仅是真实 Lark provider 的网络/权限/分页行为需要远端环境验证,仓库测试不把 mock 结果当作外部可用性证明。

我的整体评价

我已按最新主干 9e2b6d425fff9b8b2ebd69a79c3d8491b12eb7b3 重新审阅整个 PR,当前 exact head 为 620d93bac531f3b19b0790a321f1839082421dc0。此前评审提出的 retention/expiry/compaction、exact selected-id retry 和 authority fail-open 三个问题均已由实现和回归测试闭环;没有遗留 blocking finding。145 个聚焦测试、ruff、py_compile、维护性 ratchet、公共边界扫描及标准 premerge canary(18 checks、0 failures)通过;GitHub 仓库必需 checks(含 DCO、构建、兼容性、测试分片、Stage2C、merge-gate)也已全部通过。独立 SonarCloud Code Analysis 状态是非阻塞的质量门禁失败,已单独记录,不影响仓库 merge-gate;我建议 APPROVE,并在作者自评审限制下以公开 COMMENTED 结论记录该判断。

English verdict: APPROVE for exact head 620d93bac531f3b19b0790a321f1839082421dc0; retention/expiry, exact context-id retry, and fail-closed authority validation are implemented and covered by 145 focused tests, the standard premerge canary, and all repository-required checks. The separate SonarCloud quality-gate status is non-blocking and failed; repository merge-gate passed. GitHub blocks formal self-approval for the PR author, so this is recorded as the author-owned approval conclusion in a COMMENTED review.

@huangruiteng
huangruiteng force-pushed the codex/lark-manager-context-capture branch 4 times, most recently from a61e961 to 620d93b Compare September 14, 2026 06:11

@huangruiteng huangruiteng left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Approval conclusion (author-owned PR; GitHub blocks formal self-approval)

动机

本 PR 的目标是让已绑定的 Lark 管家群保留有用上下文,同时严格区分“被捕获的背景材料”和“可以驱动一次 Manager Turn 的授权消息”。此前实现虽然限制了单次 prompt 的条数和字符数,但 pending inbox 本身没有留存/过期边界;回复传输在崩溃重试后也可能重新选择更新的材料。另一个风险是 authority_mode 以裸字符串进入运行时,缺失或未知值可能落入授权分支。当前修复覆盖了这三个可复现的边界,并保持 M2 协作生命周期不在本 PR 范围内。

改动思路

入口仍是 process_lark_goal_topic_event,复用现有 Lark inbox、material-review、delivery receipt、cursor 和 ACK 所有权。manager_routing 只产生两个明确的 ManagerAuthorityMode 值;运行时对缺失/未知值 fail-closed。Manager 上下文由 manager_context 统一负责:先从完整 pending projection 做 7 天/32 条留存整理,再取最多 8 条、总计 4,000 字符的非权威材料。发送前把精确 message id 集合写入私有 delivery receipt;重试只恢复这组 id,材料不可用时保持当前事件 pending,绝不静默替换为新到材料。留存整理通过既有 material-review settlement 完成,并额外写入带 retention_expired/retention_overflow 原因的私有 receipt,便于观测和恢复。

具体改动

  • manager_routing.py 新增 ManagerAuthorityMode 与严格解析函数,保留现有 provider mention/reply 授权来源。
  • goal_topic_runtime.py 在任何 Manager 副作用前校验模式;接入留存 projection、精确上下文恢复、delivery receipt 的 context_material_ids,原有 reply verification、effect ACK 和 current-event ACK 顺序不变。
  • manager_context.py 抽出候选过滤/有序裁剪、7 天/32 条 retention/compaction、保护未完成 receipt 引用、可观测丢弃原因,以及重试时的 exact-id 恢复。
  • manager_reply_delivery.py 对 context_material_ids 做 message-id 格式、唯一性和 tamper 校验;旧 receipt 缺少该字段时仍可读取。
  • event_inbox.py 为内部 retention/retry caller 提供完整 projection 读取(limit=0),不改变默认公开 1..100 上限。
  • 测试覆盖未知/缺失模式、40 条 churn、过期/溢出 receipt、更新材料后的 exact-id retry、历史 mention 归一化和传输失败;文档与已打包 chat 资源同步于原 PR。

关键代码讲解

  1. ManagerAuthorityMode / parse_manager_authority_mode:只接受 context_only 或 turn_authorized,未知状态在进入 reaction、model、reply 之前返回 invalid_manager_authority_mode。
  2. compact_manager_context / manager_context_projection:按时间和稳定 message id 排序,先处理七天外材料,再处理超过 32 条的最旧材料;每次 settlement 都留下 material-review 与 retention 原因记录,并保护 pending/sent receipt 正在引用的 id。
  3. pending_delivery / restore_manager_context_route:发送前固化 context_material_ids,重试按 receipt 恢复全部原材料;缺失任何 id 返回 context_materials_unavailable、不 ACK 当前事件。

对主干的风险

这是行为型变更,影响只限于启用 Manager binding 的 Lark inbox;非 Manager、direct/async Goal Topic 和默认 disabled 路径保持原逻辑。留存 settlement 复用已有幂等 ledger,失败仍会保留 pending 状态。上下文 retention 是本地私有状态,不扩大通用 inbox/工作车道契约;prompt 中的 [context-only] 仍是指导性标记,真正的授权和留存边界由枚举、receipt 和 compaction 机器执行。完整 diff 的生产热点仍由 manager_context 承载,goal_topic_runtime.py 保持在 1,500 行 ratchet 上限。当前剩余风险仅是真实 Lark provider 的网络/权限/分页行为需要远端环境验证,仓库测试不把 mock 结果当作外部可用性证明。

我的整体评价

我已按最新主干 9e2b6d425fff9b8b2ebd69a79c3d8491b12eb7b3 重新审阅整个 PR,当前 exact head 为 620d93bac531f3b19b0790a321f1839082421dc0。此前评审提出的 retention/expiry/compaction、exact selected-id retry 和 authority fail-open 三个问题均已由实现和回归测试闭环;没有遗留 blocking finding。145 个聚焦测试、ruff、py_compile、维护性 ratchet、公共边界扫描及标准 premerge canary(18 checks、0 failures)通过;GitHub 仓库必需 checks(含 DCO、构建、兼容性、测试分片、Stage2C、merge-gate)也已全部通过。独立 SonarCloud Code Analysis 状态是非阻塞的质量门禁失败,已单独记录,不影响仓库 merge-gate;我建议 APPROVE,并在作者自评审限制下以公开 COMMENTED 结论记录该判断。

English verdict: APPROVE for exact head 620d93bac531f3b19b0790a321f1839082421dc0; retention/expiry, exact context-id retry, and fail-closed authority validation are implemented and covered by 145 focused tests, the standard premerge canary, and all repository-required checks. The separate SonarCloud quality-gate status is non-blocking and failed; repository merge-gate passed. GitHub blocks formal self-approval for the PR author, so this is recorded as the author-owned approval conclusion in a COMMENTED review.

Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
@huangruiteng
huangruiteng force-pushed the codex/lark-manager-context-capture branch from 620d93b to d2e8b59 Compare September 14, 2026 06:33
@huangruiteng
huangruiteng merged commit a55702c into main Sep 14, 2026
44 of 48 checks passed
@huangruiteng
huangruiteng deleted the codex/lark-manager-context-capture branch September 14, 2026 06:54

@huangruiteng huangruiteng left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Approval conclusion (author-owned PR; GitHub blocks formal self-approval)

动机

本 PR 的目标是让已绑定的 Lark 管家群保留有用上下文,同时严格区分“被捕获的背景材料”和“可以驱动一次 Manager Turn 的授权消息”。此前实现虽然限制了单次 prompt 的条数和字符数,但 pending inbox 本身没有留存/过期边界;回复传输在崩溃重试后也可能重新选择更新的材料。另一个风险是 authority_mode 以裸字符串进入运行时,缺失或未知值可能落入授权分支。当前修复覆盖了这三个可复现的边界,并保持 M2 协作生命周期不在本 PR 范围内。

改动思路

入口仍是 process_lark_goal_topic_event,复用现有 Lark inbox、material-review、delivery receipt、cursor 和 ACK 所有权。manager_routing 只产生两个明确的 ManagerAuthorityMode 值;运行时对缺失/未知值 fail-closed。Manager 上下文由 manager_context 统一负责:先从完整 pending projection 做 7 天/32 条留存整理,再取最多 8 条、总计 4,000 字符的非权威材料。发送前把精确 message id 集合写入私有 delivery receipt;重试只恢复这组 id,材料不可用时保持当前事件 pending,绝不静默替换为新到材料。留存整理通过既有 material-review settlement 完成,并额外写入带 retention_expired/retention_overflow 原因的私有 receipt,便于观测和恢复。

具体改动

  • manager_routing.py 新增 ManagerAuthorityMode 与严格解析函数,保留现有 provider mention/reply 授权来源。
  • goal_topic_runtime.py 在任何 Manager 副作用前校验模式;接入留存 projection、精确上下文恢复、delivery receipt 的 context_material_ids,原有 reply verification、effect ACK 和 current-event ACK 顺序不变。
  • manager_context.py 抽出候选过滤/有序裁剪、7 天/32 条 retention/compaction、保护未完成 receipt 引用、可观测丢弃原因,以及重试时的 exact-id 恢复。
  • manager_reply_delivery.py 对 context_material_ids 做 message-id 格式、唯一性和 tamper 校验;旧 receipt 缺少该字段时仍可读取。
  • event_inbox.py 为内部 retention/retry caller 提供完整 projection 读取(limit=0),不改变默认公开 1..100 上限。
  • 测试覆盖未知/缺失模式、40 条 churn、过期/溢出 receipt、更新材料后的 exact-id retry、历史 mention 归一化和传输失败;文档与已打包 chat 资源同步于原 PR。

关键代码讲解

  1. ManagerAuthorityMode / parse_manager_authority_mode:只接受 context_only 或 turn_authorized,未知状态在进入 reaction、model、reply 之前返回 invalid_manager_authority_mode。
  2. compact_manager_context / manager_context_projection:按时间和稳定 message id 排序,先处理七天外材料,再处理超过 32 条的最旧材料;每次 settlement 都留下 material-review 与 retention 原因记录,并保护 pending/sent receipt 正在引用的 id。
  3. pending_delivery / restore_manager_context_route:发送前固化 context_material_ids,重试按 receipt 恢复全部原材料;缺失任何 id 返回 context_materials_unavailable、不 ACK 当前事件。

对主干的风险

这是行为型变更,影响只限于启用 Manager binding 的 Lark inbox;非 Manager、direct/async Goal Topic 和默认 disabled 路径保持原逻辑。留存 settlement 复用已有幂等 ledger,失败仍会保留 pending 状态。上下文 retention 是本地私有状态,不扩大通用 inbox/工作车道契约;prompt 中的 [context-only] 仍是指导性标记,真正的授权和留存边界由枚举、receipt 和 compaction 机器执行。完整 diff 的生产热点仍由 manager_context 承载,goal_topic_runtime.py 保持在 1,500 行 ratchet 上限。当前剩余风险仅是真实 Lark provider 的网络/权限/分页行为需要远端环境验证,仓库测试不把 mock 结果当作外部可用性证明。

我的整体评价

我已按最新主干 49f979b06c38b754cd6aab4a63dfd6bcc846e713 重新审阅整个 PR,当前 exact head 为 d2e8b599048a127a5fe117b67c34d7bab6ad9eea。此前评审提出的 retention/expiry/compaction、exact selected-id retry 和 authority fail-open 三个问题均已由实现和回归测试闭环;没有遗留 blocking finding。145 个聚焦测试、ruff、py_compile、维护性 ratchet、公共边界扫描及标准 premerge canary(18 checks、0 failures)通过;GitHub 仓库必需 checks(含 DCO、构建、兼容性、测试分片、Stage2C、merge-gate)也已全部通过。独立 SonarCloud Code Analysis 状态是非阻塞的质量门禁失败,已单独记录,不影响仓库 merge-gate;我建议 APPROVE,并在作者自评审限制下以公开 COMMENTED 结论记录该判断。

English verdict: APPROVE for exact head d2e8b599048a127a5fe117b67c34d7bab6ad9eea; retention/expiry, exact context-id retry, and fail-closed authority validation are implemented and covered by 145 focused tests, the standard premerge canary, and all repository-required checks. The separate SonarCloud quality-gate status is non-blocking and failed; repository merge-gate passed. GitHub blocks formal self-approval for the PR author, so this is recorded as the author-owned approval conclusion in a COMMENTED review.

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.

1 participant