mirror of
https://github.com/sinanyuntu/trade-message-center.git
synced 2026-09-17 13:22:11 +08:00
9.3 KiB
9.3 KiB
统一修复 OneTalk React 卡片观察
Goal
让已挂载的 OneTalk 订单、询盘与商品卡片均能由 MAIN world 的 React Fiber 白名单读取器产生受控的 rendered-card observation,并沿既有 bridge、durable ledger、Bright 补全事实与 Mind message.updated 链路入库和读取。基础消息事实及其同步语义保持不变。
Confirmed facts
- 已有 observer 仅接受订单 guard(
msgType=10010与originalData.cardType=9),因此询盘和商品在归一化前被拒绝。 - 真实订单通过 identity、卡片类型和模板谓词;其
productInfoList/productList项实际使用productName与productImage。现有共享商品投影仅接受title、productTitle、name,导致订单整体 observation 为null,本地 rendered-card ledger 没有记录。 - 真实询盘使用
msgType=10010与originalData.cardType=6。其 FibermemoizedProps.data含inquiryCardDTO、displayProducts/products、inquiryContent、inquiryID;商品项使用productName、productImage、productMOQ、productUnit。该样本中inquiryContent、richTextContent与inquiryCardDTO.summary相等;可见标签来自detailStr、quoteStr、actionName。 - 14 条真实
msgType=101消息中,仅一条在 Fiber 子树有props.cardType=54,因此商品必须同时满足两层 guard。该模板的props.data含title、productImage、price、moq、moqUnit、productAction、benefitFirstText、benefitSecondText与promotionTag。 - 商品
productAction.actionParams.url是无凭据、无端口、无 query/fragment 的https://chinese.alibaba.com/product-detail/...;其路径产品 ID 与hsfId一致,可经现有normalizeOneTalkProductUrl产生安全的sourceUrl与productId。 - 当前
rendered_product.product.sourceUrl错误地使用卡片图片 URL 白名单校验;该白名单不含chinese.alibaba.com,与normalizeOneTalkProductUrl的唯一允许结果不相容。因此在启用商品 reader 前,contract 必须改为以 canonical product URL 规则验证sourceUrl与productId。 - 商品
productImage与hsfImg都通过现有图片 URL 白名单,但本次样本二者相同,无法将hsfImg证明为独立的店铺图。两个值均在 Fiber 子树的 image URL props 中传递;实际 DOM 图片已被渲染器转换,无法作同值关联。用户明确决定商品只保留商品图,不保留或构造店铺图。 - 既有专用 bridge、rendered-card ledger、
rendered.card.observed/ack、服务端补全表和读取投影已经处理受控OneTalkRenderedCardContent。本 task 不改变它们的身份、ACK、冲突、授权、发布或数据库语义。 - 已确认
6be3b839新增 rendered-card ledger 的listPending()后,61df41d的 IndexedDB 索引重构删除了通用readAll(),却没有迁移该 consumer,导致 Chrome extension TypeScript check 在未定义的readAll处失败。用户已授权把这个阻塞本 task 验证的缺口作为最小前置修复。
Requirements
R1. One dispatcher, three strict readers
- 保留 MutationObserver 仅作为
.message-item-wrapper挂载触发器,且保留现有messageId + conversationCode + channelAccountId身份、会话前后不变和 base evidence 校验。 - 将当前订单专用 reader 改为按明确 classifier 分派的三个 typed reader;不得泛化地递归读取或桥接完整 props。
- 订单仅接受
msgType=10010与originalData.cardType=9,并要求已验证的订单模板谓词。 - 询盘仅接受
msgType=10010与originalData.cardType=6,并要求已验证的询盘模板谓词。 - 商品仅接受
msgType=101且同一受限 Fiber 子树存在 renderercardType=54,并要求已验证的商品模板谓词;其余msgType=101必须继续忽略。 - 未知卡、文件卡、身份不完整、会话切换、缺失模板或任一白名单字段不满足时 fail closed,且不退回 DOM 文案、节点顺序、CSS class 或 raw
originalData.params推断。
R2. Exact white-listed projections
- 订单商品投影支持已验证的
productName和productImage,并保留现有兼容字段;订单其余内容保持既有受控 contract。 - 询盘投影为
rendered_inquiry:商品名/图片、productMOQ + productUnit、inquiryContent、inquiryID和仅标签/可用性的动作信息。不得跨出 action params、callback、URL、原始 DTO 或原始 content。 - 商品投影为
rendered_product:title、productImage、price、moq + moqUnit、经normalizeOneTalkProductUrl清洗的productAction.actionParams.url,以及仅当前可见且非空的服务/促销文案。storeImageUrl必须从 shared contract、校验、fingerprint、reader、bridge payload、持久化 JSON 和测试样例中完全删除。不得桥接traceInfo、action params、action list 或产品原始对象。 rendered_product.product.sourceUrl必须由 product URL canonicalizer 验证,并与productId对应;不得使用图片 URL validator 代替产品引用 validator。- 每个 reader 必须依赖共享 contract 的文本、图片 URL、产品 URL、fingerprint 与 equality 规则;不得自行复制安全校验或构造不安全 URL。
R3. Preserve the established downstream boundary
- 三类 observation 统一走已有 page bridge、Service Worker coordinator、独立 ledger、Bright ACK 和 server supplement 流程;不得以新消息、重跑基础同步或直接写数据库的方式绕过它。
- 基础
content、消息/会话时间字段、checkpoint、history cursor、message.created和重复/冲突语义不得改变。
R4. Regression and runtime verification
- 为订单、询盘、商品各添加 reader fixture;覆盖真实字段名、strict classifier、模板缺失、身份/会话失配、文件/未知卡及非商品
msgType=101。 - 订单 regression 必须证明
productName不再使整张卡拒绝;询盘和商品 regression 必须证明只生成各自的 exact contract shape、且不含原始或可执行字段。 - 保留并扩展 observer/bridge/coordinator tests,证明 observation 仍先写 ledger,且只在基础 candidate 已确认后发送。
- 在真实 Chrome 页面无点击、无刷新地验证三类 card reader 只产生规范化 observation;数据库验证必须在对应基础消息存在、连接授权且 ACK 成功的边界下单独报告。
R5. Repair the rendered-card ledger's indexed pending query
- 把
listPending收窄为必填channelAccountId,并只读取该账号的pending_ackrendered-card ledger records;不得恢复全 storegetAll()或在内存过滤所有账号。 - 以新 IndexedDB version 只为
onetalk_rendered_card_ledger新增[channelAccountId, status]与[channelAccountId, conversationId]indexes。现有 records 必须保留,不能清库、重键、回填或改变 ACK/first-content-wins 行为。 clearConversationHistory必须在其既有 readwrite transaction 中通过[channelAccountId, conversationId]删除同一会话的 rendered-card records;这恢复其已有测试和 history rebuild 语义,不扩大清理范围。- 为由旧 v9 数据库升级的 record 保留、pending scope 查询和 conversation cleanup 添加回归;此 scope 只修复 index refactor 的遗漏,不改变 bridge、ledger 状态机、wire、服务端或业务卡 reader 行为。
Out of scope
- 不改变 rendered-card wire version、bridge envelope、服务端 schema/migration、授权、ACK/冲突状态机或 Mind 事件语义。唯一例外是 R5 的 IndexedDB v10 index-only 升级。
- 不主动点击、翻页、导航、请求额外 OneTalk 接口或改写 React/OneTalk 页面状态。
- 不采集文件、图片消息、文本消息、名片、未知卡或任何未白名单的 Fiber/DOM 字段。
- 不将订单状态变化视为可覆盖的补全更新,也不将卡片动作变为可执行命令。
Acceptance criteria
- 已挂载的真实订单可产生
rendered_orderobservation,并且实际productName作为商品标题进入受控 contract。 - 满足
cardType=6的询盘可产生完整、受控的rendered_inquiryobservation;文件卡和非询盘msgType=10010不产生 observation。 - 仅同时满足
msgType=101和 renderercardType=54的商品可产生rendered_productobservation;其他msgType=101保持忽略。 - 三类 projection 均通过 contract 验证、没有 raw content/DTO/params/callback/trace 信息、隐藏 ID 或未经批准 URL;
rendered_product的任何路径均不包含storeImageUrl。 - canonical 的
chinese.alibaba.com/product-detail/...商品引用通过 rendered-product contract;图片 URL、带 credential/fragment 的 URL、非 canonical product path 或与 URL 不一致的productId均被拒绝。 - 订单、询盘、商品的 targeted reader/observer/coordinator tests 通过,且现有 rendered-card、基础同步和历史读取回归不变。
- 真实 Chrome 只读探针确认三类卡各自命中正确 classifier 和模板谓词;端到端入库仅在不触发主动同步的前提下、已有基础消息确认时验证。
Decisions
- 商品只保存
product.imageUrl。storeImageUrl没有业务含义或运行时证据,必须完全删除;不得以null、hsfImg或任何替代字段保留该概念。