Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion docs/BOARD.md
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,8 @@
| **SB-4 shot→video 直达(M4 E1)**:shot 面板第二个生成入口——以本镜备注为 prompt 建 **video** config 节点 + narrative 边,并把 SB-3 的预期时长/预期运镜一并写进去(省得在 video 面板重填)。**带的是意图不是承诺**:video 面板按所选 provider 的 supportedDurations/supportedCameras 钳制,不支持的值落地即丢回未设置——本卡不做任何能力判断(此刻还没选 provider);未设置的参数**不写空键**,让 video 面板照常按 provider 取默认而非被显式 null 顶掉。两个生成入口的公共主体抽 `_generateFromNotes(type, extraConfig)`——原先只有图片一条,现在两条,复制一遍迟早发散(notifier/文案 await 前取好、节点与连线失败分开报这些约束一处都不能漏)。ARB +1 键。+5 例 | #223 |
| **SB-1 规则脚本拆分器(M4 E1;D-M4-1 拍板后首件)**:`storyboard/util/script_splitter.dart` 纯 Dart 零 Flutter 依赖——`ShotDraft{label,notes}` + `splitScript(text, strategy)`,策略 blankLine(空行分段)/perLine。**剥行首编号**是本卡最易写漏处:用户粘来的文本十有八九带 `1.`/`镜头1`/`第3镜`/`SHOT 1`/`# `,留着会污染 prompt(「1. 山径破晓」让模型去画数字);但不能剥过头——「1920 年代的街道」「3D 渲染质感」里的数字是内容,故**光秃秃的数字必须跟分隔符才算编号**,有词锚的(镜头/第N镜/shot/scene)才允许无分隔符。markdown 井号单独一趟剥(可独立出现也可叠在编号前,`### Shot 1 dawn`)。只剥**段首那一行**(「2 号机位跟拍」是内容不是第 2 镜);剥完为空的行丢弃让后续行顶上。CRLF 与单独 CR 都归一 LF;「空行」按 trim 判定(Word/网页粘贴常带空格 tab);label=段首行截 60 字而 notes 恒为全文。22 例覆盖两策略/六类编号/不误伤/退化输入/顺序稳定 | #224 |
| **SB-2 脚本导入对话框 + 批量建链(M4 E1;E1 整条链自此贯通)**:`storyboard/providers/script_import_controller.dart` + `widgets/script_import_dialog.dart`——粘贴框/策略切换/实时预览 → 确认后 N 个 shot 节点 + N-1 条 narrative 边收进**单个事务**。**失败必须零残留**:半条链(几个建好的散镜 + 几条边)比一个错误提示难收拾得多——用户既不知道哪几镜落地了也没有一键撤销;测试用的 fake UoW **真回滚**(写入先落 staging,闭包整体成功才 commit),真事务语义仍由 `transaction_integration_test`(真 PG)兜底。两处坑:①**不走 CanvasNodesController**(它一次只建一个节点、不入事务)——直接经 scope 写库,落地后 invalidate 节点与边两个控制器 ②**provider 不加 autoDispose**——调用方只 `ref.read` 不订阅,autoDispose 会在 read 后立刻销毁 ref,事务 await 完再 invalidate 就撞上已销毁的 ref,画布刷不出新链。落点=第一镜落视口中心,后续每 `kShotChainSpacingX`(260) 沿 x 排开;入口=FAB 菜单「导入脚本…」+ 空态 CTA。ARB +13 键。+18 例 | #225 |
| **XM-2 图片元数据(M4;补齐 XM-1 的图片侧)**:`core/media/png_dimensions.dart` 纯函数(PNG 签名 + IHDR,不引解码库)→ 四个落盘点(inline 单/批、remote 单/批)顺手解析宽高,连同 `task.seed` 写进 `node.type_config`(主图那一张,与 XM-1 视频侧同键)与 `batch_results.width/height/seed`(逐 slot 各记各的,schema 已建未用的列自此有值)。**判定刻意严格、拿不到就不写键**:认错了会把垃圾尺寸写进库再一路带到排版,而列停在 NULL 画廊才知道退回默认比例——每条正向断言都配一条「非 PNG 时这些键根本不出现」的反向断言。inline 路径 bytes 在手零额外 IO;remote 路径回读文件头 33 字节(完整 IHDR 含 CRC),**任何探针失败一律吞掉**——元数据是锦上添花,绝不能把一次成功的生成拖成失败。视频侧不动(宽高仍归 XM-1 抽帧探针)。+22 例 | 本 PR |
| **XM-2 图片元数据(M4;补齐 XM-1 的图片侧)**:`core/media/png_dimensions.dart` 纯函数(PNG 签名 + IHDR,不引解码库)→ 四个落盘点(inline 单/批、remote 单/批)顺手解析宽高,连同 `task.seed` 写进 `node.type_config`(主图那一张,与 XM-1 视频侧同键)与 `batch_results.width/height/seed`(逐 slot 各记各的,schema 已建未用的列自此有值)。**判定刻意严格、拿不到就不写键**:认错了会把垃圾尺寸写进库再一路带到排版,而列停在 NULL 画廊才知道退回默认比例——每条正向断言都配一条「非 PNG 时这些键根本不出现」的反向断言。inline 路径 bytes 在手零额外 IO;remote 路径回读文件头 33 字节(完整 IHDR 含 CRC),**任何探针失败一律吞掉**——元数据是锦上添花,绝不能把一次成功的生成拖成失败。视频侧不动(宽高仍归 XM-1 抽帧探针)。+22 例 | #226 |
| LB-23 内存基线:cacheWidth 缩略解码收口 ×4 文件 5 站点(gallery tile 图片+视频缩略图/batch grid/两微缩略图;lightbox InteractiveViewer 有意豁免)+ ImageCache 上限 100→256MB(`kImageCacheMaxBytes`,main bootstrap 设定)+ perf-baseline 内存水位节(方法论/阈值/mac 空载实测 140MB,画廊与生成场景按 SOP 待填,Windows 列待群内机器)+ keepAlive 盘点 8 文件无未管控大对象 | #227 |

## M1 补遗(审计发现的悬空项)

Expand Down
1 change: 1 addition & 0 deletions docs/CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,7 @@ lib/
├── crash_reporter.dart # FileCrashReporter (uncaught-error crash file + keep-3 rotation, no context/extra)
├── error_hooks.dart # installErrorHooks + reportUncaught (FlutterError/PlatformDispatcher/zone → logger + CrashReporter)
├── lifecycle_timer.dart # LifecycleTimer (startup stage timing → app.lifecycle {stage, ms}; see docs/perf-baseline.md)
├── image_cache_config.dart # configureImageCache (LB-23: ImageCache 上限 256MB; main bootstrap 调用一次)
├── dio_video_download_service.dart
├── process_watchdog.dart # runWithWatchdog (ProcessStarter 流式 + 定时 kill + 硬截止; pg_dump/pg_restore 超时)
├── system_process_runner.dart # ProcessRunner/ProcessStarter impl (Process.run / Process.start+stdin close)
Expand Down
2 changes: 1 addition & 1 deletion docs/MASTERPLAN.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ M6 「公开上线」……… 官网 + 示例项目 + 冷启动执行(HN/Reddit
> 与 UI 卡去重:LB-06≡GAP-3、LB-15≡GAP-2、LB-05 联动 GAP-8——同一工作只排一张;
> Inspector 测试欠账裁决为**上线前**(UI GAP-7 为准,backend 债 #19 让渡)。
> 严格复审新增三卡:**LB-22 备份还原路径 ✅ #189**(SCRAM 后用户无法手工 pg_restore——app 内还原入口,
> beta 前 M)、**LB-23 内存基线**(ImageCache 上限/长会话水位,S-M)、**LB-24 网络代理支持**
> beta 前 M)、**LB-23 内存基线 ✅ #227**(ImageCache 上限/长会话水位,S-M)、**LB-24 网络代理支持**
> (dio 不读系统代理,中文用户连不上海外模型商——`HTTPS_PROXY` env 先行 + 设置页代理区,上线前 M)。

**债表处置总账**:24 行 → 上线前必修 11、条件必修 1(build_runner,freezed 3.2.6 触发)、
Expand Down
37 changes: 37 additions & 0 deletions docs/perf-baseline.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,3 +71,40 @@ grep '"module":"app.lifecycle"' ~/Library/Application\ Support/InkFrame/logs/ink
| 冷启 | `pg_ready`(含 initdb) | < 15s | TODO(measure on real macOS/Windows) | TODO(measure on real macOS/Windows) |

回填时一并记录机器规格(CPU / 内存 / 磁盘类型)与 app 版本,便于跨机比较。

## 内存水位(LB-23)

### 方法论
- 指标:进程 RSS(mac `ps -o rss= -p <pid>`;win 任务管理器「内存」列或
`Get-Process inkframe | % WorkingSet64`)。Release 构建,采样前静置 10s。
- 三场景:**空载**(启动进 Studio 不开项目);**画廊 100 项**(示例项目扩种或真实项目,
Gallery 滚到底再回顶);**连续生成 20 张**(任一 provider,1024px,逐张等完成)。

### 阈值(验收线)
| 场景 | 阈值 | 依据 |
|---|---|---|
| 空载 | < 400 MB | Flutter desktop shell + 嵌入式 PG 常驻 |
| 画廊 100 项 | < 800 MB | 空载 + ImageCache 上限 256MB + 解码抖动余量 |
| 连续生成 20 张后回落 | < 900 MB 且 10min 内不再增长 | 泄漏红线:持续线性增长即 bug |

### 实测记录
| 场景 | macOS (arm64) | Windows (x64) |
|---|---|---|
| 空载 | 140 MB(2026-08-18,alpha.11+ 本机 arm64;主进程 30s 稳定,嵌入式 PG 子进程另 23 MB) | 待测(群内 Windows 机) |
| 画廊 100 项 | 待测(需 ≥100 项真实产物) | 待测 |
| 连续生成 20 张 | 待测(需 API key 手工跑,SOP 如上) | 待测 |

### ImageCache 策略(评估记录)
默认 100MB/1000 张 → 字节上限调 256MB(`kImageCacheMaxBytes`,main bootstrap 设定)。
依据:cacheWidth 收口后画廊 100 项工作集 ≈80MB 贴默认上限,滚动抖动淘汰;
桌面内存充裕。条目上限不动。cacheWidth 覆盖清单:node_card / video_node_body(先例)
+ gallery_tile(图片 tile + 视频缩略图两站点)/ batch_results_grid /
node_inputs_section / image_config_inspector(本卡);
豁免:gallery_image_lightbox(InteractiveViewer 缩放需全分辨率)。

### keepAlive 常驻盘点(LB-23 子项④)
8 文件(database / providers / rate_limiter / canvas_transform / inspector_submit /
export_controller / generation_controller / jobs_registry),`grep -rln keepAlive lib`
2026-08-18 复核一致。持大对象者仅 ImageCache 域外的 jobs_registry(handle 缓存,
随 purge 收敛)与 database pool——均为设计内常驻;无未管控大对象。
上线后如需精算记 BP 系。
4 changes: 4 additions & 0 deletions docs/superpowers/plans/2026-07-07-launch-backend.md
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,10 @@ commit 更新 DATABASE/ARCHITECTURE 对应节。
- **LB-23 内存基线**(S-M):perf-baseline.md 加内存水位节(空载/画廊 100 项/连续生成 20 张后的
RSS,双平台实测);ImageCache 上限策略评估;画廊 tile `Image.file(cacheWidth:)` 缩略解码
列为 GA-1/GAP-5 验收项;keepAlive provider 持大对象盘点(17 处)记 BP 系。
状态:已随 #227 落地——cacheWidth 收口 ×4 文件 5 站点(gallery tile 图/视频缩略图、
batch grid、两处微缩略图;lightbox InteractiveViewer 有意豁免)、ImageCache 256MB
(kImageCacheMaxBytes)、perf-baseline 内存水位节(mac 空载已实测 140MB;画廊/生成/win 列
按 SOP 待填)、keepAlive 盘点 8 文件无未管控大对象。

### D. 可观测性

Expand Down
Loading
Loading