refactor(presentation): share operation review semantics in TypeScript - #4364
Conversation
Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
huangruiteng
left a comment
There was a problem hiding this comment.
Approval conclusion (author-owned PR; GitHub blocks formal self-approval)
动机
#4275 已经把 human-confirmed operation 的 canonical lifecycle、claim、outcome 与 receipt 接到 Dashboard 和 Lark,但两端仍各自解释同一份 lifecycle、projection、simulation 与 result-delivery 字段。每次扩展 outcome 或 readback 规则都需要修改两个 renderer,最坏会让群卡与 Dashboard 对同一个 operation 给出不同提示。
本 PR 把这部分无副作用的展示规则收敛到共享 TypeScript read model,同时不移动 Python 的 durable writer/authority。固定 synthetic proposal 在基线 be42a4cee 与当前 head 生成的完整 Lark Card 2.0 JSON 完全相同,SHA-256 都是 1934c6ee53564dd2fcfcb67d91cc72381646b6eb70978c40ed6526bc5aea9b99。
Motivation: retire two presentation rule owners without changing the canonical operation or its authenticated group interaction.
改动思路
实现复用了原 Dashboard 的纯 compileActionReviewPlan seam,并在 loopx/control_plane/presentation/action_review_plan.ts 扩展内部 operation_review_frame_v0。它只从 canonical proposal 派生 confirmation、pending、result 三类 frame,并强制 operation ID 与 proposal ID 一致、projection 字段完整。Dashboard 直接导入;Lark 每次 card render 只通过 managed TS runtime 请求一次 frame,随后仍由 Python adapter 完成 Card 2.0 escaping、send/patch/readback。
我也验证过把 durable operation transition 整体移到 TS runtime 的替代方案;五次 transition 增加约 279ms(约 49%),因此撤回该方向。当前方案只在 Lark 渲染付出 warm median 8.442ms、p95 10.228ms,生命周期、callback provenance、唯一 claim、executor、outcome 和 result-delivery receipt 全部保留在既有 Python owner。
Approach: share only the provider-neutral pure read model; retain canonical state and effects in their existing owners.
具体改动
关键代码讲解
compileOperationReviewFrame(loopx/control_plane/presentation/action_review_plan.ts:104)验证 exact identity、typed lifecycle 和 bounded content,再生成 discriminated union;未知 lifecycle、ID drift 或 malformed field 都返回undefined。compileActionReviewPlan(同文件:168)保留原 gated/stale/applied/applying/failed precedence,并只附加可选operationFrame;operation completion 仍要求 canonicalresult_delivery。_operation_review_frame(loopx/extensions/lark/goal_channel_operation.py:86)成为薄 bridge;confirmation/result builder 各调用一次共享 runtime,校验 frame schema/operation ID 后才渲染 provider markup。workspaceProposal(apps/presentation/dashboard/src/features/personal-workspace/personal-workspace-page.tsx:546)从共享 frame 读取 title、fields、lifecycle、expiry 和 delivery verification,不再重新解析 raw operation projection。
旧 Dashboard-local reducer/types 已删除;managed handler、control-plane tsconfig、wheel package-data、双语 RFC、Lark README、Node/Python/Dashboard tests 与 packaged chat assets 同步更新。生成资产在 rebase 到 #4337 后从合并源码重建,并仅保留当前和上一代 JS bundle。
Implementation: one shared compiler now serves both shipped consumers; no parallel writer, queue, CLI, callback route, or provider state was added.
对主干的风险
最大风险是共享 compiler 改变 digest-bearing 按钮 payload、把未知 outcome 误标成完成,或让 malformed proposal 在一端继续展示。对此我用同一 fixture 做了基线/head 完整 card digest 对比;新增 negative tests 对 operation ID drift 和空 projection field 敏感;Lark tests 还断言每个 builder 只调用一次共享 frame。未来若 canonical outcome 新增种类,需要显式扩展 typed resultKind,不能从 summary 文本猜测。
验证:TypeScript typecheck 与 14 个 Node tests 通过;Lark 10 个 pytest 与 Ruff 通过;Dashboard action-review smoke 及 production/chat build 通过;clean wheel 包含 handler 与 presentation TS 源、两代受控 bundle,在全新 Python 3.13 venv 安装后真实调用 handler 通过;标准 premerge 18/18、零 warning、public-boundary clean、self_merge_allowed=true。没有发送 live Lark 消息或真实金融订单,部署后的认证 simulation-card 点击仍是产品验收,不是本 review 的合并证据。
Risk: remote required checks remain mandatory before merge, and live provider acceptance remains deliberately separate from code approval.
我的整体评价
当前 exact head 4364@3be30294069f8a62060365298163e615e89fcc7c 未发现 blocking finding。它符合 TS 重构趋势,但边界克制:TypeScript 只拥有可复用的纯展示语义,Python 继续拥有 durable state、authority、provider transport 与 receipt。相对保留两套 renderer 或把 transition 全部跨 runtime,这个切片在一致性、性能和维护成本之间更合理。
结构化 review result 已通过 capability consistency check(approval_consistent=true,无 blockers)。本结论只批准该 exact head;若 head 变化必须重新审查,合并前还要等待 GitHub required checks 全绿并运行即时 merge-readiness。
Overall assessment: the change is proportionate, domain-neutral, fail-closed, and bound to active Dashboard/Lark callers without broadening operation authority.
English verdict: APPROVE — no blocking findings on exact head 3be30294069f8a62060365298163e615e89fcc7c; merge remains subject to all required checks and immediate exact-head readiness verification.
摘要 / Summary
operation_review_frame_v0。operation_review_frame_v0.动机 / Motivation
#4275 让 Dashboard 和 Lark 成为同一 operation review seam 的两个真实消费者,但两端仍各自解释 lifecycle、projection、result kind 与 delivery verification。继续复制会让“群卡显示待确认、Dashboard 显示另一状态”成为新的漂移点。仓库的 TypeScript control-plane RFC 趋势适合承载这类 provider-neutral、无副作用的 read model;它不适合接管每次 durable transition。
#4275 made Dashboard and Lark two real consumers of the same operation-review seam, but both still interpreted lifecycle, projection, result kind, and delivery verification independently. Continued duplication would allow group cards and Dashboard to disagree. The repository's TypeScript control-plane direction is a good fit for this provider-neutral, effect-free read model, but not for every durable transition.
我验证过把整个 operation lifecycle 跨到 managed TS runtime 的方案;五次 transition 会增加约 279ms(约 49%),所以本 PR 保留 Python canonical writer,只在卡片/界面渲染时支付一次共享 compiler 成本。
I also evaluated moving the entire operation lifecycle through the managed TS runtime. Five transitions added roughly 279ms (about 49%), so this revision keeps the canonical Python writer and pays the shared compiler cost only when rendering a card or UI model.
用户入口 / User entry points
边界 / Boundaries
operation_review_frame_v0是内部 presentation read model,不是新的 wire authority。验证 / Validation
Exact base:
be42a4ceeaed73e06a7996cd13fe493212af79acExact head:
3be30294069f8a62060365298163e615e89fcc7cnpm run typecheck:control-planenode --test --experimental-strip-types tests/control_plane_ts/action_review_plan.test.ts tests/control_plane_ts/effect_runtime_handlers.test.ts— 14 passed.venv/bin/pytest -q tests/extensions/test_lark_goal_channel_operation.py— 10 passednpm run smoke:action-review-planand production/chatnpm run buildpresentation.action_review_plan.compilepassedself_merge_allowed=trueNo live Lark message or real financial order was sent by this refactor validation. Deployment plus one authenticated simulation-card interaction remains the product acceptance step; real trading remains separately authorized.