inline 占位补到期清理,收掉存活窗口引入的回归
存活窗口把「立即刷新也能清掉孤儿占位」换掉了:剥离只在首次加载跑一次,窗口内 被保留的占位再没有东西会重新判定,页面开着就一直转。 复查发现缺的不是删除手段——requestRemoveCanvasGenerationDialog 已接入快捷键, 对 generating 会弹确认再删——而是「它已经死了」这个信号。 加一次性到期定时器,到点走与加载期完全一致的处置:移除 + 同一条文案。未采纳 标记 failed,那会被持久化且剥离只处理 generating,卡片跨刷新长期存在,与当初 选「刷新后占位消失」的用意相反。 三条实现约束:到期回调只推进 tick、判定在 effect 里用当前值重做;清理用底层 removeCanvasGenerationDialogById 而非 View 的版本(后者写历史、清选中、切工具, 是用户主动删除的语义);本会话在途占位不靠推理豁免,靠重新判定兜住。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -6107,3 +6107,14 @@
|
||||
- 复查中核过、确认不是问题的两点:其一,网关放宽的作用域正确——`/api/*` 走 `is_generic_api_proxy_path`,读超时默认 `3600` 秒,远高于服务端 90 秒预算与客户端 120 秒,次序是 `90 < 120 < 3600`,网关不会在服务端合法工作期间截断,它合成 502/504 只可能是连接失败或进程不可用,确属未知结果;唯一变数是有人把 `GENARRATIVE_PINGORA_GATEWAY_UPSTREAM_API_READ_TIMEOUT_SECONDS` 调到 90 秒以下。其二,`projectHasUnresolvedGenerationDialog` 由 `some(...)` 改为「取首个匹配再判」存在极低风险的语义收窄,同 id 多 dialog 时行为不同,但 id 唯一,实际不可达。
|
||||
- 验证:`vitest src/components/image-editor` 908 通过 / 72 文件,typecheck、eslint、check:encoding 通过。
|
||||
- 关联文档:`docs/technical/【前端架构】图片画布编辑器MVP接入方案-2026-06-11.md`。
|
||||
|
||||
## 2026-08-03 inline 占位补到期清理,收掉存活窗口引入的回归
|
||||
|
||||
- 缺陷:存活窗口把「立即刷新也能清掉孤儿占位」这条旧行为换掉了。剥离只在项目首次加载执行一次,窗口内被保留的占位再没有任何东西会重新判定——页面保持打开就一直转,必须等到用户下一次加载且距创建已满窗口才收口。这是引入 TTL 时的已知取舍,本次补上。
|
||||
- 复查中发现的关键事实:**手动收口入口本来就存在**——`requestRemoveCanvasGenerationDialog` 已接入键盘快捷键,对 `generating` 占位会先弹确认再删。所以缺的从来不是删除手段,而是「它已经死了」这个信号;占位看起来和正在干活一模一样。
|
||||
- 决策:加一次性到期定时器,到点走与加载期**完全一致**的处置——移除 + 同一条文案(抽成 `DEAD_INLINE_PLACEHOLDER_NOTICE` 共用)。未采纳「标记 failed 而不移除」:`failed` 会被自动保存持久化,而剥离只处理 `generating`,那张卡片会跨刷新长期存在,与当初选「刷新后占位消失」的用意相反,把一次性噪音变成永久残留。
|
||||
- 三条必须守住的实现约束,都写进了 hook 的文档注释:其一,到期回调只推进 tick 让 effect 重跑,判定始终在 effect 体里用当前 dialogs 和当前时间做——挂上定时器之后占位可能已被拥有者会话正常收口,按闭包旧值行动会清掉一个已完成的占位;其二,清理用底层 `removeCanvasGenerationDialogById` 而不是 View 的 `removeCanvasGenerationDialog`,后者是用户主动删除的语义(写 `delete-generation-result` 历史、清空选中、切回选择工具),自动清理记用户没做过的历史、抢走当前选中态都是错的,加载期剥离同样不做这些;其三,本会话自己在途的占位不会被误清(客户端 120 秒就 abort,catch 会把它推离 `generating`),但不依赖该推理,靠第一条的重新判定兜住。
|
||||
- 作用面划分:`dropDeadInlineGenerationPlaceholders` 跑在**快照**上、只在加载时执行;`collectExpiredInlineGenerationDialogIds` / `resolveNextInlineGenerationDialogExpiryAt` 跑在**内存 dialog** 上、供页面打开期间使用。同一条规则、两种数据形状,边界(到期时刻含等号不算过期)与缺时间戳的兜底方向都保持一致。
|
||||
- 到期时刻可精确计算,所以挂一次性定时器而不是轮询;多给 50ms 余量,避免贴着到期时刻醒来判定为未到期、白白多挂一轮。
|
||||
- 验证:纯函数四条用例覆盖边界、队列型与已终态不到期、缺时间戳立即到期、最早到期时刻;hook 四条覆盖到期清理、醒来重新判定(占位期间被收口则不清)、队列型永不挂定时器、已超窗立即清理。去掉定时器重挂逻辑后第一条变红。`vitest src/components/image-editor` 916 通过 / 73 文件,typecheck、eslint、check:encoding 通过。
|
||||
- 关联文档:`docs/technical/【前端架构】图片画布编辑器MVP接入方案-2026-06-11.md`。
|
||||
|
||||
Reference in New Issue
Block a user