Skip to content

fix(lark): share one App listener between groups and owner Chat - #7066

Merged
huangruiteng merged 4 commits into
mainfrom
codex/lark-shared-owner-listener
Oct 22, 2026
Merged

huangruiteng merged 4 commits into
mainfrom
codex/lark-shared-owner-listener

Conversation

@huangruiteng

Copy link
Copy Markdown
Collaborator

An App already connected to group Chat could not also serve its verified owner's private Chat: setup rejected coexistence and runtime dispatch sent every event to the private route. Allow the same verified profile to share one App consumer while keeping each audience's existing admission, grants and reply path.

Group events retain group authentication and review callbacks. Private rejection never falls back to group authority; a mismatched App or competing alias still fails. Removing one route preserves the other. The SSH evidence grant editor also accepts the existing native audience channel format, with independent revocation for each audience.

Placement: existing Lark provider transport and setup adapters, plus reuse of the manager-context channel validator. Core still owns identity, Session, grants and Inbox semantics; no new capability, protocol vocabulary, listener, executor or scheduler. This is the R3/S4/S5 same-App entry repair. It does not implement remote Inbox dispatch or qualify phone-to-SSH result return.

Validation at f0a05d31af:

  • 356 focused tests passed across manager SSH evidence, private/group compatibility, Lark runtime and private conversations.
  • Existing packaged Settings → Lark completed same-App owner setup against real Core/HTTP with a synthetic verified provider: missing owner authentication rejected; keyboard retry succeeded; reload retained the steward binding; mobile fit without overflow; disconnect retained the original group configuration. No model or provider messages were sent.
  • Chat build, focused Ruff, semantic advisory and full-tree semantic vocabulary smoke passed. Public/private diff scan passed.
  • Shared main CI has unrelated test lint failures; their narrow repairs are included with the workspace validation fixes in fix(workspace): route legacy Goal status failures to storage recovery #7064. Installed authentication, listener adoption and real remote roundtrip remain unqualified.

The related refactor extracts the existing group-profile enumeration once so configuration, dispatch and review callbacks agree on which group routes still exist. App and CLI continue using existing configuration surfaces; no new frontend switch or duplicated authority.

@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

REQUEST_CHANGES,精确头 f0a05d31af39df65c796dc12fe5c6bbb75b1158a 有两项 P2 阻断。 旧群配置可以在 HTTP 返回失败后留下启用的私聊连接,冷刷新继续失败;该头还引入了必需模块预算检查失败。本轮不修改源码或合并。

动机

已用同一飞书 App 接入群聊、还要让本人从私聊继续原工作区对话的用户。旧版禁止同一 profile 的群聊与本人私聊共存;提案尝试复用一个消费者并分开权限。已存 App ID 的路径成功,但旧群配置没有该字段时,用户收到失败且留下已启用的私聊连接。真实 HTTP/Core/监听器配置路径中,有保存 App ID 的对照返回200;缺少该字段的旧配置返回400,但绑定revision从3变4并保存1条启用连接,冷刷新仍抛同一错误。不可变基线相同输入返回400但revision仍3、零新增连接且冷刷新正常。不要求此修复完成远程 Inbox、手机到 SSH 回传或全套长期路线;不发送真实飞书/模型消息,也不授予任何合并或安装权限。

用户任务是继续已有对话,设置只是必要的授权入口。复用已经验证的同一 App 应减少重复配置,不能要求先拆掉有效群连接,或让失败后出现一个无法工作的启用连接。群成员权限和本人权限仍应分别检查,不能为了少一次操作而共享授权。当前提案在已存身份的常见路径有实际收益,但旧配置的错误发生在同一个正常入口,属于本次范围内的剩余缺口。

改动思路

群事件分派与 provider 配置留在 Lark 扩展,Core 继续拥有身份、会话和授权;复用现有 group 枚举与 channel validator 的位置合理。当前 PR 是同一已验证 App 的群/本人入口修复与已有 SSH channel 兼容;必须先统一旧配置的身份观察和运行时合并,防止写入后永久拒绝。

一个 App 消费者只负责按事件种类选择原有 admission:明确 group 事件走原群路由,私聊走 Core owner 路由。拒绝不能回退到另一种权限。提取原群 profile 枚举供配置、分派与 review callback 使用是合适的同域重构;SSH 编辑器复用原严格 channel validator,也比添加新前缀或独立授权状态更小。

最小修复应留在这些现有所有者中:在写入 Core 之前,用本次已验证的身份得到与 runtime 相同的有效共享配置,并处理旧 lease 的兼容关系;若不能接入,就保持原状态或有明确原子恢复。不要从 profile 名猜 App ID,也不要把群 grant 转移给私聊。没有必要为此增加全局 Core 开关或把远程路线全部纳入本 PR。

具体改动

独立规格是修改前的 docs/architecture/rfcs/app-conversation-and-async-inbox-v0.md,固定修订 265ec9b78bc6ba76ab4dc940973fb98e364d116c。Core owns 要求身份、Session 和撤销仍归 Core,当前复用原 owner;One machine/App lease 要求同一 App 与别名复用消费者,当前正向分派/别名/standby/移除路由测试覆盖该源路径;Legacy group profiles 明确保留没有保存 App 身份的旧群配置,这一兼容要求在当前正常私聊设置路径未满足。新增双语段落不能取消旧规格;独立服务和真实远端回传资格仍分别保留。

[P2] 写入前统一旧群配置的已验证身份

_private_conversation_connect 对缺少 bot_app_id 的群配置会调用真实身份观察 fallback,因此同一 profile 的已验证 owner 可通过 guard。接着 configure 已经提交 Core binding,再调用 runtime.refresh。_active_profile_configs 第167–170行 却仍把缺少已保存 App ID 作为硬拒绝,抛出的 ValueError 被 HTTP 包装成400。

独立复现使用真实 loopback HTTP、Core binding store 和真实 LarkGoalTopicRuntimeService.refresh,仅把外部事件流换成停止屏障,不替换配置合并或写入结果。两例只切换群 target 是否保存相同 App ID,owner 验证来自同一个合成 provider:

场景 HTTP Core revision / 新启用连接 冷服务刷新
基线,旧群无 App ID 400,旧版禁止共存 3→3 / 0 正常
当前头,已存 App ID 200 3→4 / 1 正常
当前头,旧群无 App ID 400,shared listener 错误 3→4 / 1 同一 ValueError

缺少 owner 登录在两种当前头配置中均拒绝且不改 Core;所有实验都没有 provider 写入、模型调用或 Session,原群配置和 grant 保持相同。因此问题来自新的前后置身份条件矛盾,不能归咎于登录或测试 transport。作者新增 HTTP 测试将 refresh 设为空函数,且总是提供已存 App ID,故409项既有测试全绿仍未覆盖这条失败链。

请在提交 binding 前完成一致的身份/共享配置验证,失败不能留下不可用启用连接。回归必须走 HTTP→真实 Core→真实配置刷新,并测试旧配置、已存身份对照、失败无副作用及新服务冷读后的恢复;仅补 _active_profile_configs 的 helper 断言不足以保证事务边界。

[P2] 处理此头引入的模块预算失败

必需 native premerge 在当前头失败,具体是 goal_topic_runtime.py 的 module_metric_budget:Any 59,已审预算56;同命令在不可变基线通过。这不是行数超限,当前文件1681行、预算2000。新注解/分支使原类型债务增长,不能用作者所说的共享 CI lint 故障归因。

优先收敛新增边界的已有类型/所有者;若有证据表明59的增量值得保留,也可按仓库预算流程比较语义与维护成本,提交有理由的受审预算调整。单纯把阈值升到59、改名或删扫描不能证明修复。再跑同一模块 ratchet 和 native premerge,保留本次失败作为原始证据。

对主干的风险

相关 manager SSH、Lark runtime、private conversation/feedback/agents 等 409通过。另有独立真实 HTTP/Core/runtime 当前头两例及不可变基线两例,四例均按观测 oracle 通过;其中“通过”包含成功捕捉上述错误,不代表产品兼容性通过。没有把所有断言变绿当交付结论。

native standard premerge 的差异/双语/编译检查、其他4项 catalog、8项风险 smoke 和公共边界检查均通过,唯一失败明确归为 PR 引入的模块预算回归。没有获取、轮询或等待远端 CI。共享分派测试覆盖群/私聊/未知事件、拒绝不回退、App mismatch、别名、一路移除后另一路保留;SSH 两种合法 channel 及独立撤销仍走原 policy fence。它们支持权限边界保留,却不能抵消真实设置事务的失败。

现有前端 PrivateConversationPanel.act 无论操作成功失败都会重新读取 Core,因此不会完全藏住新连接,但也不能修复 runtime 的矛盾。这里未新增前端编辑器或第二份配置;原 Settings→Lark 仍是入口。默认没有新自动授权或调度行为;原共享 transport 的可用性不等于 owner/group grant,远端安装、消息采用和手机往返仍未独立验证。回滚须考虑已经发生的设置写入,不能只撤回 Python 代码就宣称已恢复。

我的整体评价

原问题值得修复,扩展/Core 的职责位置和 group 枚举提取也合理,整包规模与同一 App 的入口任务相称;但用户可用结果尚未闭环。当前长期续作会在持久化后反复卡住,设置失败的恢复成本反而增加,故结论必须为请求修改。最小修复就是统一写入前/运行时身份条件并恢复必需预算检查,不要求新路线或形式化后继任务。修正后应复审完整头及两种失败方向,不能只验证最新 helper。

已检查现有 Settings → Lark 面板及其 HTTP 调用;此 PR 不改页面布局或渲染代码,视觉评审不适用。本轮不继承作者的移动端截图结论,也未独立验证安装后的飞书往返。

English verdict: REQUEST_CHANGES at f0a05d31af39df65c796dc12fe5c6bbb75b1158a. Real HTTP→Core→runtime configuration reproduces a legacy-group setup returning400 after persisting an enabled private binding; a cold service still fails. The stored-App-ID control succeeds, while the immutable base refuses without mutation. Required local premerge also newly fails Any59>56;409 passing tests do not cover or waive these defects. Reconcile verified identity before commit and resolve the measured budget regression. No source repair, live provider message or merge performed.

huangruiteng and others added 3 commits October 23, 2026 00:19
Signed-off-by: huangruiteng <huangrt01@163.com>
Signed-off-by: LoopX Agent <337587101+loopx-agent@users.noreply.github.com>
@loopx-agent
loopx-agent force-pushed the codex/lark-shared-owner-listener branch from f0a05d3 to 6c77055 Compare October 22, 2026 16:33
Signed-off-by: LoopX Agent <337587101+loopx-agent@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

APPROVE,限完整精确 head 1d0d7648cf10c8a6cbf9164e1c4c143ee98ba444。未发现当前阻塞项。 原评审的持久化后失败与模块预算问题已核验修复;本轮还保留了中间 head 的跨进程锁失败,在最终 head 重新执行并通过。安装态飞书往返、远程 Inbox 和手机到 SSH 的结果返回仍未资格。

动机

同一飞书 App 已接入群聊时,本人应能沿现有 Settings → Lark 入口接入原工作区私聊,同时保留群成员和本人各自的准入、会话与撤销。基线拒绝这一组合;旧候选还会先发布私聊绑定,再因监听器配置不兼容返回失败。对用户而言,这会把一次设置操作变成持久的恢复负担。当前改动在原有入口完成了可用的源码增量,不要求为了复用 App 而重配一套身份或启动第二个消费者。安装态飞书往返、远程 Inbox 和手机到 SSH 的结果返回仍未资格。

我先阅读修改前的独立规范 docs/architecture/rfcs/app-conversation-and-async-inbox-v0.md,spec_revision ff9566619d0b675914a23231f4f9467e7d054f66,再审完整11文件、+301/-48。评审框架是原有 Core/扩展职责、同一 App 消费者与受众隔离。检索建议只用来提示检查首个有用结果,不把历史案例的 verdict 或“召回成功”当作本 PR 的证据,也不要求这次有限修复承担全部长期工作路线。

改动思路

群 profile 枚举从原 _active_profile_configs 提取到 _active_group_profile_configs,供设置、事件分派和审阅回调复用。_native_profile_event 只选择传输路径:明确群事件回原群准入,其他事件仍由原私聊准入判断,拒绝后不会转投另一种权限。Core 继续拥有 App 身份、Session、grant、队列和撤销;扩展只观察 provider 与本机消费者。

首次设置在提交前用本次已验证身份组合有效配置;ChatConversationBindings.configure 的可选 expected_provider_ref 在第二次观察后钉住同一 App,漂移时先拒绝而不发布绑定。旧群未存 App ID 时保留原 profile 锁,同时持有 App 锁;ExitStack 使用固定顺序获取原有内核锁,冲突进入既有 standby。consumer_ref 纳入 worker 指纹,使配置身份变化可以停止旧 worker,再沿原服务恢复。这比增加独立监听器或第二套权限状态更小,也保留升级期间旧进程的排斥关系。

具体改动

规范逐项核验如下:

  • Core owns:身份、Session、撤销和原 grant 保持原所有者。真实 HTTP 首次接入旧配置与已存身份配置均返回200,Core revision0→1、只保存一条启用绑定,冷服务能发现同一 profile。
  • One machine/App lease:最终 head 同时保护旧 profile 与 App 身份。真实独立子进程在活动消费者期间获取 App 锁失败;原进程释放后的恢复由仓库跨进程用例覆盖。没有用模拟的“锁已持有”返回值代替内核行为。
  • Legacy group profiles:不要求迁移旧群记录或补写其 App ID;没有私聊绑定的群路径也不增加 provider 身份检查。原群配置在成功、拒绝和冷读后逐字保持。profile-only 的原身份在升级期间仍被保护。
  • Group principal:本人未登录、已存其它 App、发布前 App 身份变化均拒绝,完整 Core 不变。群/私聊/未知事件、别名、移除一路和原回调用例覆盖传输隔离。SSH evidence 不另造校验器,复用原 _require_external_channel,两种原生 audience 地址分别配置和撤销,不接受缺段、额外段或通配符。
  • Installed service qualification:这是规范明确分开的后续验收。本轮没有真实飞书发送、实际模型、手机端、远程 Agent 执行或正式安装,不把源码和普通 wheel 的通过写成这些结果。

两份 RFC 同步说明现有入口、双锁与未完成的外部边界。七个 Python 变更文件分别覆盖配置、Core IO 身份观察、分派、worker 和 SSH 地址兼容;两份回归文件覆盖上述反例。没有新增 capability、持久状态机、CLI 开关或通用控制面义务。原 Settings 面板、CSS、父页面和数据调用四个实际 blob 与不可变基线相同;已检查原有错误/刷新入口,视觉评审不适用,不继承作者移动端截图作为本轮独立证据。

同输入反例与失败处理

实际边界 不可变旧版本/候选 最终 head
首次同 profile 设置,旧群无 App ID / 已存相同 App ID 基线两例400,Core保持0 两例200、Core0→1、冷发现成功
异 App / 发布前身份变化 基线拒绝且无写入 400且完整Core无写入
活动旧共享消费者期间,另一进程取同 App 锁 中间 6c77055d 竟可获取,独立断言失败 同一冻结用例拒绝另一进程,私聊单用对照也通过
没有共享配置,普通路径完整结果 5819字节JSON 逐字相同、相同hash

中间候选551项相关测试通过,仍被独立内核反例推翻,故没有沿用其批准,也未发布旧 head 结论。新提交的 service、指纹、跨进程测试与文档全部重读;与中间头相同的七个 blob 及原 reply 方法有明确失效/复用记录,最终重新运行受影响282项测试、HTTP和内核反例。未把未标记的旧执行结果算成最终 head 全套通过。

对主干的风险

主要风险在于配置发布和 worker 生命周期之间的错位、别名跨进程竞争、以及群事件误入本人权限。当前真实 HTTP→Core文件→生产 refresh/冷发现检查覆盖成功、缺登录、异App及晚变化拒绝;实际OS锁覆盖第二进程。未共享的 inactive、旧/已存身份群聊、私聊单用路径,以及原 SSH preview/commit/revoke 的完整5819字节输出,在同输入基线/本头逐字一致,没有仅比较状态码。

最终 head 的282项相关测试和6项独立HTTP/内核检查通过。构建实际Chat bundle后,普通2.1.0 wheel 在独立 target 重跑同6项,通过且712个已加载产品模块全部来自该 wheel。首次 wheel 构建因复用工作区的前端 bundle 陈旧而按门拒绝;执行正常 npm ci/build 后才重新构建,没有跳过包检查。Ruff、diff-scoped advisory与完整语义 smoke通过;空 advisory 不代表覆盖动态语义。

标准 native premerge 六项直接检查、十四项所选检查通过,零人工hold,原 Any59>56 的预算失败已消除。没有获取、轮询或等待远端CI。原失败保留,当前通过也不替代独立合并授权或readiness。原配置文件、provider行为和用户实际安装均未被本评审改写。

我的整体评价

最终完整头解决了同一正常入口的兼容与恢复问题,机制集中在既有 Lark provider/原Core IO/内核锁;group枚举提取是合适的同域整理。没有留下必须另建控制面的理由,也不因无模型效果测量而阻断确定性的传输修复。验收是可用设置、可恢复冷发现和真实互斥,不是测试数量本身。

原评审的两项问题和中间候选的新互斥缺陷均已逐项对照当前代码与执行,当前没有未解决阻塞项。原讨论应保留;任何旧阻塞评审的撤销仍须核对当前授权、GitHub实际权限和DISMISSED回读,批准本身不是撤销/合并权限。最强未测仍是安装态真实provider回传与原生Windows内核执行;长期总成本、真实模型采用和手机远程完成也不在本次证明内。

English verdict: APPROVE at 1d0d7648cf10c8a6cbf9164e1c4c143ee98ba444. Real HTTP/Core/cold discovery, same-input baseline counterfactuals and real cross-process App fencing validate the repaired same-App owner/group entry. Current282 tests, six independent source cases, six ordinary-wheel cases and native premerge pass; ordinary outputs match the base byte-for-byte. Earlier candidate failures remain recorded. Installed Lark/model/mobile/remote return and native Windows execution remain unqualified. No merge or install performed.

@huangruiteng
huangruiteng merged commit 04240f3 into main Oct 22, 2026
26 of 40 checks passed
@huangruiteng
huangruiteng deleted the codex/lark-shared-owner-listener branch October 22, 2026 17:15
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