Skip to content

feat(chat): owner private project admission with native queue and recovery - #5541

Open
huangruiteng wants to merge 3 commits into
codex/personal-native-bots-20261004from
codex/native-private-chat-20261004
Open

huangruiteng wants to merge 3 commits into
codex/personal-native-bots-20261004from
codex/native-private-chat-20261004

Conversation

@huangruiteng

@huangruiteng huangruiteng commented Oct 3, 2026 •

Copy link
Copy Markdown
Collaborator

Private Chat has no ordinary project binding, and waiting for a model answer in the event handler delays follow-up admission. This increment adds Settings → Lark → Owner private Chat: independently verify one non-default App and its owner, select an authorized read-only workspace and executor, and read back listener/pending/recovery state.

The shared typed Core owns the App/audience grant, exact Session context, native Turn FIFO and stable request/stop targets. The provider supplies current provenance, reads the exact canonical source, then journals admission and delivery separately. Replies use the existing Inbox transport and provider readback. A slow Turn no longer occupies the private-message listener; later text persists in the canonical queue and another App proceeds independently. App-scoped leases reuse the existing service. Context replacement/revocation, conflicting redelivery and unknown senders fail closed; an ambiguous send without a receipt is retained for recovery instead of blindly resent.

Commands are /status, /stop and /new; setup also offers exact-revision disconnect. Rendered lark-cli text is preserved, including literal JSON text. Unsupported attachments receive an explicit response without a model Turn. No hidden Goal, new model runner, replacement scheduler or provider-owned Session authority is introduced.

Dependency: #5540, with base codex/personal-native-bots-20261004 at 1e0bedc160a5db421741cf26ff6cc8830e8fd51c. Only this successor diff is proposed here. Unmerged #5538 is neither copied nor a dependency. After #5540 merges, retarget this PR to main and requalify the resulting exact head. Runtime/authority changes remain for maintainer review and merge.

Validation on this source content:

  • 132 relevant Python tests passed; 6 focused typed tests passed. The follow-up expired/changed App identity isolation regression (1) and maintainability checks (14) passed. One unavailable App no longer hides the other verified listener; a changed owner/App identity does not restart the old binding under a different login.
  • An additional legacy companion run: 97 passed / 2 failed. Both failures (manager_waits_for_actual_turn_in_its_own_audience_session and real_chat_entrypoint_serves_while_binding_discovery_is_blocked) reproduced on unchanged exact main 99839aeb8. They remain failures, not waived checks.
  • Control-plane/dashboard type checks, packaged Chat build, CSS token checks, Ruff/configured Mypy, semantic advisory/full drift and registry IO census passed. The top-level module budget remains 147.
  • Risk-selected premerge: 5 direct and 16 selected checks passed; no self-merge authority.
  • Packaged product canary with the real Core/service and synthetic provider/protocol: desktop/narrow setup, workspace revocation/recovery, independent App completion during a slow Turn, persistent follow-up queue, exact stop, restart recovery and no duplicate verified delivery passed. Synthetic visual evidence below.
  • Separate real installed Codex/Core canary with independently verified App identities: different native threads, ordinary Sessions without Goals, and no context transfer passed. This does not qualify live Lark model delivery or mobile behavior.
  • The installed lark-cli event schema and bounded connection probe were checked. Separate real Bot-to-owner synthetic send and canonical readback passed. This verified the installed shortcut’s rendered message schema without simulating a human inbound message. Real private-message source/readback, live stop/resume, installation/login restart and phone journeys remain untested.

Scope still open: registered Agent selection, steward portfolio/long commissions, real incremental output, host media and permission callbacks. Both bindings in the canary are ordinary project conversations. This slice does not claim the complete two-role Bot outcome or promote an installation; #5540 has unresolved Python CI and a separate Release Artifacts browser timeout.

Synthetic private setup

Narrow setup

Revoked workspace

Current-head CI follow-up: the 49562a4a77206c7af333365906bce67a62c6e872 Python run finished failed (four test shards, pytest aggregate and merge gate; 74 failure entries). The newly introduced Lark projection import-boundary regression is fixed and locally validated in stacked successor #5542 by moving provider-only setup into the extension. The remaining failures are not all attributed, and this is not a CI waiver. #5542 also completes the bounded, explicitly confirmed native steward commission slice. Neither branch is promoted or self-merged.

Signed-off-by: huangruiteng <huangrt01@163.com>
Signed-off-by: huangruiteng <huangrt01@163.com>
Signed-off-by: huangruiteng <huangrt01@163.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=xhigh

动机

想从个人 App 私聊讨论本机工作区的人,需要把消息接入已有会话队列,并能看清目标、排队与恢复状态。

此前只能从本机项目对话进入;当前设置页可选择已验证 App、授权工作区和执行器,私聊文字复用原生队列,并支持状态、停止和新会话命令。

合成 App 的打包设置旅程已验证连接、工作区撤销提示、恢复、重新加载和解绑;旧群锁键与无私聊配置的鉴权路径仍有回归,Core 归属检查也失败。

本次不声称已替换真实 Bot,不验收媒体、实时模型账户或长期管家职责;上游项目对话仍需独立修复。

当前 head 的三项阻塞需要修复;真实私聊、安装服务和上游依赖资格尚未完成。

改动思路

共享授权由 TypeScript 的 binding/context 规则决定;Python 负责原子存储、HTTP 和 provider IO。请求先持久化 scoped identity,再关联已有 Chat Session/Turn 队列;准入 ACK 与最终回复分别记录并验证。设置页复用现有 Lark 入口。这个归属合理,但 provider HTTP glue 当前错误地留在 Core,必须修复。

具体改动

评审绑定 5541@49562a4a77206c7af333365906bce67a62c6e872,精确 base 为 1e0bedc160a5db421741cf26ff6cc8830e8fd51c。全 diff 共 29 个文件;包含未改动的周边调用路径一起检查,未沿用旧批准。

关键代码讲解

  • loopx/control_plane/collaboration/conversation_binding.ts:65 的 planConversationBinding / resolveBoundConversation:Own typed exact binding decisions。输入为 Revision-CAS configure and exact source;关键约束是 No private payload can manufacture authority; context change creates fresh binding。经 Python atomic binding IO adapts typed result 交给 Bound native Session context,失败由 Missing/revoked/stale scope rejects; no alternate Goal 处理。
  • loopx/capabilities/native_chat/external_conversations.py:22 的 ChatExternalConversations.admit / _admit_prepared:Durable request correlation into existing queue。输入为 Verified source/request content + current binding;关键约束是 Same scoped client identity maps to one native Turn。经 ChatSessionStore + runtime.enqueue 交给 Exact receipt/status/recover,失败由 Conflicting content denied; prepared retry resolves existing Turn 处理。
  • loopx/extensions/lark/private_conversations.py:104 的 LarkPrivateConversations.admit / reconcile:Provider source verification and separate reply effects。输入为 Fresh App/sender/chat + original source message;关键约束是 No group/unknown sender/media fallback into owner scope。经 Controller.external_conversations; real reply verification journal 交给 Original private source admission/final reply,失败由 Unknown delivery remains recoverable/held, not blind resend 处理。
  • loopx/extensions/lark/goal_topic_runtime_service.py:249 的 LarkGoalTopicRuntimeService._poll_profile consumer key:Single consumer fence。输入为 Existing enabled legacy group, no private rows, old owner alive;关键约束是 One machine/App/source consumer must own stream。经 try_exclusive_file_lock -> stream callback 交给 Listener health/status,失败由 Current key bypasses old lock; standby not honored 处理。
  • apps/presentation/dashboard/src/features/personal-workspace/private-conversation-panel.tsx:8 的 PrivateConversationPanel:Packaged owner setup/readback。输入为 Explicit selection and fresh backend list;关键约束是 Truthful unavailable state, no hidden Goal。经 Private HTTP routes and native binding store 交给 Desktop/narrow UI and persisted binding,失败由 Revoked workspace visible; restore/reload recover same binding 处理。

规范基准:docs/architecture/rfcs/app-conversation-and-async-inbox-v0.md @ 1e0bedc160a5db421741cf26ff6cc8830e8fd51c,逐项判断如下。

  • Ordinary workspace conversations: bounded implementation checkpoint:Ordinary local-owner read scope must not implicitly create a Goal or portfolio authority. → implemented。Real native Session/store tests and packaged configuration readbacks; source context is owner-only workspace_read.
  • Acceptance:Lost response after durable accept must recover the same scoped request with one logical Turn/provider call; conflicting content cannot borrow identity. → implemented。Private conversation native tests include duplicate/prepared recovery/conflict/queue full and restart with real store, external model protocol doubled.
  • Dispatch:ACK records durable queued admission rather than claiming model execution. → implemented。Existing queue/status/cancel/new source tests; receipts separate admission and final delivery.
  • Scope:Return/update remains exact original source/session/Turn; independent consumer ownership must not escape existing scope. → not_met。Real native POSIX lock pair: base stays standby; head reaches stream callback while old owner is alive.

对主干的风险

1. [P1] loopx/extensions/lark/goal_topic_runtime_service.py:252

触发:Existing group binding has no bot_app_id and private bindings are empty; a prior listener still holds sha256(profile) native lock.

观察:New raw-profile fallback acquires a different file lock and starts the stream path while the existing consumer owner is still running.

最小修复:Preserve sha256(profile) for legacy group fallback. Use consumer_ref only for explicit verified private bindings, or implement/prove an atomic single-owner migration.

回归:Hold the old key in a separate process and run real _active_profile_configs/_poll_profile at base/head with zero private bindings; current head must stay standby with no stream start.

2. [P2] loopx/chat_lark_api.py:593

触发:POST existing group connection preview or malformed request while conversation_bindings exists but contains zero rows.

观察:Valid preview body remains identical but auth status --verify calls increase1→2; malformed missing required fields now performs1 auth call instead of0 before the same400 validation.

最小修复:Validate structural/Goal requirements before provider IO; run private collision guard only when relevant private bindings exist and reuse already-required App observation.

回归:Replay real HTTP with empty private bindings: valid preview full body and auth count match base; malformed shape must reject before auth. Also cover real private binding and alias collision.

3. [P2] loopx/capabilities/native_chat/private_conversation_api.py:27

触发:Core native_chat private HTTP endpoint is imported in the shipped handler.

观察:Core imports Lark extension runtime/config and identity helpers; native architecture ownership test fails at head and passes at base.

最小修复:Move provider-specific private HTTP composition to the Lark extension; keep generic binding/session owner in native_chat and wire the handler through chatserver.

回归:uv run --extra test python -m pytest -q tests/architecture/test_control_plane_import_boundaries.py::test_lark_projection_sinks_are_owned_by_the_extension_layer; rerun real private HTTP and packaged configuration journey.

证据边界:锁键比较使用真实 native file lock 与独立旧 owner 进程,stream callback 是观察替身;这证明新 consumer 准入越过旧 fence,未声称已产生真实 Lark 双重收信。HTTP 比较走实际服务、Core 与 store,只有外部 CLI IO 为替身;合法 preview 与 malformed request 的完整响应一致,但 auth 次数分别从1→2、0→1。Core import guard 在 base1 pass,在 head 列出两个 forbidden edges。

验证:changed/native组104 passed/1 architecture failure;相邻与语义193 passed;typed binding4 passed;TS、Ruff、diff和打包 build通过,已有 bundle chunk warning保留。实际打包设置页完成 connect → root revoked → restore → reload → disconnect,原生读回验证 binding 复用与解绑;桌面和390×844视口显示同一目标和可行动状态。合成 App、模型协议和独立临时 workspace 不证明真实已安装 listener/model资格。

语义与 CI 对齐

本次依 capability 当前 policy revision18 完成 typed ownership、domain neutrality、behavior disclosure、guidance/obligation、default-off 和 authority lenses。changed-diff advisory 的空结果不覆盖动态构造;共享规则按 native checks 与反例判断。未查询、轮询或等待远端 CI,结论来自本地当前 head 的必要证据。

我的整体评价

原生队列和打包配置是一项可用的有界增量,重复准入、撤销和恢复有本地证据。长期 consumer ownership 与未开启私聊的群路径发生回归,不能以新功能正常掩盖;Core/provider 归属也需要压回现有 owner。上游#5540是独立依赖,其旧结论不替代本 PR判断,依赖更新后还需重新核验。

Future-facing pass:Useful related refactor now required: keep generic binding/session authority in TS/native_chat and move provider HTTP glue to Lark extension. Reuse existing queue and reply verification; do not add another consumer/process manager. No broad migration proposed.

English verdict: REQUEST_CHANGES. Repair the private-disabled legacy consumer lease and extra auth regressions, and move provider HTTP imports out of Core; successful private/UI paths do not erase those blockers. No CI wait or merge requested.

@mergify

mergify Bot commented Oct 4, 2026

Copy link
Copy Markdown

This pull request has merge conflicts with codex/personal-native-bots-20261004 and cannot be merged
until they are resolved. Please rebase or merge the base branch, @huangruiteng.

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/codex/personal-native-bots-20261004
# 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>/codex/personal-native-bots-20261004 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 4, 2026

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

needs-rebase Mergify: the pull request has merge conflicts with its base branch

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants