Conversation
dashboard_launcher restated /api/chat/capabilities as its own module-level constant while chat_server dispatches on it. The import is inside the probe: measured on this machine, a module-level import of chat_server raises the launcher import from ~12ms to ~120ms, and the launcher runs on a port that may hold no LoopX process at all. Signed-off-by: karenchuu <25980598+karenchuu@users.noreply.github.com>
The census pins three shapes: the module-level binding, every Python literal, and the browser client's copy by file and count, so a new hardcoded fetch in either runtime fails here. Signed-off-by: karenchuu <25980598+karenchuu@users.noreply.github.com>
same_runtime_forks 11 -> 10, same_runtime_fork_definitions 25 -> 23 and same_runtime_forks_semantic 9 -> 8, measured on this revision. Signed-off-by: karenchuu <25980598+karenchuu@users.noreply.github.com>
|
CI triage for exact head The failed checks do not point to any of this PRs four changed files:
The PR changes only Current This explains the current red checks only; it is not an approval. The PR still needs exact-head review after the branch update. |
huangruiteng
left a comment
There was a problem hiding this comment.
动机
评审精确 head:afb94f9b8bf2c332a9574a32a33ddd2622dbc692;比较基线:f49b4a00870604d39fa4318da24d6dd35e72bb6e。#4447 Track A 的这个阶段解决真实 wire 身份重复:Chat server dispatch 与 dashboard launcher probe 各持有 /api/chat/capabilities,未来仅调整一边会把有效服务误判成 foreign,要求用户重复启动。浏览器仍是独立运行时,不能直接导入 Python 常量。
改动思路
launcher 在探测函数内导入 chat_server.CHAT_CAPABILITIES_PATH,保留服务端的既有 route owner,不改变 URL、capabilities schema、版本指纹校验或配置门。函数内导入避免扩大 launcher 模块加载图,但首次独立 probe 仍会加载 server 图;这不是零成本改动。当前公开 CLI 的 support_control.py 已先导入 chat_server,所以普通 dashboard/chat 入口无需新增操作或重复导入。架构 census 将浏览器的一个 literal 明确列出,同时降低现有 fork 预算。
具体改动
四文件 +196/-7,生产代码是删除 launcher 的私有定义、添加本地 import;新增 185 行 source guard,另有两处预算同步。
关键代码讲解
dashboard_launcher.py:36的_probe_existing_chat在第 53 行取得 server-owned route;HTTP 请求仍有原超时、响应大小上限和 close。malformed/foreign、stale identity、配置不匹配、空闲端口的结果及处理顺序不变。- 未改动的
chat_server.py:1309的ChatRequestHandler.do_GET仍在原 URL 返回 v1 capabilities;read-only、approval_policy=never、preview-locked Todo 写入等 authority 字段均保留。来源归一不赋予 launcher 停止 foreign listener 或绕过保护的权限。 launch_dashboard的 packaged validation → probe → matching reuse / refusal / fresh serve 链未改;tests/architecture/test_chat_capabilities_route_single_owner.py:52扫描 module-level binding,独立 route oracle 与 browser file/count 防止普通 literal 副本静默新增。该 census 的语法范围有限,不宣称识别动态拼接等任意代码。
独立验证:先用未构建 checkout 复现 base/head 相同五个 bundle-manifest 缺失失败,逐个核对测试身份及错误;没有按总数直接豁免。随后分别 npm ci --ignore-scripts、npm run build:chat,同一 dashboard/CORS/startup isolation 选择在 base/head 各 98 passed。新增架构测试和完整 semantic checks 在原 head 的相关选择中另有 213 passed;早期五失败已由上述构建后验证消除。
同一独立 harness 经真实 serve_chat、隔离 runtime/registry、实际打包 assets 和 HTTP,验证健康、capabilities、/chat/ 及 launcher reuse;七场景的完整输入/结果在 base/head 相同(只规范化随机监听端口)。故意改错 probe URL 后,独立正常复用 oracle 按预期失败。全树 semantic smoke、changed-diff advisory、改动文件 Ruff、whitespace 和公私边界检查也通过。未调用模型、外部 Lark 或生产服务。
对主干的风险
未发现阻塞问题。首次直接调用独立 launcher probe 的 server import 有可见冷启动成本:本次单次测量 base 约 2ms、head 约 1.06s,不能把作者约 110ms 的测量当成通用保证;普通 CLI 已预加载该图,重复探测不重复初始化。这个邻接边界适合在未来真正需要独立轻量 launcher 时抽取现有 wire contract,而不是现在另建通用框架。本次实际 packaged 服务复用/拒绝链已覆盖,未声称改善冷启动性能。
没有 UI 源码/视觉变化,新构建产品资源已真实服务;没有 persisted-state 或 PostgreSQL owner 变化,后端存储迁移资格不适用。浏览器 literal 和独立 schema 接受策略保留,未来跨运行时变更仍需共同资格。与同作者 work-lane PR 共享预算锚点,合并时应重新测量最新主干。未查询远端 CI;批准不代表可自合并。
我的整体评价
APPROVE。真实生产副本被删除,route 身份收敛到既有 server owner;包内用户路径、完整 capabilities 和失败诊断保持一致。已有环境缺产物的失败没有掩盖,最终在 base/head 构建后通过。相邻轻量契约/重复 census 重构已考虑并保留为实际下一次需要时的边界,不扩大本 PR。批准后会读回有效旧阻塞评审,只有已解决且授权的过期评审才撤销;不合并。
English verdict: APPROVE — server-owned route reuse preserves the packaged HTTP/launcher journey and negative classifications. The five initial missing-bundle failures were reproduced at base and resolved by building both checkouts; cold standalone import cost remains disclosed, not claimed improved.
Goal And Delivered Outcome
inventory_ratchetsnote inloopx/semantics/vocabulary_v0.json, which makes a repeated module-level constant duplicate knowledge regardless of whether the copies currently agree./api/chat/capabilitiesis a wire identity with three owners.loopx/chat_server.py:100binds it and dispatches on it at line 1309;loopx/dashboard_launcher.py:19bound its own copy and probes with it at line 60 to decide whether an already-running server may be reused; and the shipped browser build fetches the same string inapps/presentation/dashboard/src/data/chat.ts:618. The two Python copies were also a counted fork in the generated inventory, so the drift smoke already treated them as one decision spelled twice.regression_parityrow shows the inventory now reportssame_runtime_forks=10/10,same_runtime_fork_definitions=23/23andsame_runtime_forks_semantic=8/8.mainatf49b4a008.Scope And Continuation
dashboard_launcher.pylost its module-level copy and readschat_server.CHAT_CAPABILITIES_PATHinside_probe_existing_chat, and three budgets were re-anchored to the values measured on this revision. The import sits in the probe, not at module level, for a measured reason: with a module-level import, importingloopx.dashboard_launchercost 118-121ms across three samples against 10-13ms on base, because the launcher is imported byloopx/cli_commands/support_control.pyand frequently runs against a port that holds no LoopX process at all; with the deferred import the same three samples are 12-13ms. The probe path itself is unchanged, and the guard pins it behaviourally.apps/presentation/dashboard/src/data/chat.ts:618keeps its own literal. A browser module cannot import a Python constant, and that file is being changed by in-flight PR fix(chat): recover uncertain instructions after page reloads #5373. The copy is therefore declared by file and count inDECLARED_WEB_CLIENT_RESTATEMENTS, so a second hardcoded fetch, or removing the declared one without updating the census, fails the guard. A generated binding is the real fix and is out of scope here.chat_server.py:1315advertisesloopx_chat_capabilities_v1as an inline literal whiledashboard_launcher.py:21and the browser build declare the accepted set (chat.ts:143accepts both..._v0and..._v1). Advertised-versus-accepted is a per-surface policy decision, so merging them would erase a compatibility window rather than a duplicate. The one visible defect - the advertised version having no name in its owner module - is left as a follow-up with its file:line.Validation
afb94f9b8unitpassedtests/architecture/test_chat_capabilities_route_single_owner.py: 9 passed, covering the module-level binding scan, the Python literal census, the declared browser-build census, the owner's value, the launcher probe through a recordingHTTPConnection, the absence of a private copy in the launcher, and the generated inventory.integrationpassedtests/architectureplustests/canary: 1098 passed, 0 failed. Chat/dashboard selection (test_dashboard_command, bothtest_support_control_*,test_chat_server_cors,test_chat_startup_isolation,test_manager_channel_bindingand the new guard): 145 passed, 5 failed.staticpassedpython -m ruff checkclean on all changed files; configuredpython -m mypysucceeded for 19 source files;git diff --checkclean.python -m ruff format --diffflags the same pre-existing files on base and head, so no format finding is introduced.real_entrypointpassedtests/test_chat_startup_isolation.pystarts the real chat server and reads/healthzand/api/chat/capabilitiesover HTTP, so the owner's route is exercised as a live endpoint rather than a constant.regression_paritypassedtests/test_dashboard_command.py) and otherwise passes 136; the head adds 9 passing tests and no new failure. Those 5 fail for an environment reason this change cannot affect: the compiled Chat bundle is gitignored build output and is absent from the worktree, andexamples/loopx-chat-server-smoke.pystops on the same missing bundle on base and head. The drift smoke was run on both trees; every line is byte-identical except the ratchet line, which movessame_runtime_forks=11/11 -> 10/10,same_runtime_fork_definitions=25/25 -> 23/23andsame_runtime_forks_semantic=9/9 -> 8/8, withschema_version_same_runtime_forksunchanged at2/2.premergepassedloopx canary premergeover the exact four changed files completed 5 checks with 0 failures and no manual hold;loopx check --scan-pathreported the public boundary clean for the changed paths."/api/chat/" + "capabilities", passes the census, because the literal scan looks for the whole quoted value. That is a real gap in the guard, disclosed rather than papered over; the binding scan and the inventory assertion would still catch it if the consumer also bound a name.uv pip install -e ".[test]") instead ofuv sync --extra test, with Node 22.23.2 on PATH and the repository's npm dev dependencies installed, both required by the drift smoke.Frontend / Visual Evidence
Type of Change
LoopX Area
Shared-authority RFC fixture impact
N/A. This PR does not claim progress against the shared Goal Authority or TypeScript migration RFCs.
Boundary Checklist
none.Signed-off-bytrailer (git commit -s).Technical Direction
Notes For The Reviewer
same_runtime_forks10 -> 9 andsame_runtime_fork_definitions23 -> 21 re-measured on the integrated base;same_runtime_forks_semanticstays at the 8 measured here. The quoted values are measured againstf49b4a008.