Files
photo-live/docs/plans/progress/UI04-验收记录.md
T

289 lines
22 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# UI-04 验收记录:嵌入组件自动上滚照片窗
对应方案:[2026-09-22-UI04-嵌入组件上滚照片窗高保真实施方案](../2026-09-22-UI04-嵌入组件上滚照片窗高保真实施方案.md)
执行日期:2026-09-22 起
交付目录:[docs/designs/ui04-implementation/](../../designs/ui04-implementation/)
## 0 基线与保护
- 基线 commit:f435d7b(docs: UI-03 acceptance record)+ 本记录随 E00 提交。
- 工作树既有改动保护:E00 起始时工作树存在 **UI03R(App 高保真还原)未提交改动**
(apps/mobile/*、apps/mobile/android/*)——与本任务文件集(packages/embed-loader、
apps/viewer、apps/admin、packages/contracts、services/api)不相交;全程不暂存、
不 reset/clean、不 checkout 这些路径。
- 本任务新入库文件:docs/designs/embed-widget-*-2026-09-22.{png,md}(设计稿三组)、
docs/plans/2026-09-22-UI04-*.md(方案)、docs/designs/ui04-implementation/**(证据)。
## 1 E00 基线(v1 现状采集)
- 现状代码核对:loader(packages/embed-loader/src/loader.js 424 行 + params.js 197 行);
viewer 嵌入页(EmbedPage.vue + pages/embed/{EmbedCarousel,EmbedStage,EmbedFooterBar};
embed/{useEmbedFeed,feed,postMessage,images}.ts);实时(realtime/ws.ts RealtimeClient,
likes.burst 契约见 packages/contracts/src/realtime.ts);API 侧 embed(cn 管理)与
embed-ov(ov 公开数据,settings 归一化投影);admin embed-slots 五视图。
- v1 运行截图(跨源宿主 127.0.0.1:3999 ← viewer 5175,slot 绑定 6 张种子照片):
- [v1-desktop-baseline.png](../../designs/ui04-implementation/reference/v1-desktop-baseline.png)
- [v1-mobile-baseline.png](../../designs/ui04-implementation/reference/v1-mobile-baseline.png)
- v1 尺寸实测(getBoundingClientRect,viewport 1440×900 / 390×844):
| 端 | 元素 | 尺寸 |
|---|---|---|
| 桌面 | wrapper/iframe(md) | 320×339(宽度 md=320;高度为 iframe resize 上报的内容高) |
| 手机 | 收起把手 | 97×44 |
| 手机 | 展开 wrapper(sm 强制) | 280×309 |
- v1 行为登记:窄屏(<480px)默认收起 + 强制 sm;配置优先级 data-* > config 消息 >
默认;postMessage 白名单 {resize,collapse,expand,config,destroy};轮询 30s + ETag
304 + 失败退避 ×5;destroy 于 404/410。
- 采集方式:临时 Playwright 规格(复用 embed-crossorigin 夹具模式,种子经 e2e helpers
直种 cn 库 + flushSync/flushOutbox 同步 ov),采集后已删除;本地栈复用既有进程
(compose 容器已运行 26h+,cn:8080 / ov:8081 / viewer:5175 复用)。
## 2 版本与兼容策略(E01 定案登记)
- **入口形态**:新发布物 `/embed/v2/loader.js`(源 src/loader-v2.js,v1 源 loader.js 冻结
零改动,双产物同 build/sync 脚本);iframe 复用同一路由 `/embed/:slotToken` + 白名单
版本查询 `v=2`(v1 loader 不拼 v → 旧 carousel 分支,旧 v1 接入零变化)。
- **契约扩展**(全部可选、响应恒归一化全集):EmbedSlotSettings += `displayMode`
(carousel|vertical-stream,默认 carousel)、`scrollSpeed`(8..32 CSS px/s,默认 16)、
`reactionsEnabled`(默认 true);事件载荷 SlotSettingsPayload 同步可选字段。
- **缺省语义**:契约/服务端缺省 displayMode=carousel(存量记录读取归一为旧模式,
不一夜切换);管理端新建默认 vertical-stream 由表单显式提交(§8.2)。
- **v2 尺寸硬性**:loader 侧 V2_WIDTH/V2_HEIGHT=195/280 常量;size/intervalMs/imageFit
不进 v2 配置面(data-* 不解析、snippet 不生成、iframe 布局忽略);resize 消息 v2 忽略。
- **E01 证据**:v2 跨源宿主桌面/手机双端 getBoundingClientRect 实测 195×280(e2e
embed-v2.spec.ts E01 出口门 2 用例);ov 公开端点响应含新字段全集(实测 200);
v1 回归 20 e2e 全绿(EMB-A14 部分证据);loader 36 测试(+9 v2 参数面)。
## 3 任务进度
- [x] E00 基线(本记录第 1 节)
- [x] E01 契约和版本骨架(第 2 节;改动面:contracts openapi+events+gen、api dto/
embed.service(cn 管理与 ov 投影共用归一化)、embed-loader params+loader-v2+build/sync、
viewer EmbedPage v=2 分支+EmbedStream+stream.ts+i18n、admin 类型+utils+snippet v1/v2 版本选择)
- [x] E02 静态高保真样板(登记见下)
- [x] E03 连续滚动(登记见下)
- [x] E04 操作和生命周期(登记见下)
- [x] E05 实时气泡(登记见下;含效果示例 embed-preview-2026-09-22.html 对齐)
- [x] E06 管理预览与接入(登记见下)
- [x] E07 验收(登记见下;矩阵见第 5 节)
### E02 登记(2026-09-22)
- 真实摄影素材:e2e/fixtures/photo-01..08.jpg(picsum 固定 seed 下载,800×500 ~
1200×400 混合比例);helpers.seedPhoto 扩展 thumbBytes/browseBytes 注入(向后兼容)。
- 静态测量(e2e/embed-v2.spec.ts E02 块,全部断言过):
- wrapper 195×280 / radius 12px / border 1px rgba(255,255,255,0.8) / bg rgb(16,22,30)
/ box-sizing border-box(§2.1 全项);
- 首图(最新序)193 宽 ×135 高(1000×700 原比例);track rowGap 3px(§2.2/2.3);
- 收起:44×44 触区锚定右上、可视圆 24×24 内缩 6px;全窗唯一 button(§2.4);
- 上下 12px 弱暗渐隐(rgba(16,22,30,0.12),§2.3 可选项落地)。
- 截图:actual/desktop/e02-static-desktop.png、actual/mobile/e02-static-mobile.png
(390×844 展开态同尺寸 195×280)。
- 存量偏差修复登记:admin eslint globals 缺 ElNotification(模板 .auto-import.json
生成缓存不含、types/import d.ts 已声明——login/index.vue 存量问题,UI-04 前即红;
最小修复 eslint.config.mjs globals 补 readonly)。
- E02 出口确认:无标题/底栏/页码/左右按钮,图片窗口形态与目标图一致(截图对照)。
### E03 登记(2026-09-22)
- 引擎架构:纯状态机 stream.ts(advanceStream 单帧推进/advanceStreamFor 分块/
anchorRebuild 锚定重建/removePhoto 移除;窗口数学、循环代次 key、DOM 上限 16/
队列上限 30/缓冲 480px 常量)+ 编排 useVerticalPhotoStream.ts(rAF 积分、transform
逐帧直写 DOM 不经响应式、退役/补尾低频同步渲染列表、ResizeObserver 重测锚定、
单张静态不 rAF、恢复重置 lastTime 不补跑;stepForTest 受控时间测试接口)。
- 单测:embed-stream.spec.ts 14 用例(比例防御/窗口覆盖与副本 key/匀速积分与 dt
封顶/退役边界与多帧跨界/锚定保位/新图入未显示区/锚移除回退/removePhoto 保位/
装配推进 transform/单张静态/dropPhoto 清理)——全仓 viewer 236 绿。
- 动态 e2e(embed-v2.spec.ts E03 块):①16px/s 实测 2s 位移 32px(30-34 断言过);
②12s 逐 250ms 采样跨退役边界:匹配照片连续性 -4px/250ms、最大误差 <2.5px;
③20s DOM 实例恒 ≤16;④32s 录屏 recordings/e03-scroll-32s.webm(含 ≥4 个循环
边界,7.7s/条退役节奏)。
- 修复记录:anchorInPhoto 方向(-acc);transform 写入 0.01px 取整(浮点噪声不进
DOM);单张照片窗口副本刷屏违 §3.2.8 → rebuildItems 单张特判恒一实例。
- E03 出口确认:不瞬移(边界连续性断言)、不露空白(匹配采样全程有内容)、
DOM 不无限增长(上限断言)。
### E04 登记(2026-09-22)
- 暂停原因集合(§4.2):Set 管理(hiddenDocument/offscreen/hoverFinePointer/
focusWithin/pointerActive/manualScroll + reducedMotion/userPaused/active 经 running
闸门汇聚到引擎);瞬态原因清空后 500ms 恢复(scheduleResume 复评);hover 仅
(hover:hover)+(pointer:fine) 媒体查询命中才生效(触摸不粘滞);Space 为用户显式
暂停不自动恢复;aria-live 播报(streamPaused/streamResumed,视觉隐藏不抢布局)。
- 点击语义(§4.1):pointerdown 锁定 data-photo-id;位移 >8px 抑制 click(拖动同时
以 nudgeOffset 跟手平移);pointerup 校验锁定目标一致才放行;照片下线清锁定目标。
- 手动查看(§4.3):滚轮/拖动/上下方向键经引擎 nudgeOffset 平移有限窗口(夹取
窗口范围,不重放历史;实现选择登记:不切换 scrollTop DOM 模式,transform 单一
路径满足无跳变/有限 DOM/锚点恢复);viewport touch-action none 承接触摸手势。
- 键盘(§4.2):viewport tabindex=0 聚焦;Space 暂停切换 / Escape 收起 / Arrow±60px
手动;不抢 INPUT/TEXTAREA/SELECT。
- e2e(E04 块 5 用例全过):悬停冻结+离开恢复;点击弹窗 URL 命中 /p/{photoId};
拖动 30px 不开弹窗;Space 暂停不自动恢复+Escape 收起(宿主把手出现/iframe 隐藏);
槽停用 destroy 无残影(data-poll=1000 加速)。
- E04 出口确认:小窗可操作(暂停/手动/键盘/点击四通道),动画不造成点错照片
(点击锁定+拖动取消断言)。
### 效果示例对齐登记(2026-09-22,用户指定 docs/designs/embed-preview-2026-09-22.html)
以效果示例为准重调的实现值(方案值域内的具体冻结):
- 初始偏移 32px(顶部露首照上缘片段,示例 offset=32;单张仍完整展示);
- 心形:实心 SVG 心、尺寸 12/16/20 轮转、双色 #FF6B7A/#FF8B98 交替、右缘
10/20/30、漂移 {-8,5,8}px、旋转 -5°→6°、scale .8→1.05、上浮 110px、
1.6s ease-out(透明度 0/.85/.75/0)、drop-shadow——ReactionLayer 用非 scoped
样式块(createElement 粒子无 data-v 哈希,scoped 选择器不命中——踩坑登记);
一批 ≤3 颗、颗间 300ms 错峰、同屏 ≤8;
- 拖动 1:1 跟手(去 0.5 系数);方向键 ±40;聚焦小提示 focus-tip;
- 启动闸:首窗图片 decode + 500ms 静置(decode 原因位);
- 手动滚动双向回绕(示例 translate 负向 prepend 分支——stream.ts manualScroll);
- loader v2:把手 100×44/圆角 22/1px #e3eaf2 边/白底/蓝图标 16+12px 文案;
默认水平偏移 ≤599px 视口 12px;收起钮 − 字形 19px(#ffffffd1 底)。
### E05 登记(2026-09-22)
- 架构:纯函数 reactions.ts(heartsForDelta 抽样 1→1/2–5→2/更大→3;BurstDeduper
TTL30s/容量200;PendingVisibleCache 5s/50 条;EmissionThrottle 250ms 合并封顶3)
+ 编排 useEmbedReactions.ts(复用 RealtimeClient 只读订阅 album.publicToken——
不经 useAlbumRealtime 带出观众页副作用;换绑停连清态;失活 10s 宽限断连;
WS 断线不伪造气泡)+ ReactionLayer.vue 粒子层(§5.1 值域 + 示例冻结值)。
- 归属(§5.2):burst → 照片可见(交集 ≥20px)→ visibleRectOf 交集下侧-10 出泡;
不可见 → 5s 缓存转可见补放;收起/隐藏/换绑/reducedMotion 清粒子。
- 单测:embed-reactions.spec.ts 8 用例——全仓 viewer 244 绿。
- e2e(E05 块 2 用例 + 录屏):真实公开路径点赞(另一上下文 POST likes)→
心形出现于被赞照片交集下侧区间(EMB-A09);组件自身零点赞/浏览提交
(网络断言,EMB-A15);16s 真实点赞节奏录屏 recordings/e05-hearts-16s.webm。
- E05 出口确认:两上下文真实点赞触发正确图气泡(归属区间断言通过)。
### E06 登记(2026-09-22)
- 表单(SlotFormDialog):展示模式单选(照片上滚/旧版轮播;新建默认新版);
v2 字段组 = 固定尺寸只读「195 × 280」+ 上滚速度滑杆(8-32,实时值展示)+
点赞气泡开关;v1 布局字段(尺寸/间隔/适配)v2 下隐藏(§7.2「不保存后偷偷
生效」,切回旧版恢复编辑);位置/偏移/层级/语言/默认收起两模式共用。
- 真实组件预览(§8.2):EmbedSlotPreview v2 分支内嵌 viewer `/embed-preview`
iframe(新增路由,meta.layout embed)——渲染生产同源 EmbedStream/引擎/气泡层,
样例数据为 picsum 固定 seed 真实摄影(与 e2e fixtures 同比例);配置经
postMessage {type:config} 实时更新(不整页重载);「模拟点赞事件」按钮在
预览工具区(不在实际组件),经 simulateBurst 注入真实校验管线。
- 隔离(§8.2 红线):预览页零请求零订阅(preview 模式禁用 WS;不 fetch feed、
不上报浏览、不提交点赞);未保存草稿仅存在于表单/预览内存。
- 代码生成:displayMode=vertical-stream → /embed/v2/loader.js(E01 utils 已就绪,
EmbedCodeDialog 自动生效);data-speed/data-reactions 仅非默认生成。
- 文档:README-embed.md 增 v2 章节(接入/硬性尺寸与停靠/交互与限制/产物与
版本缓存说明)。
- 测试:admin vitest 83(+1 v2 placement:恒 195/无 sm 降档/mobile 默认收起;
v1 用例固定 carousel 后原断言保持);admin e2e 5(v1 用例先切 carousel 保
留回归 + 新增 UI-04 v2 全链:表单字段组/预览 iframe 内 .stream-viewport/
模拟点赞出心形/v2 代码卡/绑定后 ov settings 投影 displayMode+scrollSpeed=24
+reactions);viewer 244 / v2 e2e 16 全绿。
- E06 出口确认:后台保存与第三方跨源实际效果一致(admin e2e ov settings
投影 + viewer e2e 真实宿主效果两条链均有证据)。
### E07 登记(2026-09-22)
- 矩阵补齐 e2e(embed-v2.spec.ts E07 块 7 用例全过):A01 四视口恒 195×280;
A02 狭窄收缩不溢出 + 双槽纵排 12px 间距不重叠;A03 单图静态(transform 恒定
+ 单实例)/空相册空态收起可用/两图矮片循环副本(DOM>2);A04 破图 onError
受控移出窗口且其余照片继续滚动;A07 reducedMotion 停自动滚动 + 方向键手动
可用;A11 宿主伪造 expand/collapse 消息无效;A12 敌意全局 CSS
(box-sizing/border !important)下尺寸保持——loader v2 几何关键属性升级为
inline !important 反制 + 同槽重复 script 标签去重。
- 全量回归:根级 lint/typecheck/test 12 包全绿(api 56、viewer 244、admin 83、
loader 36、worker 14、contracts 29 等);viewer build 产物正常;三套嵌入
e2e 合跑 43/43(v2 23 + v1 embed 14 + crossorigin 6);admin embed-slots 5/5。
- 性能记录(§12,不编百分比):loader v2 9,885B / gzip 3,959B(v1 对照
9,462B / 3,733B);嵌入页首屏数据请求 = 1×GET public embed-slots(后续 30s
ETag 轮询,304 零负载)+ reactions 开启时 1×WS 只读连接(E05 网络断言:
零点赞/浏览提交);组件仅渲染可见窗口 + 缓冲实例(≤16,20s 断言)。
- 静态对照:actual/desktop/e02-static-desktop.png、actual/mobile/
e02-static-mobile.png(全链终态重采)vs 目标图(设计对照结论见 E02 节);
动态证据:recordings/e03-scroll-32s.webm(≥4 循环边界)、
recordings/e05-hearts-16s.webm(6 次真实点赞节奏)。
- 存量失败登记(非 UI-04 引入,干净 HEAD 可复现):journey.spec「processPhoto
已发布」与并行会话/残留 worker 的队列消费竞争(本任务多次清理游离 worker;
记忆库亦有登记);likes.spec view-count 精确断言与并行会话 AlbumHeader
Unicode 图标(◉)改动冲突——本任务以 toContainText 最小修复。两处均已
在本轮全量中分别验证:journey 失败与工作树无关(stash 后 HEAD 复现),
likes 修复后通过。
- 并行会话混入登记:E06 admin 侧中间态被并行会话 eebf3b3 卷入(其提交信息
为 users list);本任务 3bba8d1 携带最终态补齐。本轮 prettier 顺带格式化
并行会话遗留的两文件(useAdminUserPages.ts / users/index.vue,纯格式)。
## 4 测量与证据索引
- 尺寸实测:E02 块断言(195×280/半径 12/边 1px/border-box/首图 193×135/缝 3px/
收起 44/44+24 可视)+ E07 多视口;基线对照见第 1 节 v1 表。
- 位移:16px/s 实测 2s=32px(30-34 断言);边界连续性 12s 采样最大误差 <2.5px。
- 资源上限:DOM 实例 20s 恒 ≤16;数据队列 ≤30;粒子同屏 ≤8、发射 ≥250ms。
- 产物体积:loader v2 9,885B/gzip 3,959B(v1 9,462B/3,733B);viewer 构建
JS 241KB/gzip 84KB(含观众页全量,非嵌入页独立分包)。
- 首屏请求:1×GET embed-slots(30s ETag 轮询)+ 1×WS(reactions 开);
E15 零提交断言。
- 截图/录屏:actual/desktop|mobile/e02-*.png;recordings/e03-scroll-32s.webm、
e05-hearts-16s.webm。
## 5 验收矩阵 EMB-A01…A16
| 编号 | 场景 | 状态 | 证据 |
|---|---|---|---|
| EMB-A01 | 多视口固定尺寸 195×280 | 通过 | E01 门(桌面/手机)+ E07 四视口(320/430/768/1920) |
| EMB-A02 | 狭窄/横屏/安全区/多实例不越界 | 通过(横屏=代码路径) | E07 狭窄收缩+双槽 12px;safe-area=env() calc(loader 源码);orientationchange→onViewportChange 重排 |
| EMB-A03 | 横/竖/全景/单图/0图/2图短循环 | 通过 | 混合比例 fixtures(E02/E03)+ E07 单图静态/空态/两图副本 |
| EMB-A04 | decode 慢/破图/签名到期/304/失败恢复 | 通过(分级) | 破图=E07 onError 移出;decode 闸=启动门(实现+E02 静置);304/签名=feed 既有链(v1 e2e 14 + 单测)复用 |
| EMB-A05 | 循环锚定 + DOM 上限 | 通过 | E03 边界连续 <2.5px + 20s DOM≤16;锚定单测(幸存保位/新图入尾/移除回退) |
| EMB-A06 | 隐藏/删除/关闭/换绑/停用清理 | 通过 | 停用→destroy E04 e2e;照片隐藏/换绑=feed merge/anchorRebuild 单测 + v1 A22 e2e(同管线) |
| EMB-A07 | 点击/拖动/悬停/键盘/reducedMotion | 通过 | E04 五用例(弹窗深链命中/拖动取消/Space/Escape)+ E07 reducedMotion |
| EMB-A08 | 收起展开/记忆/默认收起/后台配置更新 | 通过(记忆=同机制复用) | E01 手机默认收起+展开同尺寸、E04 Escape/把手;收起记忆=sessionStorage 同 v1 键(v1 e2e 覆盖机制);config 动态=loader params 单测 + v1 同管线 e2e |
| EMB-A09 | 双上下文真实点赞/重复 burst/错相册/不可见归属 | 通过 | E05 e2e 真实点赞归属;去重/错相册(房间隔离)/不可见缓存=单测 |
| EMB-A10 | WS 断线不假造气泡 | 通过(设计+单测级) | 无伪造路径(useEmbedReactions 仅真实帧驱动 + ingestForTest 显式测试口);断线=照片轮询独立(实现结构);真断线演练随 P5 T8 |
| EMB-A11 | 真跨源 + 消息伪造拒绝 | 通过 | 全部用例宿主 3998/3999 真 http 跨源;E07 伪造 expand/collapse 无效 |
| EMB-A12 | 宿主全局 CSS/重复 script/SPA 移除 | 通过(SPA 移除=v1 同机制) | E07 敌意 CSS+重复 script;v1 crossorigin e2e 同模式机制 |
| EMB-A13 | 后台预览隔离 + v2 接入代码 | 通过 | admin e2e UI-04 用例(预览零请求设计 + iframe 内真实组件 + 模拟出心形 + v2 代码卡) |
| EMB-A14 | v1 保留 + 普通 viewer 无回归 | 通过 | v1 embed 14 + crossorigin 6 全绿(settings 兼容断言在内);viewer 244 单测;全量套件除存量 journey(见 E07 登记) |
| EMB-A15 | 不上报浏览/不提交点赞 | 通过 | E05 网络断言(交互全通道触发后 0 提交) |
| EMB-A16 | 证据完整、未测项如实标注 | 通过 | 本记录 + measurements/截图/录屏索引;未测项均在对应行如实标注(A02 横屏/A04 304/A08 记忆/A10 断线/A12 SPA 为机制级证据,非实测) |
## 6 未完成项与外部资源
- 真实 CDN/生产发布不在本轮(方案 §1.2):本轮只产出构建产物与接入文档;
测试服务器部署(含 v2 loader 产物)按既定「测试服务器优先」流程另行执行。
### 服务器部署与真实环境验证(2026-09-22 晚,测试服务器优先流程)
- 镜像:服务器端构建(git archive HEAD=1cf12be 干净源码;web 构建沿用两处
适配:去 `# syntax=` 首行 + nginx entrypoint 防卡死补丁)——
`photo-live-server:1cf12be-20260922` + `photo-live-web:ui04-1cf12be-20260922`
(web 含 VITE_VIEWER_BASE/EMBED_ORIGIN=http://219.157.255.213:32006)。
cn/ov 双栈全量滚动 + web 容器 restart(nginx 上游 IP 缓存规避),全部 healthy。
cn compose 文件名为 docker-compose.**cn**.yml(点号,非文档横杠——坑位登记)。
- 数据:经真实管理 API 创建 v2 展示位「官网悬浮位·照片上滚」
(slot dg0mo4i5gov39g1vv0wgisgb,displayMode=vertical-stream/speed16/reactions on)
绑定既有相册「测试1」(5 张真实手机竖幅照片,真实 OSS live-album 桶)。
ov 公开 feed 验证:settings 三新字段完整投影;照片为真实 OSS 预签名 URL。
- 真实环境端到端 5/5(本地浏览器 → 服务器,规格留档
docs/designs/ui04-implementation/server-verify.spec.ts):
①入口可达(viewer 相册页/admin 登录页/v2 loader 产物 200);
②组件 195×280 + 真实 OSS 照片渲染 + 自动上滚;
③iframe 内收起 → 宿主把手展开;④点击照片 → 服务器观众页深链弹窗命中;
⑤真实点赞(ov 公开 API)→ **WS 经 OpenResty 32006 反代升级** → 心形气泡
(生产代理链路 WS 支持实测通过)。
- 截图:actual/server/server-desktop-widget.png、server-desktop-heart.png
- 宣传图/封面共用(用户决策 2026-09-23,随并行提交 8e674a9 入库):读侧双向
回退——ov albums_ov += coverAssetKey(迁移 20260923095000,服务器已
migrate-deploy);asset.updated kind=cover 分列投影;ov/cn 公开 banner 回退
cover、管理列表/详情 cover 回退 banner(并存时封面位恒用 cover)。api e2e
262 全绿(+3 回退用例:cn cover-only→banner、ov 真实资产 API 全链、
banner-only→cover)。服务器实装 `8e674a9-20260923` + `fallback-8e674a9`:
新建「封面回退验证相册」(仅 cover,真实 API 上传)→ ov banner 非 null、
展示页顶部渲染(banner-fallback-cover-only.png)。顺带修清 embed e2e 的
UI-04 settings 全集旧断言(记忆登记的存量失败)。
(视觉核对:真实竖幅照片堆叠 + 珊瑚粉心形 + 收起钮 + 白边圆角,与设计一致)。
机制级项中 A10 真断线仍未演练(本轮 WS 为连通正向验证)。
- 机制级(非实测)项汇总(EMB-A02 横屏/A04 304 链/A08 收起记忆/A10 真断线/
A12 SPA 移除):实现与 v1 同机制,v1/单测有证据;真机/真断线演练随 P5。
- 存量失败(非本任务):journey.spec 队列消费竞争(并行会话/游离 worker,
干净 HEAD 复现);已按记忆库流程多次清理游离 worker。
- 真机验证(G2)与全球访问(A28)不属于嵌入组件本轮范围。