mirror of
https://github.com/sinanyuntu/trade-message-center.git
synced 2026-09-17 13:22:11 +08:00
16 KiB
16 KiB
研究:共享 OneTalk 图片合同与 Chrome Extension MAIN 链路
- 查询:核对 OneTalk 图片 canonical type/guard、MAIN raw/flat-history 解码、上传 metadata、live sent correlator、页面观察发布顺序、v5 协议常量消费者、现有测试与文档中的
width/height读写点。 - 范围:internal(仓库源码、测试、规格、GitNexus);运行态未执行。
- 日期:2026-09-11
- 协调类别:cross-cutting
- 阻塞:共享合同/协议版本 scope 必须先稳定;Chrome extension MAIN scope 才能独立收敛。extension scope 还依赖 server/harness 接受同一个 v6 frame/content 形状。
- 共享边界:
apps/onetalk-contract/src/content.ts是 image canonical type/strict guard 唯一 owner;apps/onetalk-contract/src/wire.ts是 wire version owner;apps/chrome-extension/src/onetalk/main-page/message-observer/content-decoder.ts是 raw OneTalk 到 normalized content 的唯一 MAIN decoder;send-observation.ts是 live/send correlator owner。 - 证据基线:checkout
/Users/ybf/code/trade-message-center-worktree,branchmain,HEADb47720872da147e9da791de77424007e21e1a74c(2026-09-11);产品源码/测试无 dirty path,只有本任务.trellis/tasks/09-11-remove-image-dimensions/未跟踪。GitNexus 当前索引同一 HEAD,indexed2026-09-11T02:51:38Z。 - 复用证据与缺口:复用本任务
prd.md、design.md、implement.md的 v6 严格切换和 live-confirmation 约束,以及.trellis/spec/chrome-extension/frontend/onetalk/{page-bridge,send-sop,runtime-sync}.md;GitNexus 对normalizeImage、metadataFrom、createSendObservationCorrelator的 upstream 影响均为 LOW,但索引对部分 const/type 只给出符号级关系,仍以源码搜索为准。未执行 Chromium、Bright/Mind server、PostgreSQL 或外部trade-mindruntime 验证。
发现
1. 当前实际数据流与 owner
OneTalk raw contentType=101/custom.type=7
-> decodeMediaPayload(Base64 -> UTF-8 -> JSON)
-> normalizeImage (MAIN only)
-> observedMessage (shared isOneTalkMessage guard)
-> WebSocket observer sink / page-script-entry
-> sendObservation.observe(batch.messages) [先于 observedSink]
-> Service Worker page bridge -> Bright send.confirmation
apps/chrome-extension/src/onetalk/main-page/message-observer/content-decoder.ts:175-210当前将payload.width、payload.height写入 normalized image,并用ONETALK_MAX_IMAGE_DIMENSION_PX校验;因此缺失、错误类型或超界的 raw dimension 会生成media_invalid_schema。decodeOneTalkRawContent:289-302和 flat-history 分支265-286都汇入同一个normalizeImage,不能另建 parser。apps/chrome-extension/src/onetalk/main-page/message-observer/model.ts:148-247先校验身份,再调用唯一 content decoder;只有完整isOneTalkMessage才生成带upstreamType: 1的观察消息。该边界只输出 normalized content,不能把 rawcustom.data或 raw dimensions 带出 MAIN。- live 入口是
new.ts:12-51→index.ts:9-32→websocket.ts:40-97;raw history WebSocket envelope 在index.ts:24-31被忽略,历史由 SDK adapterhistory.ts:71-143使用同一 content decoder。page-script-entry.ts:38-46,56-90在发布 Bright sink 前先调用 correlator,故 live sent batch 可以直接完成 pending send。 apps/chrome-extension/src/onetalk/main-page/message-observer/send-observation.ts:24-41,115-182的 image pending expected 当前为sizeBytes,md5, 可选width,height,fileId;matchesImage:119-125读取并比较两项 dimensions。matches:162-181保留既有顺序:目标会话 +sent+ 完整消息;有 candidate ID 时只按 ID(不回退指纹/时间),无 ID 时才使用sentAfterMs到now + 5_000ms的窗口及 image fingerprint。send-observation.ts:184-376的createSendObservationCorrelator仍是唯一 pending/终态 owner;图片预算由ONETALK_IMAGE_SEND_TIMEOUT_MS:11保持 45 秒,finish 时只允许完整 sent message 变成confirmed_sent,多 pending 匹配是send_ambiguous,错误/超时继续delivery_unknown。apps/chrome-extension/src/onetalk/main-page/image-send.ts:21-29,185-217的FinalImageMetadata与metadataFrom读取width/height并将其可选写入 expected metadata;finalMetadataFromSendFileArgs:240-255从直接参数及mediaInfo/relationInfo/fileInfo收集候选。installUploaderInterceptor:304-385在匹配tmpKey后先做 metadata/current-target fence,再调用 correlator;sendOneTalkMedia:408-592在 fetch/blob/File 后、nativesendFile前注册短生命周期 pending。生产 relation callback 的无 dimensions 形状已经在image-send.test.js:148-155注释和relationMetadata:98-103fixture 中存在,当前缺口主要是 MAIN decoder/contract 强制 live payload 带 dimensions。
2. 共享合同与公共读边界
apps/onetalk-contract/src/content.ts:5-30定义ONETALK_CONTENT_VERSION=1、媒体大小上限和OneTalkImageContent;CONTENT_KEYS.image:82-96与isOneTalkImageContent:282-296同时决定 exact-shape accepted keys。移除 dimensions 时必须同时删除 type、key list、dimension constant 和 guard reads;保留fileId/extension/sizeBytes/isOriginal/md5/previewUrl/urlScope与现有 media size/URL allowlist。apps/onetalk-contract/src/messages.ts:94-121的isValidOneTalkMessagePayload通过isOneTalkMessageContent验证 observed frames;apps/onetalk-contract/src/sending.ts:140-166的 confirmed send guard 通过isOneTalkMessage/isOneTalkCenterMessage验证完整 sent message。因此没有另一份 message/send image schema 可安全绕过共享 guard。apps/server/src/onetalk/read-projection.ts:84-110只对持久化content再调用共享isOneTalkMessageContent并浅拷贝,server source 没有独立 dimensions reader;但 server image fixtures 仍在apps/server/test/onetalk-read-domain.test.ts:395-420,478-518,由 server scope 清理后才能读取无宽高历史。- Page bridge contract 已规定 MAIN decoder 是唯一 raw boundary、ISOLATED/SW 不重解析
custom.data:.trellis/spec/chrome-extension/frontend/onetalk/page-bridge.md:64-70,111-115,193。send SOP 已规定候选 ID 优先、完整 sent fact、45 秒媒体观察和三态 fail-closed:.trellis/spec/chrome-extension/frontend/onetalk/send-sop.md:37-43,67-78。
3. width/height 全量业务读写点(当前 checkout)
- Canonical shared writer/reader:
apps/onetalk-contract/src/content.ts:7,18-30,82-96,282-296。 - MAIN raw/flat-history normalized writer/reader:
apps/chrome-extension/src/onetalk/main-page/message-observer/content-decoder.ts:6,187-210。 - MAIN upload metadata writer/reader:
apps/chrome-extension/src/onetalk/main-page/image-send.ts:21-29,185-217;不是 UI geometry。 - MAIN live correlator expected/matcher reader:
apps/chrome-extension/src/onetalk/main-page/message-observer/send-observation.ts:24-35,115-125。 - Extension test canonical/raw fixtures:
apps/chrome-extension/test/onetalk-media-content-decoder.test.js:19-28,54-70,107-136,157-191;send correlator fixtureonetalk-send-observation.test.js:169-224;image upload/callback fixtureonetalk-image-send.test.js:61-96;flat-history fixtureonetalk-websocket-tap.test.js:355-371。这些应改成 canonical 无宽高,并新增 raw dimension absent/one-sided/wrong/over-bound/present cases均产出相同无宽高 canonical content;若保留 raw evidence 字段,必须只出现在明确标注的 input fixture 中而不出现在 expected/public output。 - Harness/server 是 R1 之外的共享下游:
apps/mind-test-harness/src/harness/validators.ts:18-30和messages.ts:17-35仍验证/显示 dimensions;apps/server/test/onetalk-read-domain.test.ts的 image expected 仍带 dimensions。CSS/layout geometry(例如apps/chrome-extension/src/onetalk/main-page/conversation-id-copy.ts:27-36、action-status-tooltip.ts:47-100、harnessstyles.ts)不是消息字段,不应被全局文本替换。 - 当前源码未发现其他 extension page-bridge、Service Worker、Bright client 或 database schema 对 image dimensions 的业务读写;Service Worker 只传递已收窄消息。
apps/chrome-extension/src/onetalk/service-worker/flows/frame-writers.ts:145-176直接写 message frame,但 payload 类型来自 shared contract。
4. 协议版本消费者与升级影响
- owner/decoder:
apps/onetalk-contract/src/wire.ts:41,123-135定义 v5 常量和 frame 类型;decoder.ts:177-197对非当前版本返回onetalk_protocol_upgrade_required,不能静默剥离旧 image fields。 - shared frame creators 全部导入该常量:
connection.ts:3,185-221、conversation-sync.ts:10,271-351、messages.ts:10,177-220、contact-profiles.ts:4,165-176、buyer-facts.ts:4,401-416、sending.ts:8,173-204;index.ts:39-53对外导出。把常量升至 6 会统一改变所有 frame builders,不应只改 send/image frame。 - extension exact consumers:
service-worker/transport/bright-client.ts:3-12,232-260生成 plugin hello/heartbeat 并调用 shared decoder;service-worker/flows/frame-writers.ts:3-24,145-210手工生成 observed/sync frames;bright-client.test.js与bright-protocol.test.js使用 shared constant 验证 handshake/upgrade。 - server admission consumers:
apps/server/src/cutover-policy.ts:3,11-43、websocket/handler.ts:197-271、websocket/index.ts:70-87、websocket/connection-store.ts:123-126、http/onetalk/public-context.ts:136-170、http/onetalk/summary.ts:46-55。这些都要求 currentONETALK_PROTOCOL_VERSION;cutover-policy的 mode 字符串仍叫bright-v5(13,26,39),它是独立 release-mode label,是否改名为 v6 需由 cross-cutting owner 明确,不能误以为只改数字常量即可。 - hard-coded test consumers:
apps/server/test/observation-batcher.test.ts:53-71直接写protocolVersion: 5;apps/server/test/mind-authorization.test.ts:359-369直接以canAdmit("bright-v5", ..., 5)验证。apps/onetalk-contract/test/contract.test.ts:191-219,1295-1303和 extension/harness tests 多数引用 shared constant,但测试名称/文档仍写 v5。 - harness consumers:
apps/mind-test-harness/src/harness/contract.ts:3-36从 shared contract 注入protocolVersion,harness/websocket.ts:48-174使用注入值发送 hello/heartbeat/send;这与 image validator 是同一个 downstream release participant。
GitNexus pre-change evidence:normalizeImage upstream 4 symbols / 2 observer processes / LOW;metadataFrom upstream 3 / sendOneTalkMedia process / LOW;createSendObservationCorrelator upstream 1 (page-script-entry.ts) / LOW。它们支持 extension module 边界,但 shared contract/protocol 的实际 fan-out以源码 imports 和 frame builders为准。
候选 Scope 与依赖
- Shared v6 image contract(cross-cutting prerequisite):owner
apps/onetalk-contract/src/content.ts、wire.ts、相关 contract tests;交付无宽高 exact-shape image、v6 decoder/builders、旧 v5 明确 upgrade error。应排除 extension implementation、server migration 和 harness UI。所有消费 shared content/frame 的 writer 必须等待此 scope;旧 v5 client 不可兼容运行。 - Chrome MAIN image observation/send confirmation(本 R1 package-local implementation scope,依赖 1):owner
content-decoder.ts、image-send.ts、send-observation.ts及其 decoder/image-send/send-observation/websocket tests;交付 raw dimensions 完全忽略、无宽高 live sent 可确认、candidate ID 优先/唯一 fingerprint/时间窗/目标身份/45 秒终态不变。可排除 server persistence/read projection、harness、external Mind。该 scope 与 server migration、harness validator 的源码写入可 write-disjoint,但由于同一 shared contract 和 v6 wire prerequisite,不能在 scope 1 未稳定前开始;合同稳定后才可并行。 - 明确不属于 R1 的下游:server read projection/JSONB migration 和 harness validation/rendering 需要消费新的 canonical shape;不能由 MAIN scope 通过保留 dimensions 或兼容 parser 解耦。
Invariant 与验收探针
Static/unit probes(implement/check 可执行)
rg -n -i --glob '!**/dist/**' --glob '!**/node_modules/**' '\b(width|height)\b|ONETALK_MAX_IMAGE_DIMENSION_PX' apps/onetalk-contract/src apps/chrome-extension/src/onetalk/main-page apps/chrome-extension/test/onetalk-{media-content-decoder,image-send,send-observation,websocket-tap}.test.js:预期无 canonical/metadata/correlator业务读写;仅允许明确 raw input fixture,不能出现在 expected normalized/public content;区分 CSS geometry。pnpm --filter @trade-message-center/onetalk-contract test:contract guard 断言无宽高 image accepted、任一额外 dimension key rejected、保留 size/URL/nullable metadata 边界,旧 v5 frame 返回 upgrade error。pnpm --filter @trade-message-center/chrome-extension test:decoder 断言 raw image dimensions 缺失、单边、错误类型、超界、正常存在均得到同一个无宽高 normalized content,非法 size/URL 仍 anomaly;websocket/parse tests 断言 history/live 共用 decoder且 raw 不跨 bridge。- correlator/image tests:无 candidate ID 时仅
conversationId + sent + kind=image + sizeBytes + md5 + optional fileId + window + unique可确认;candidate ID 仍可越过时间/指纹但不能越过完整 sent guard;wrong conversation/direction、received、不完整、同图并发均不确认/send_ambiguous;relation metadata 中缺 dimensions 或带任意 dimensions 均不改变 expected。 pnpm typecheck、pnpm build、pnpm format:check、git diff --check;改协议后确认所有 frame creator/import 编译通过,并搜索 hard-codedprotocolVersion: 5/canAdmit(..., 5)。
Runtime probes(研究期间未执行)
- Chromium/CDP 隔离要求:使用无敏感测试图片、已重载 v6 extension 并重开 OneTalk tab;确认 MAIN/ISOLATED/SW build hash相同。当前已知浏览器规则要求先观察真实
page_command_result,不能把 SDK Promise、页面图片、WebSocket frame count 当成功证据。 - 最小探针:唯一同账号页面、selected 会话可与目标不同;发送流程 fetch → File →
tmpKeyinterceptor → nativesendFile→ live WebSocket sent observation。记录仅脱敏 stage/request reference;检查 live canonical content 不含width/height,并确认同一次 pending 得到confirmed_sent。 - 反例矩阵:raw payload dimension 缺失、仅 width、仅 height、字符串/负数/超界/随机 object 与正常 dimensions 各跑一次;其它
size非法、URL host/action 非法仍产生原 anomaly。并发同图两 pending 必须send_ambiguous,断线/目标账号变化/超时必须保留delivery_unknown。 - v6 deployment probe(需维护窗口,不在研究中启动):停旧 server → 执行已审查 JSONB migration → 启动 v6 server → 发布并重连 v6 extension/Mind;旧 v5 hello/frames 应收到明确
onetalk_protocol_upgrade_required,不接受/剥离旧 dimensions。生产/真实 Mind 联调当前未验证。
注意事项 / 未找到内容
docs/onetalk-image-send-observation-feasibility.md:9-25,435-459,472-554,560-578,620-648把 dimensions 写成 canonical image 和 correlator 条件;docs/onetalk-media-message-sync-prd.md:145-146,235-252也有 image contract/code;这些当前文档必须同步为无宽高版本。docs/onetalk-media-message-format-investigation.md:152-210、docs/onetalk-message-content-formats.md:301-363同时包含已验证 raw payload 样本(应保留但明确 raw dimensions 在 MAIN 边界被忽略)和旧的推荐 normalized contract(应更新/标注)。apps/server/src/onetalk/read-projection.ts、service.ts、repository/schema 没有独立 image dimension reader;它们依赖 shared guard/JSONB 通用拷贝,但历史 image JSONB 在 guard 更新后需要 migration 才可读取。R1 不改 server migration。- 与消息合同无关的 DOM/CSS
width/height(例如 conversation-id-copy 的可见矩形)必须保留;全局删词会破坏页面控件测试。 ONETALK_PROTOCOL_VERSION升级是全协议 strict cutover,不是 image-only adapter;共享常量变更会影响 auth/heartbeat/sync/profile/buyer/message/send 所有 frame。bright-v5mode label 的处理是待 cross-cutting architecture decision。- 外部参考:无新增网络/外部文档;仓库内运行态调查仅作为历史证据,当前轮次未重新启动 Chromium、服务或数据库。