verify
GitHub用于 Electron 小说应用前端 UI 的实机自动化验证。通过 Playwright 驱动无头窗口,执行特定场景并截图、记录耗时,支持对比新旧版本界面表现与启动性能。
Trigger Scenarios
Install
npx skills add EthanYoQ/AI-Novel-Writer --skill verify -g -y
SKILL.md
Frontmatter
{
"name": "verify",
"description": "在真实 Electron 中驱动 AI 小说作家,按场景截图、记录启动耗时并读取只读诊断。前端重设计 RD-0 至 RD-10 每个 PR 的实机验证都走这里。用于「实机验证」「截图对比」「跑一下界面场景」。"
}
verify
驱动脚本是 scripts/redesign/drive.mjs。它用 Playwright 的 _electron 启动当前工作树的构建产物(electron .),每个会话(一次冷启动)一个全新的隔离目录,模型调用全部走本机假服务,不调用真实模型。单跑一个场景就是只含这个场景的会话。
应用窗口不出现在屏幕上。驱动用 electron -r scripts/redesign/offscreen-window.cjs 在应用主进程脚本之前挂上 browser-window-created 监听:窗口一创建就移到所有显示器右侧之外,去掉任务栏按钮,设为不可激活并交还焦点,不打扰正在用电脑的人。截图走页面视口,与窗口位置无关;页面焦点由 Playwright 的焦点模拟提供,document.hasFocus() 仍为 true。每次截图前断言 document.visibilityState 为 visible,防止屏幕外窗口被当作隐藏而停帧。
启动前
在要验证的工作树根目录依次运行:
pnpm install --frozen-lockfile
pnpm rebuild:electron
pnpm build
驱动加载的是 dist/ 与 dist-electron/,改了 src/ 或 electron/ 必须重新 pnpm build。better-sqlite3 刚为 vitest 切到 Node ABI(pnpm prepare:native-node)时,先 pnpm rebuild:electron 再驱动。
命令
pnpm verify:drive -- --scenario <名称> [--theme light|dark] [--shell writer|stage] [--out <目录>] [--dump-dom] [--console] [--video] [--app-root <目录>]
# 等价于
node scripts/redesign/drive.mjs --scenario <名称> ...
--theme默认light,即外观里的「浅色」;dark为「深色」。--shell只对 RD-10 之前的构建(--app-root指向的 trunk)有意义:不给时不碰外观里的外壳偏好(旧外壳),stage选 RD-3 起的流程脊外壳,与主题在同一次写入里改,只重载一次;RD-2 及更早的 trunk 不认识stage,不要传。RD-10 起的构建只有纸墨外壳,外观写在 v3 键里,没有外壳偏好:--shell不必传,传writer直接报错。--video在每个截图点的run期间录屏:CDPPage.startScreencast收帧,按帧时间戳交给本机ffmpeg编成 H.264 mp4,写到<场景>-<主题>.mp4。不需要 Playwright 自带的 ffmpeg。--out默认.runtime/redesign-baseline/(已被 git 忽略)。--app-root默认当前工作树。性能对照时指向 trunk 的工作树,用同一个驱动测两边;目标工作树也要先跑完上面三条命令,它加载的是自己的dist-electron/和better-sqlite3。- 退出码:0 全部通过;1 有场景失败、残留进程或隔离目录外写入;2 参数错误。
RD-10 删除旧外壳之后,场景分三类:
- 只走旧外壳的场景只对 trunk 跑(
--app-root):下面「场景」表的 8 个基线场景与baseline-all、nav-*、write-latency、settings-appearance、run-write-steps、legacy-no-chat、arch-legacy-sidebar。对照时 head 一侧改跑对应的新外壳场景。 - 两种外壳都能跑的场景运行时按页面上有没有纸墨外壳选页面对象,head 与 trunk 用同一条命令:
startup-timing、idle-memory、chapter-switch、chapter-open、typing-latency、chapter-regression、blueprint-regression、blueprint-timing、refs-regression、refs-timing、new-project-files。 - 其余声明了
shell: 'stage'的场景只对 RD-3 及以后的构建跑。
场景
| 名称 | 对应流程 | 单跑时截图停在 | baseline-all 里的不同 |
用夹具模型 |
|---|---|---|---|---|
new-project |
新建作品 | 新作品的小说配置页 | 无 | 否 |
open-sample |
打开示例作品 | 项目树刷新完成(蓝图 2/100 章、角色图谱已生成),显示第 1 章与草稿_v1 | 无 | 否 |
write-chapter |
写作此章 | 草稿标签已打开,正文非空 | 已有预置的草稿_v1,写出的是草稿_v2 | 是 |
review |
AI 审稿 | 审稿报告标签 | 审的是最新一稿草稿_v2 | 是 |
revise-merge |
按确认意见修稿并合并 | 修稿合并对话框;截图后点完成合并,等对话框关闭 | 修的是草稿_v2 | 是 |
finalize |
定稿 | 已定稿(只读),AI 输出显示后处理完成 | 定稿的是合并后的草稿_v2,不是草稿_v1 | 是 |
run-panel |
打开运行面板(现为 AI 输出) | 重开作品后从右侧栏打开 AI 输出,显示一条持久运行「第1章候选」 | 无;它排在审稿之前,因为草稿被修稿改动后这条记录变成「第1章生成记录」 | 是 |
settings |
打开设置 | 设置弹窗 | 截图后关闭设置,接着跑 new-project | 否 |
baseline-all |
按共享前置串成 2 个会话跑上面 8 个场景 | 8 张截图 | ||
startup-timing |
只启动 | 不截图,输出启动耗时 | 否 |
示例作品名为「灯塔」,第 1 章「旧港」,由公开 IPC 预置后从书房打开;打开后等项目树统一刷新结束再继续,之前的画面随刷新进度变化。
场景的 run 可以调 context.restart():退出应用、用同一隔离目录冷启动(不重写外观),context 里的 app、page 换成新的,用于验证「重启后仍保持」。
scripts/redesign/scenarios.mjs 里每个场景分三段:setup 是单跑时的前置(预置作品、写一章、审稿等),run 从前置状态走到截图状态,after 在截图后执行。一个会话只跑首个场景的 setup,然后依次 run、截图、after。baseline-all 的会话在 BASELINE_SESSIONS:
baseline-shelf:settings→new-project。不预置作品,new-project要在空项目目录里建「灯塔」,与示例作品不能共存。baseline-sample:open-sample→write-chapter→run-panel→review→revise-merge→finalize。预置一次带草稿_v1 的示例作品,后面每步接着上一步的状态。
改动前 baseline-all 每个场景各冷启动一次(8 次);现在 2 次。
输出
在 --out 目录下:
<场景>-<主题>.png:场景截图,1440×900(stage-1280为 1280×900)。--video时另有<场景>-<主题>.mp4,结果项的video字段指向它。<场景>-<主题>.json:本次运行的结果数组,每个截图点一项。scenario、screenshot属于这个截图点;session(会话名,单跑时等于场景名)、timing、shell(外壳的data-shell-presentation,writer或stage:startup-timing取计时那次启动显示的外壳,其余场景取写好外观、重载之后的外壳,用来确认测的就是要测的外壳)、externalRequests、residualProcesses、externalWrites、quit、isolationRoot属于整个会话,会话里每一项都抄一份;会话用了夹具模型时另含modelRequests(整个会话里假服务收到的全部请求数,嵌入请求也计入,与--console里的[fake-model]行一一对应)。失败时含error:截图点自己的失败写在该项;同一会话里排在失败点之后的截图点不再运行,error写明是被哪个场景拖住;会话级失败(启动、外部请求、退出、进程枚举)写进该会话的每一项。- 失败时额外写
<失败场景>-<主题>.failure.png、.dom.html、.aria.yml和<会话>-<主题>.console.log,隔离目录保留以便排查。
每个会话结束后,驱动检查三件事,任一不满足即退出码 1:
externalRequests为空。每个会话都在 Electron 启动后替换主进程的globalThis.fetch:用夹具模型的会话只放行https://api.openai.com/v1/*并改道到本机假服务,其余会话一律不放行。被拒的请求记下来源并抛错。检查范围只有主进程fetch,且从electron.launch返回后才生效;更早的请求、渲染进程的请求和 Electronnet模块的请求都不在内。residualProcesses为空:应用关闭后,以--user-data-dir匹配不到存活进程。子进程退出需要时间,驱动最多查 10 次、间隔 300 ms。externalWrites为空:~/.vela、%APPDATA%\ai-novel-writer、%APPDATA%\AI小说作家的最新修改时间不变。
枚举或结束进程本身失败时,原因写进该会话每一项的 error,结果 JSON 照常写出。
只读诊断
node scripts/redesign/drive.mjs --scenario open-sample --dump-dom --console --out <目录>
--dump-dom在每个截图点截图后写<场景>-<主题>.dom.html(page.content())和.aria.yml(Playwright 无障碍快照)。改页面对象前先看.aria.yml,选择器优先用其中的角色与可访问名称。--console每个会话写一份<会话>-<主题>.console.log(单跑时会话名就是场景名,baseline-all为baseline-shelf、baseline-sample):渲染进程控制台、页面异常、主进程 stdout/stderr,以及假模型每次请求的分类([fake-model] prose|review|revision|character-state|embedding)。
截图可重复性
同一场景连续跑三次再比较:
for i in 1 2 3; do node scripts/redesign/drive.mjs --scenario review --out shots/r$i; done
node scripts/redesign/pixel-diff.mjs shots/r1/review-light.png shots/r2/review-light.png shots/r3/review-light.png
pixel-diff.mjs 输出各张相对第一张的不同像素占比,maxRatio 小于 0.005 时退出码 0,否则 1。尺寸与第一张不同的图记为全部不同(ratio 为 1),reason 写明两边尺寸。任一通道差值超过 2 级才算不同像素(ratio),因为同一状态连续截图时,渲染器在背景模糊和渐变上偶发全屏 ±1~2 级抖动;逐字节比较的结果另列为 strictRatio,供判断差异是不是这种抖动。
启动耗时
startup-timing 的 timing 字段:readyToShowToInteractiveMs(主窗口 ready-to-show 到书房「新建作品」按钮可见,计划里的性能指标)、launchToInteractiveMs、navigationToInteractiveMs。ready-to-show 监听在预加载脚本里、先于移窗挂上,窗口创建前就已就位,所以每次都有值。trunk 与 head 交替各跑 5 次取中位数:
node scripts/redesign/drive.mjs --scenario startup-timing --app-root <trunk 工作树> --out <目录>
node scripts/redesign/drive.mjs --scenario startup-timing --out <目录>
空闲内存
idle-memory 与 startup-timing 一样先在同一隔离目录预启动一次写好主题,再冷启动一次;第二次启动到书房可交互后静置 10 秒,再每隔 1 秒用 app.getAppMetrics() 采样 5 次全部进程的内存,结果写进 memory:workingSetKB、privateKB(Windows 才有私有字节)是各次合计的中位数,byType 按进程类型(Browser、Tab、GPU、Utility 等)各取工作集中位数,samples 是采样次数。不截图、不用夹具模型。计划 RD-10 的性能复测与启动耗时交替跑:trunk 与 head 各 5 次,取中位数比较,跑的时候机器上不开别的程序。
node scripts/redesign/drive.mjs --scenario idle-memory --app-root <trunk 工作树> --out <目录>
node scripts/redesign/drive.mjs --scenario idle-memory --out <目录>
不进 baseline-all 的场景
scenarios.mjs 的 EXTRA_SCENARIOS 只能单跑,不进 baseline-all。run 的返回值写进结果的 measured。需要卡住模型调用时,场景从上下文的 fake.gate 调 hold(),在 after 里 release()。hold() 只卡对话请求;只走嵌入的步骤(参考文本入库)用 hold({ embeddings: true }) 连嵌入一起卡。fake.gate.waiting 是正卡在门上的请求数,截图前等它大于 0,画面才停在确定的那一步。
| 名称 | 检查 | 单跑时截图停在 | 用夹具模型 |
|---|---|---|---|
write-latency |
在渲染进程里计时:点击写作此章弹窗的「开始创作」到 AI 输出标题可见,写进 measured.writeToOutputMs。RD-4 起旧外壳右栏默认是 AI 输出,计时前只在它开着时收起,trunk 不受影响 |
写作完成 | 是 |
nav-switch-project |
角色视图加沉浸写作时从标题栏切换到另一部作品,断言退出沉浸、侧栏显示项目树 | 新作品的小说配置页 | 否 |
nav-toast-open |
写作完成后再点右侧栏「AI 输出」收起它,点完成提示「打开查看」,断言 AI 输出重新出现 | AI 输出里的「第1章候选」 | 是 |
nav-status-capsule |
卡住模型让写作停在运行中,收起 AI 输出后点状态栏任务胶囊,断言 AI 输出出现 | 运行中的 AI 输出 | 是 |
nav-settings-model |
先从标题栏「备份」打开设置并关闭,再点状态栏模型,断言落在「AI 生成模型」 | 设置弹窗的模型分组 | 是 |
nav-kb-import |
关掉底部面板后在「小说」视图导入创作资料并确认发送,断言底部面板打开且停在「任务」 | 知识库页与任务面板 | 是 |
nav-card-import |
关掉底部面板后在「角色」视图粘贴角色卡并确认发送,断言底部面板打开且停在「任务」 | 角色页与任务面板 | 是 |
nav-batch |
关掉底部面板后从章节蓝图启动 1 章批量创作,断言底部面板打开且停在「任务」 | 批量创作运行中 | 是 |
nav-home-import |
回到首页,点「小说拆解」把参考小说导入当前作品,连嵌入一起卡住模型,断言离开首页、项目树与 AI 输出出现 | 项目树刷新完成,第 1 步「导入参考文本与构建知识库」卡在第一个嵌入请求上 | 是 |
settings-appearance |
旧外壳打开设置并切到「外观」。head 比 trunk 多「界面布局」一组,两边截图不同是预期 | 设置的外观分区 | 否 |
nav-immersive-twice |
关掉底部面板后两次切换沉浸写作,断言三块面板恢复到切换前 | 恢复后的工作台 | 否 |
nav-plot-blueprint-source |
生成剧情树(假模型回复不是 JSON,落到按蓝图的确定性剧情树),从事件来源打开第 1、2 章蓝图;第 1 章标题改了不保存,断言切换选中后改动仍在,手动选第 2 章后再点第 1 章来源会重新选中第 1 章 | 章节蓝图选中第 1 章、标题有未保存改动 | 是 |
nav- 场景对 trunk(--app-root)与 head 各跑一次,两边都通过即行为一致。write-latency 与 startup-timing 一样交替各跑 5 次取中位数。
新外壳(RD-3 起)
页面对象在 scripts/redesign/pages/stage.mjs,选择器用角色与可访问名称(流程脊是 navigation「创作流程」,章节是其中的列表「章节」,标签条是 tablist「已打开的页面」,顶栏是 banner)。示例作品在 scripts/redesign/stage-sample.mjs:「灯塔」12 章全有蓝图,架构四节齐全,1、2 章定稿,3 章已审稿,4 章草稿,其余待写;与旧外壳基线的 SAMPLE 分开,基线截图不受影响。打开后落在第 4 章(几章都在写时取最后一章在写的,#407 第 2 轮用户决定);seedStageSample 默认等落点后切到第 3 章并关掉第 4 章标签,场景都从只开着第 3 章开始(对照用的旧构建本来就落在第 3 章,不切)。两种外壳都能用这份示例:新外壳从书房打开,旧外壳从项目树打开第 3 章草稿。
| 名称 | 检查 | 截图停在 | 夹具模型 | 对应计划 |
|---|---|---|---|---|
stage-open-sample |
流程脊四个阶段的状态(设定、架构、蓝图完成,正文进行中)、章节阶段、当前章为 3、只有一个标签时标签条收起、外壳文字对比度(名称 4.5:1,说明 3:1,底色沿祖先叠加求出) | 第 3 章正文 | 否 | lane 1 的新外壳部分、lane 2(浅色)、lane 3(--theme dark) |
stage-tabs |
依次打开设定与蓝图共三个标签,关掉一个后还剩两个且标签条仍在;after 再关一个,标签条收起 |
两个标签 | 否 | lane 4 |
stage-dirty-close |
改设定页后关「设定」标签,出现危险确认;after 点「继续编辑」,标签与修改都在 |
危险确认对话框 | 否 | lane 5 |
stage-save |
改小说配置,顶栏变「未保存」,Ctrl S 后变「已保存」 | 已保存 | 否 | lane 6 |
stage-find-chapter |
Ctrl P 输入「4」回车打开第 4 章,再输入「第3章」打开第 3 章,流程脊当前章随之变化 | 第 3 章正文 | 否 | lane 7 |
stage-focus |
沉浸写作后流程脊与标签条消失,正文与章节动作条(AI 审稿等)在;after 按 Esc 恢复 |
沉浸写作 | 否 | lane 8 |
stage-1280 |
视口 1280×900:页面无横向滚动,外壳里的名称、章名、位置、搜索提示、保存状态都没有被截断或折行 | 1280 宽 | 否 | lane 9 |
stage-migrate |
RD-10 起:去掉 v3 键、在旧键写入 RD-10 之前的配置后重载,galaxy(v1、旧外壳偏好)与 paper(v2)各走一遍:进入纸墨外壳且不出现启动阻塞,galaxy 迁成深色、paper 迁成浅色,缩放照旧,旧键逐字节不变(供回滚) | 纸墨外壳 | 否 | RD-10 lane 3、4 |
stage-palette |
Ctrl K 输入「灯」,结果里有第 6 章;after 按 Esc 关闭 |
Ctrl K 结果 | 否 | |
stage-run |
卡住模型后从章节蓝图写下一章:运行侧页自动打开,顶栏胶囊展开并显示进度;after 先确认侧页开着时 Ctrl K 仍能打开搜索(侧页不是模态层),再放行、等侧页里「上一次运行」显示已完成、新草稿打开 |
运行侧页与胶囊 | 是 | |
stage-library |
没有打开作品时是书房,没有流程脊;书架空着时唯一的主按钮是「新建作品」,没有模型时有「还没有连接 AI 模型」引导;书房文字对比度 | 空书房 | 否 | RD-5 lane 2 |
stage-modal-layers |
改设定后从作品菜单打开旧的「导出项目」对话框:Ctrl K 不开搜索、Ctrl W 不弹放弃确认;从主进程关窗,退出确认画在对话框之上(isTopmost 让所有元素参与命中测试后取中心点最上层元素);after 取消退出并关掉导出。RD-5 起设置是页面而不是弹窗,所以模态层改用导出对话框;Radix 对话框会把退出确认设为 aria-hidden,页面对象 exitDialog 按类名找它 |
退出确认 | 否 | 第 3 条 |
stage-close-key |
书房里、搜索框里各按一次 Ctrl W,页面都拦下(defaultPrevented),应用仍在。应用菜单有 CommandOrControl+W 的「关闭」,但驱动注入的按键到不了菜单快捷键,所以断言的是拦截 |
搜索框 | 否 | 第 4 条 |
stage-reopen |
从作品菜单回到书房,用 Ctrl K「打开《灯塔》」重新打开同一部作品(新的项目会话),再次落到最后一章在写的第 4 章 | 第 4 章正文 | 否 | 第 8 条 |
stage-partial-blueprint |
规划 100 章、只有 12 章蓝图:蓝图算完成,落点仍是正文第 4 章 | 第 4 章正文 | 否 | 第 6 条 |
stage-revert-after-final |
第 1 章定稿后再建一份新草稿(版本历史「回退到此版本」的效果):第 1 章回到草稿,但最后一章在写的仍是第 4 章,打开作品落在第 4 章;章节列表里第 1 章按草稿显示,点它打开的是新草稿 | 第 1 章新草稿 | 否 | 第 7 条 |
stage-new-project |
新外壳里新建作品:设定进行中、其余未开始;外壳文字对比度、进度环半径 8.5、设定说明在名字下一行、作品资料图标跟随行文字色 | 新作品首屏 | 否 | 第 20、23、24 条 |
stage-focus-search |
沉浸写作里 Ctrl F 打开正文搜索,Esc 只关搜索框、不退出沉浸;after 再按 Esc 退出沉浸 |
沉浸写作 | 否 | 第 10 条 |
stage-tour |
30–60 秒的导览:四个阶段、Ctrl K、Ctrl P、关标签、沉浸写作、写一章看运行胶囊与侧页。配 --video 录评审视频 |
写完一章 | 是 | Review gate |
chapter-switch |
打开第 3 章后,从点击第 4 章到它的正文在编辑器里可见,渲染进程内按帧计时,写进 measured.chapterSwitchMs。旧外壳点草稿箱里的草稿,新外壳点流程脊里的章 |
第 4 章正文 | 否 | perf |
lane 1 的旧外壳部分:head 与 trunk 各跑一次 baseline-all,逐张 pixel-diff.mjs,maxRatio 小于 0.005。
perf:三组交替,各预热 2 次不计,再各计 5 次:trunk 旧外壳、head 旧外壳、head 新外壳。head 旧外壳对 trunk 旧外壳量的是新外壳模块被 App.tsx 静态引入后旧外壳用户付出的启动代价。这是 RD-3 到 RD-9 的做法;RD-10 起 head 没有旧外壳,只比 trunk 旧外壳与 head 纸墨外壳两组,下面带 --shell stage 的命令对 head 去掉 --shell。
node scripts/redesign/drive.mjs --scenario startup-timing --app-root <trunk 工作树> --out <目录>
node scripts/redesign/drive.mjs --scenario startup-timing --out <目录>
node scripts/redesign/drive.mjs --scenario startup-timing --shell stage --out <目录>
node scripts/redesign/drive.mjs --scenario chapter-switch --app-root <trunk 工作树> --out <目录>
node scripts/redesign/drive.mjs --scenario chapter-switch --shell stage --out <目录>
startup-timing 三组都先在同一隔离目录启动一次写好主题(新外壳另写外壳偏好)再退出,计时的是之后那次冷启动;首次启动还要迁移旧配置、建库,与之后的启动不可比,所以两侧都不计首次。启动计时以驱动发现「新建作品」可见为准,Playwright 的轮询间隔随等待时间变长,所以晚出现的界面会被多计一些。
运行侧页(RD-4 起)
场景在 scripts/redesign/run-scenarios.mjs,页面对象在 scripts/redesign/pages/run-sheet.mjs(侧页是 complementary「运行」,分页是其中的 tab,运行与恢复项是 article,按标题命名)。假模型另有两种回复:fake.streamProse({ chunks, intervalMs }) 之后的正文按块定速流出,每块发出的时刻记进 fake.streamLog;fake.replyCharacterCards() 之后,提示词里有「【资料 」时回一份角色提取 JSON(守塔人与林岚),不开时照旧回正文、提取失败。复制类操作在页面里改写 navigator.clipboard.writeText 记录内容,不碰系统剪贴板。
| 名称 | 检查 | 截图停在 | 夹具模型 | 对应计划 |
|---|---|---|---|---|
run-write-steps |
旧外壳写一章,measured 记下 AI 输出里的步骤名、正文与聊天按钮、「写作助手」区域的数量;head 与 trunk 各跑一次对照 |
写完的 AI 输出 | 是 | lane 1 |
run-live |
正文定速流出时侧页「进行中」展开当前步骤,实时输出的句数持续增加 | 正文流到一半 | 是 | lane 2 |
run-cancel |
卡住模型后在运行卡片上点「取消」:没有进行中的运行,顶栏胶囊消失,「上一次运行」写明已取消 | 取消后的侧页 | 是 | lane 3 |
run-batch |
删掉 3、4 章草稿后批量写两章:Ctrl P 里只有正在写的第 3 章标生成中;暂停后本章写完即停,2 秒内不再有模型请求,没有章标生成中;after 继续并写完 |
已暂停 | 是 | lane 4 |
run-confirm |
从角色页粘贴两张角色卡:侧页出现「等你确认」与两个采用方式;after 林岚对应已有、守塔人新建,确认后角色列表多了守塔人、林岚仍只有一个 |
等你确认 | 是 | lane 5 |
run-discard |
预置一条恢复候选:复制得到原文;「放弃…」出现就地确认条且焦点在「保留」;after 确认放弃,收起再打开侧页(重新读取)后候选不再列出 |
就地确认条 | 否 | lane 6 |
run-diagnostics |
预置三条调用记录后写一章:诊断分页是宽版,调用表三行,复制安全诊断不含正文与密钥,界面文字没有 token(日志行原文除外) | 诊断分页 | 是 | lane 7 |
run-en |
切到英文重载:Ctrl K 搜 assistant、agent、chat 都没有结果;写一章时侧页分页是英文,整页没有聊天字样 | 英文的进行中 | 是 | lane 8 |
legacy-no-chat |
旧外壳:右侧栏只有「AI 输出」,没有 Agent 按钮,右侧区域名为「AI 输出」,整页没有聊天字样;再点一次收起、再点打开 | AI 输出 | 否 | lane 9 |
run-olddata |
预置一条助手任务(两轮历史加一轮回复):打开作品与运行侧页没有报错,界面没有调用任何 agent-generation:*(在主进程里包一层 invoke 计数),侧页不列助手任务;after 重开读出的对话内容与之前相同,项目目录里数据库以外的文件没有改动 |
进行中 | 是 | lane 10 |
run-tour |
30–60 秒的导览:定速写一章看实时输出与完成,历史里展开这次运行,诊断宽版,放弃恢复候选的就地确认后选「保留」,收起侧页再用 Ctrl K 打开。配 --video 录评审视频 |
进行中 | 是 | Review gate |
write-stream |
60 块、每块 50 字、间隔 50 ms 的正文流出(3000 字):measured.fps 是第一块到最后一块显示之间的帧率,appendMedianMs、appendP95Ms 是每块从假模型发出到出现在界面上的延迟。两种外壳都能跑,用 --shell stage 选新外壳 |
写完一章 | 是 | perf |
run-olddata 的状态对比只看对话内容:重开作品时主进程会把旧会话里没写完的助手任务登记为暂停、改期限,这是主进程的租约记账,与界面无关。
书房、设定与设置(RD-5 起)
书房、设定页与设置页的页面对象也在 pages/stage.mjs:书架是列表「最近的作品」,封面按钮叫「预览《书名》」,右侧概览是区域「《书名》概览」,里面唯一的主按钮是「打开《书名》」(只预览的书)或「继续写作 · 下一步」(当前作品);每本书的更多操作是「《书名》更多操作」菜单。openFromLibrary 先点封面再点「打开《书名》」,openFromPalette 从 Ctrl K 打开(同一部作品也会开新的会话)。新建作品的对话框旧外壳叫「新建小说项目」,新外壳叫「新建作品」,bookshelf.createProject 两种都认。设定页的核心大纲是文本框「核心大纲」(缺这项时名字带「 · 必填」),三项必填是下拉「类型」「目标读者」与一组「篇幅」,更多设定是按钮组「更多设定」,展开的每项是同名区域;dirtySetup 在核心大纲末尾补一句。假模型认出配置 JSON 合同的提示词时返回 FIXTURE_CONFIG。设置页是导航「设置分组」,每页标题是一级标题;openSettings 从流程脊打开,showSettingsPage 切页,closeSettings 点「返回作品/返回书房」。
| 名称 | 检查 | 截图停在 | 夹具模型 | 对应计划 |
|---|---|---|---|---|
stage-library-preview |
预置示例作品但不打开,点封面预览:概览的阶段进度里架构、蓝图完成,正文进行中;没有流程脊(没有打开);唯一的主按钮是「打开《灯塔》」;文字对比度 | 预览概览 | 否 | lane 3 |
stage-library-remove |
回到书房,书本菜单「从最近项目移除…」出现确认;after 确认后封面消失、作品文件夹仍在 |
移除确认 | 否 | lane 4 |
stage-library-delete |
当前作品的书本菜单「删除作品…」,输入「灯」时「删除作品」禁用;after 输入完整书名后可用,再取消,文件夹仍在 |
删除确认(名字不对) | 否 | lane 5 |
stage-update-card |
夹具更新源(stubUpdates 替换主进程的更新 IPC,安装只计数);设定页改一项未保存,回书房点「下载更新」再点「立即重启更新」,出现「请先处理未保存的修改」与「返回保存」;after 返回保存,安装次数为 0 |
更新拦截 | 否 | lane 10 |
stage-setup-required |
新外壳新建「雾岛」,写核心大纲、选类型,不选目标读者:「下一步:故事架构」禁用,提示「选好目标读者就能继续」并由 aria-describedby 关联;设定页唯一的主按钮;对比度;after 选目标读者后点下一步,先保存再到架构 |
必填未齐 | 否 | lane 6 |
stage-setup-fill |
示例作品的设定页点「AI 补全其余设定」,确认扩写已有内容;夹具按配置 JSON 合同返回(FIXTURE_CONFIG),世界观被填上、核心大纲保留作者原文;再改世界观,设定变为未保存 |
补全后的世界观 | 是 | lane 7 |
stage-settings-groups |
从流程脊打开设置:分组为常用(AI 模型、外观)、高级(检索模型、网络代理、提示词模板、写作 Skills)、其他(项目备份、关于与更新),落在 AI 模型,位置为「设置 / AI 模型」;外观里放大到 105% 再还原;外观页没有主按钮;对比度;after 按 Esc 回到第 3 章 |
外观 | 否 | You see、缩放移入外观 |
stage-settings-dark |
设置 → 外观 → 主题选「深色」,外壳变深色;context.restart() 退出应用再用同一隔离目录冷启动,仍是深色,外观里「深色」仍选中;深色对比度 |
深色外观 | 否 | lane 8 |
stage-settings-model |
设置 → AI 模型,夹具模型的更多操作「删除模型…」出现危险确认;after 取消,模型还在 |
删除模型确认 | 否 | lane 9 |
stage-first-model |
全新配置的空书房点「还没有连接 AI 模型」里的「添加模型」,落在设置的 AI 模型,空状态「还没有添加模型」,唯一的主按钮是添加模型 | 首次使用的模型页 | 否 | 附录 A 首次使用 |
stage-rd5-tour |
30–60 秒的 RD-5 导览:空书房、新建「雾岛」进入设定页、写核心大纲并补齐必填、展开「文风」、下一步到架构、设置的 AI 模型与外观(切深色再切回)、关于与更新、回书房看书架、删除作品确认(名字不对时禁用)。配 --video 录评审视频 |
书房 | 否 | Review gate |
library-timing |
计时会话(与 startup-timing 同样先预启动一次,另用公开 IPC 新建 20 部作品):readyToShowToInteractiveMs(书房「新建作品」可见),以及页面里记下的 renderInteractiveMs(「新建作品」进入 DOM)与 renderShelfMs(20 个「预览《书名》」按钮都进入 DOM),都以导航开始为 0。旧欢迎页与新书房的书本按钮同名,所以对 trunk 也能跑 |
不截图 | 否 | perf |
stage-lazy-retry |
主进程 webRequest 拦下设定页代码块(blockChunks),重载后打开示例作品点「设定」,出现「页面没有载入」与「重试」;after 放行后点重试,设定页出现,且请求日志里有带 ?retry= 的设定页代码块 |
载入失败 | 否 | RD-5 修复第 1 轮 |
stage-setup-save-fail |
设定页改一句后让 project:save 返回失败(failProjectSaves 换掉主进程处理函数):Ctrl S 与「下一步」都在页脚出现 role=alert 的失败说明,仍停在设定、仍是未保存;after 换回处理函数再点保存,变为已保存、失败说明消失 |
保存失败 | 否 | RD-5 修复第 1 轮 |
stage-setup-short |
新建「雾岛」:必填项先不标红;1440×900、1280×800、1280×720 下「类型」「目标读者」都在底栏之上;after 点开「全局写作要求」,面板不在底栏后面、焦点在它的输入框里 |
1280×720 设定页 | 否 | RD-5 修复第 1 轮 |
stage-settings-legacy |
模型编辑表单的输入框 40px 高;context.shoot 中途拍下模型编辑、提示词模板、写作 Skills;项目备份页只有「导出本地存档」一个实心主按钮 |
项目备份 | 否 | RD-5 修复第 1 轮 |
stage-settings-leave |
编辑夹具模型改名,输入框里按 Esc 设置页不关;焦点移出后 Esc 弹「放弃未保存的修改?」;after 继续编辑修改还在,「返回作品」再确认放弃才关;再开设置页从 Ctrl K 选「角色」,设置页收起、「角色」标签选中 |
放弃确认 | 否 | RD-5 修复第 1 轮 |
stage-settings-leave-work |
作品里开着两个标签,设置页改了夹具模型名、不保存:标签条不显示;依次从流程脊阶段「架构」、流程脊资料「剧情与伏笔」、Ctrl K「蓝图」、Ctrl P「旧港」、Ctrl K「回到书房」、作品菜单「回到书房」离开,每次先弹「放弃未保存的修改?」,「继续编辑」后设置页与输入都在,再走一次选「放弃修改」才到去处 | 每个入口的确认(leave-<入口>) |
否 | RD-5 修复第 2 轮 |
stage-settings-leave-library |
书房里从顶栏打开设置、改模型名不保存:Ctrl K「打开《灯塔》」、Ctrl O、Ctrl K「打开作品」(系统对话框打桩为示例作品)、Ctrl N、Ctrl K「新建作品」、Ctrl K「小说拆解与仿写」,每次先确认、继续编辑不走;放弃后打开作品(等「项目数据加载完成」)或弹出新建、拆解对话框 | 每个入口的确认与到达(leave-、arrived-<入口>) |
否 | RD-5 修复第 2 轮 |
new-project-files |
新建作品后列出作品文件夹里建出的文件(measured.files)与 .ai-novel/project.json 去掉标识、时间后的形状(measured.manifest)。trunk 与 head、两种外壳(--shell stage)各跑一次,两项都应一致 |
新建作品后 | 否 | RD-5 lane 1 |
页面内计时
计时会话(startup-timing、library-timing)启动时设环境变量 DRIVE_RENDER_TIMING,offscreen-window.cjs 据此给默认会话注册页面预加载 render-timing-preload.cjs:它在页面脚本之前装好 MutationObserver,把「新建作品」与书架上的书第一次进入 DOM 的时刻(performance.now())写在 <html> 的 data-drive-interactive、data-drive-shelf 上,驱动启动后读出,写进 timing.renderInteractiveMs、timing.renderShelfMs。它们没有 Playwright 轮询的量化误差。其他场景不注册这个预加载。
改外壳时
类名选择器只出现在 scripts/redesign/pages/,按任务域分文件:shell(启动、外壳就绪、标题栏、状态栏、左右栏与可收起面板)、bookshelf(旧外壳书房与两种外壳的新建作品)、project(项目树)、chapter(单章写作、审稿、修稿合并、定稿)、run-panel(运行面板)、settings(设置,含外观里切换界面布局)、materials(知识库与角色卡导入)、stage(新外壳:流程脊、章节列表、标签条、Ctrl K 与 Ctrl P、保存状态、沉浸写作、书房)、run-sheet(新外壳的运行侧页)。shell.waitForShell 对两种外壳都成立。外壳替换后只改这些页面对象,场景 scripts/redesign/scenarios.mjs 不动。
/.claude/ 在 .gitignore 里,提交本文件的改动要用 git add -f .claude/skills/verify/SKILL.md(或 git add -u)。假模型在 scripts/redesign/fake-model.mjs,按提示词特征返回正文、短细纲(与正文同一段文字,但不参与定速流出)、审稿 JSON、修稿正文、角色状态 JSON 或角色提取 JSON。
架构阶段与角色名单(RD-6 起)
场景在 scripts/redesign/arch-scenarios.mjs,页面对象在 scripts/redesign/pages/architecture.mjs(四节是 region,按节名命名;角色名单左栏是 complementary「角色名单」;生成架构对话框是 dialog「生成架构」)。示例作品沿用「灯塔」,按场景清空架构的某几节;示例作品有蓝图与正文,打开后落在写作位置(用户决定 B,#394 §6),场景等落点定下后从流程脊进架构。驱动读库用界面那次打开作品的会话(在主进程里包一层 project:open 记下租约),不必重开作品。夹具模型对「本次只写第 N 章」的情节大纲请求回这一章的二级标题与正文。
| 名称 | 检查 | 截图停在 | 夹具模型 | 对应计划 |
|---|---|---|---|---|
arch-regression |
清空前提、世界观、大纲后从架构页生成(角色名单已预置),measured 记下四份文档与哈希;head 与 trunk(--app-root,旧故事架构总览)各跑一次,四份文档逐字相同 |
生成完的架构页 | 是 | lane 1 |
arch-partial |
两节已确认:主按钮「继续生成架构」且只有一个、「下一步:章节蓝图」置灰,四节徽标,流程脊同为 2 / 4,角色名单一节列出林岚 | 架构页 | 否 | lane 2 |
arch-done |
四节已确认:主按钮「下一步:章节蓝图」;after 点它进入蓝图 |
架构页 | 否 | lane 3 |
arch-confirm |
生成架构对话框:勾选已确认的前提标「将覆盖」,角色名单「保留」,空的两节「新生成」 | 对话框 | 否 | lane 4 |
arch-resume |
24 章的大纲先生成 1–10 章,从提示条续写 11–16 章,提示条写明第 17–24 章还没有大纲;部分完成不算已确认(页头与流程脊 3 / 4、主按钮继续生成、下一步置灰),运行侧页两张大纲恢复稿按范围区分;after 续写 17–24 章,1–16 章逐字不变、1–24 章各一次 |
第 17–24 章的续写对话框 | 是 | lane 5 |
arch-rewrite |
大纲写到 16 / 24 章后先把第 1–5 章改成作者旧稿,从「AI 重新生成此节…」选第 1–5 章:默认起始章 17,标「将覆盖第 1–5 章」并写明第 6–16 章原样保留,可以提交;after 生成后第 6 章起逐字不变、第 1–5 章换成本次结果,大纲仍是部分完成 16 / 24,页头与流程脊 3 / 4 |
第 1–5 章的重写对话框 | 是 | 修复第 2 轮 |
arch-legacy-sidebar |
--shell writer(发布默认外壳):大纲分批写到 16 / 24 章,侧栏「故事架构 4/4」,情节大纲一行不是待生成、行内有清空按钮、右键「清空情节大纲」可用;侧栏写「角色名单」 |
右键菜单 | 否 | 修复第 2 轮 |
arch-names-en |
英文界面:四节 Premise、Cast、World、Outline,名单菜单「View cast as text」打开「Cast as text」标签与指向 Cast 页的横幅,没有旧名字,名单底栏「1 character」 | 角色名单 | 否 | 修复第 2 轮 |
arch-clear |
世界观「清空此节…」出现危险确认;after 取消,摘要、徽标与数据库里的世界观都不变 |
危险确认 | 否 | lane 6 |
arch-cast-save |
新建「守塔人」并按 Ctrl S 保存:名单、名单投影(db:character-roster-read 的 renderedMarkdown)、架构页「2 位角色」与「查看角色名单全文」都有守塔人 |
角色名单 | 否 | lane 7 |
arch-graph |
关系图谱放大、滚轮、拖拽(画面变化)都生效;after 点中心节点打开档案 |
关系图谱 | 否 | lane 8 |
arch-cards |
角色名单里粘贴两张角色卡,运行侧页确认后守塔人进名单、林岚仍只有一个 | 角色名单 | 是 | lane 9 |
arch-import-dialog |
导入角色卡对话框与外发确认是同一个纸墨对话框的两步(.pi-dialog、底色等于 --surface,不另弹确认框);after 返回并关闭 |
外发确认 | 是 | lane 9 |
arch-dark |
用 --theme dark 跑(漏传时开头的主题断言失败):架构页文字对比度达标(名称与正文 4.5:1,说明 3:1),分节卡底色等于 --paper 的计算值 |
架构页 | 否 | lane 10 |
arch-timing |
从点流程脊「架构」到四节可交互的毫秒数(measured.openMs 按动画帧轮询;openDomMs 是 DOM 达到就绪的时刻,屏幕外窗口的动画帧会被节流;ipcDuringOpen 是这段时间主进程按通道收到的 invoke 数),200 位角色时角色列表第 1 页滚动帧率(measured.scrollFps)。trunk 是旧故事架构标签与旧角色列表,head 是架构阶段与角色名单 |
角色列表 | 否 | perf |
arch-tour |
30~60 秒的导览:四节与主按钮、对话框的覆盖与保留、清空此节的危险确认、角色名单保存与关系图谱。配 --video 录评审视频 |
架构页 | 否 | Review gate |
perf 交替各跑 5 次取中位数:
node scripts/redesign/drive.mjs --scenario arch-timing --app-root <trunk 工作树> --out <目录>
node scripts/redesign/drive.mjs --scenario arch-timing --out <目录>
蓝图阶段与写作弹层(RD-7 起)
场景在 scripts/redesign/blueprint-scenarios.mjs,页面对象在 scripts/redesign/pages/blueprint.mjs(章节规划是 complementary「章节规划」,单章蓝图是 region「第 N 章蓝图」,写作弹层是 dialog「本次写作选项」,主按钮「写第 N 章」直接开始写)。新外壳从蓝图写下一章的场景(stage-run、stage-tour、运行侧页各场景、write-stream --shell stage)都改走 blueprint.writeNext;旧外壳仍走 chapter.writeNextChapter。新外壳写作此章按设定里的每章字数写,不再在写作时填字数,所以示例作品的每章字数是夹具模型一次写得完的 100。假模型另记 fake.chats:每次对话请求的种类、模型与消息原文。
| 名称 | 检查 | 截图停在 | 夹具模型 | 对应计划 |
|---|---|---|---|---|
blueprint-regression |
第 3 章蓝图带出场人物与作者指导,从蓝图写下一章:旧外壳点「写作第 3 章」在对话框里直接开始,新外壳点「写第 3 章」。measured.requests 是每次模型请求的种类、模型与消息的 sha256,proseMessages 是正文请求原文。trunk(--app-root)与 head(--shell stage)两边的 requests 相同即通过 |
写出的草稿 | 是 | lane 1 |
blueprint-page |
选中第 5 章:标题「逐章规划」、主按钮「写第 3 章」、12 章规划、页头只有一个拆分主按钮、蓝图页文字对比度(名称 4.5:1,说明 3:1;章节规划的状态文字 .stage-bp-plan-status 每种状态都查,含默认的待写)。选择器清单是 blueprint-scenarios.mjs 的 PAGE_CONTRAST,算法与外壳共用 scenarios.mjs 的 contrastFailures。浅色、深色各跑一次 |
蓝图页 | 否 | lane 2、lane 10(--theme dark) |
blueprint-popover |
打开「本次写作选项」:只有本次模型、作者微操指导、折叠的更多(检索关键词),整页只有这一个对话层 | 写作弹层 | 否 | lane 3 |
blueprint-preflight |
主进程里把 db:continuity-list-before 换成夹具(第 1 章守塔人已死),点写第 3 章:弹层里出现一致性预检,有保存安排、仅本次忽略、改蓝图后重检,模型没有收到请求;after 换回原处理函数后仅本次忽略,写完 |
一致性预检 | 是 | lane 4 |
blueprint-overwrite |
AI 生成蓝图选覆盖后开始:生成对话框先收起,危险确认「覆盖已有蓝图?」写明会替换 12 章;after 取消后生成对话框原样回来,没有错误提示,蓝图不变 |
覆盖确认 | 否 | lane 5 |
blueprint-batch |
删掉 3、4 章草稿后批量创作 4 章:运行侧页出现批量卡(第 3 至 6 章);after 取消 |
批量卡 | 是 | lane 6 |
blueprint-clear |
更多蓝图操作的危险分组里清空全部蓝图,危险确认后列表为空,出现空状态与 AI 生成蓝图 | 空状态 | 否 | lane 7 |
blueprint-recover |
规划 16 章,生成第 13~16 章蓝图(假模型回正文,生成失败留下恢复稿):蓝图页出现恢复稿提示条,「编辑恢复稿」打开恢复稿标签,「继续生成缺少的章节」可用;after 点它,模型再次收到请求 |
恢复稿标签 | 是 | lane 8 |
blueprint-save |
改第 6 章标题:整页只有顶栏一处「未保存」,Ctrl S 后变「已保存」,重新加载后标题仍在 | 已保存 | 否 | lane 9 |
blueprint-finalize-next |
第 3 章草稿定稿,设置里开着「定稿后打开下一章」(F-056):落到第 4 章的单章视图,写作弹层由这一章「写作此章」旁的「本次写作选项」打开(aria-controls 指向弹层)并贴着它展开,只弹出写作弹层,没有旧的创作对话框 |
写作弹层 | 是 | F-056 |
blueprint-tour |
30–60 秒导览:选章改标题保存、清空的危险确认、生成蓝图覆盖、批量创作、写作弹层、一致性预检、仅本次忽略后写完。配 --video 录评审视频 |
写完一章 | 是 | Review gate |
blueprint-timing |
300 章蓝图:从点蓝图到第 300 章出现在列表里(openMs),从点第 150 章到它的标题出现(switchMs),渲染进程内按帧计时。旧外壳点项目树「章节蓝图」与列表项,两种外壳都能跑 |
第 150 章 | 否 | perf |
node scripts/redesign/drive.mjs --scenario blueprint-regression --app-root <trunk 工作树> --out <目录>/trunk
node scripts/redesign/drive.mjs --scenario blueprint-regression --shell stage --out <目录>/head
node scripts/redesign/drive.mjs --scenario blueprint-timing --app-root <trunk 工作树> --out <目录>
node scripts/redesign/drive.mjs --scenario blueprint-timing --shell stage --out <目录>
正文单章视图(RD-8 起)
场景在 scripts/redesign/chapter-scenarios.mjs,页面对象在 scripts/redesign/pages/chapter-view.mjs(单章视图是 .stage-ch,审稿侧页是 complementary「审稿报告」,修稿合并是 region「修稿合并」,定稿后处理是 region「定稿后处理」,版本切换器是按钮「本章版本:…」,定稿确认是 dialog「定稿第 N 章?」)。新外壳打开第 N 章就是单章视图,示例作品第 3 章带一份审稿(已审稿,打开时默认展开审稿侧页);待写章显示本章蓝图与「写作此章」,草稿状态主按钮是 AI 审稿,已审稿是「按 N 项意见修稿」,有待合并修稿时直接摆出合并视图,已修稿是定稿,定稿后列出后处理各步。假模型另有 fake.breakCharacterState():之后定稿后处理的角色状态更新收到不是 JSON 的回复而失败,传 false 恢复。
| 名称 | 检查 | 截图停在 | 夹具模型 | 对应计划 |
|---|---|---|---|---|
chapter-regression |
删掉 3、4 章草稿后写第 3 章,走完审稿、按意见修稿、全部用修稿合并、等复验、定稿;measured 是定稿正文的 sha256 与后处理各步成败(从数据库读)。trunk(--app-root,旧外壳)与 head(--shell stage)两边相同即通过。读库要回书房重开作品,新外壳之后再打开第 3 章 |
定稿视图(新外壳)、书房(旧外壳) | 是 | lane 1 |
chapter-draft |
第 4 章草稿:主按钮 AI 审稿,生命周期停在审稿,版本切换器「草稿 v1 · N 字」 | 草稿 | 否 | lane 2 |
chapter-review |
第 4 章 AI 审稿后侧页展开;取消、再勾一条意见时主按钮「按 N 项意见修稿」与侧页底部「N / 总数」同步 | 审稿侧页 | 是 | lane 3 |
chapter-manual |
添加我的意见后修稿,假模型收到的修稿请求里有这条意见 | 合并视图 | 是 | lane 4 |
chapter-merge |
修稿后合并视图第一处用修稿(多于一处时第二处手动编辑);after 完成合并,正文里是选中的文字 |
逐段选择 | 是 | lane 5 |
chapter-finalize |
第 3 章从「更多」定稿,确认后正文只读,后处理「4 / 4 完成」(正文文件与三步后处理) | 定稿视图 | 是 | lane 6 |
chapter-retry |
角色状态更新失败后点「重试失败步骤」:之后假模型只收到角色状态请求,后处理回到 4 / 4 | 重试后的定稿视图 | 是 | lane 7 |
chapter-selection |
选中一段:工具条四个纸墨按钮(润色、扩写、续写、改成对话);润色预览后替换,再选一段润色后取消,原文不变 | 选区工具条 | 是 | lane 8 |
chapter-delete |
第 4 章有 v1、v2:从「更多」删除这一稿出现危险确认;after 确认后版本切换器只剩 v1 |
危险确认 | 否 | lane 9 |
chapter-1280 |
视口 1280×900(配 --theme dark):第 3 章打开时审稿侧页已展开,收起它后正文一行 32~35 字;运行侧页打开后不少于 24 字,页面没有横向滚动 |
运行侧页与纸面 | 否 | lane 10 |
chapter-sheet-landing |
删掉第 4 章的稿,打开作品落在已审稿的第 3 章:审稿侧页刚出现与 4 秒后都展开(不先开后收);换到带历史审稿的已定稿第 2 章不展开,「更多」里有审稿报告;回到第 3 章仍展开 | 审稿侧页 | 否 | 侧页归属 |
chapter-sheets-1280、chapter-sheets-1440 |
第 3 章(已审稿)在该宽度下先开运行侧页、再从「更多」开审稿报告:同一时间只有一个侧页,纸面不被盖住,正文一行不少于 24 字,没有横向滚动 | 审稿侧页与纸面 | 否 | 双侧页 |
chapter-focus |
1440 宽打开第 4 章进入沉浸写作:内容面板无外边距、圆角与阴影(全出血);底部「N / 设定每章字数 字」与进度条;正文首行缩进 36px | 沉浸写作 | 否 | Focus 画板 |
chapter-tour |
30~60 秒导览:检查维度、审稿侧页与作者意见、按意见修稿、逐段合并、定稿确认、定稿后处理。配 --video 录评审视频 |
定稿视图 | 是 | Review gate |
chapter-open |
1 万字的第 5 章:从点击(新外壳点流程脊里的章,旧外壳点草稿箱)到正文出现且所在滚动区可以滚动,毫秒,不取整。frameMs 按动画帧检查,domMs 在 DOM 变化回调里记,不依赖动画帧 |
第 5 章 | 否 | perf |
typing-latency |
在第 5 章第 1 段末尾连续输入 40 个字母:每键从 beforeinput 到正文 DOM 变化(domP95Ms)与之后第一帧(frameP95Ms) |
第 5 章 | 否 | perf |
node scripts/redesign/drive.mjs --scenario chapter-regression --app-root <trunk 工作树> --out <目录>/trunk
node scripts/redesign/drive.mjs --scenario chapter-regression --shell stage --out <目录>/head
node scripts/redesign/drive.mjs --scenario chapter-open --app-root <trunk 工作树> --out <目录>
node scripts/redesign/drive.mjs --scenario chapter-open --shell stage --out <目录>
node scripts/redesign/drive.mjs --scenario typing-latency --app-root <trunk 工作树> --out <目录>
node scripts/redesign/drive.mjs --scenario typing-latency --shell stage --out <目录>
草稿、审稿、合并、定稿、1280 与沉浸写作各场景都用 contrastFailures 核对单章视图的文字对比度(正文与合并栏 4.5,说明文字 3)。屏幕外窗口的动画帧可能被系统节流,chapter-open 与 typing-latency 都同时报不依赖动画帧的 DOM 口径。RD-X1 起打开作品的默认落点随提交同步落下,读文件树期间打开的运行侧页不再被收起(x1-run-sheet-keep);afterProjectOpenSettles 的 2 秒等待是之前留下的,保留无害。审稿侧页属于单章视图,不随落点收起。
作品资料页(RD-9 起)
场景在 scripts/redesign/refs-scenarios.mjs,页面对象在 scripts/redesign/pages/refs.mjs(流程脊「作品资料」里的三个按钮;剧情树是 table「剧情树」,线索路线是 list「线索路线」,知识库资料是 navigation「资料」,版本历史的章节是 navigation「章节」、各稿是 list「版本时间线」、对比是 region「对比」里的 article「与当前稿的差异」)。示例作品在 seedStageSample 之上加一条伏笔线索「雾钟为何提前」和第 3 章的第二稿。fake.replyPlotTree() 之后的剧情树整理回一份两轨 JSON(定稿章与单数位蓝图章进主线「雾钟与沉船」,双数位蓝图章进支线「父亲的地图」),来源取自提示里的资料;不开时假模型回正文,剧情树落到单轨的确定性快照。知识库导入用 stubOpenFiles 让系统打开对话框直接返回两份资料,外发提取确认点「取消」。
| 名称 | 检查 | 截图停在 | 夹具模型 | 对应计划 |
|---|---|---|---|---|
refs-regression |
生成剧情树后从主进程读出快照,measured.tracks 是轨道与事件。head 用 --shell stage,trunk 用 --app-root,两边 tracks 逐字相同即通过 |
剧情树 | 是 | lane 1 |
refs-plot |
剧情树两行依次是主线、支线,主线有已定稿发生的事件;页面写明只读快照、不参与写作;点事件后出现「打开来源:第 1 章定稿」 | 选中事件的剧情树 | 是 | lane 2 |
refs-clear |
「更多」里的「清除剧情树…」弹出危险确认;after 取消,剧情树仍在 |
危险确认 | 是 | lane 3 |
refs-threads |
线索路线起初是埋设未到、推进不显示、解决未到;记录第 1 章定稿里的变化后,埋设一站变成已发生 | 推进后的线索 | 否 | lane 4 |
refs-delete |
线索行「更多」里的「删除线索…」弹出危险确认;after 取消,线索仍在 |
危险确认 | 否 | lane 5 |
refs-kb |
导入两份资料后查「雾钟」,结果片段里标出查找词;整窗文字、可访问名称、提示与占位里没有 LanceDB、FTS、BM25、Embedding、向量、query、MCP、token | 查找结果 | 是 | lane 6 |
refs-kb-dirty |
改了项目副本不保存就点另一份资料,弹出放弃修改的确认;after 选「继续编辑」,修改还在,再按 Ctrl S 保存后「有未保存的修改」消失 |
未保存确认 | 是 | lane 7 |
refs-diff |
第 3 章选草稿 v1:对比是 aria-readonly 的差异页,标出新增,区域里没有输入框、可编辑元素或编辑器,没有「完成合并」 |
只读对比 | 否 | lane 8 |
refs-revert |
回退到草稿 v1:确认里写明新建草稿 v3;确认后时间线依次是草稿 v3、v2、v1,选 v3 显示「与当前稿相同」 | 回退后的时间线 | 否 | lane 9 |
refs-dark |
用 --theme dark 跑:知识库、版本历史、剧情树三页各查一次资料页文字对比度(标题与正文 4.5:1,说明 3:1;选中章序号、选中稿说明与对比里删去的字按 4.5:1),最后再查外壳 |
深色剧情树 | 是 | lane 10 |
refs-kb-finalized |
在第 3 章正文里点「定稿」并确认,等运行侧页写明已完成;知识库「定稿章节 1」里是第 3 章、「我导入的 0」,点开只有「这一章由定稿自动收入」,没有编辑框 | 定稿章节一栏 | 是 | 定稿入库 |
refs-narrow-{plot,kb,history}-{1280,1440} |
视口 1280 或 1440,导入资料后运行侧页开着:剧情树的模型、生成与「更多」同一行,线索名称不折行、「更多」与路线同一行;知识库原文宽不小于 300px;版本对比头的标签都不折行、对比正文宽不小于 420px。measured.contentWidth 是内容区宽 |
侧页开着的资料页 | 是 | 窄宽度 |
refs-tour |
30–60 秒的导览:生成剧情树、选事件、清除确认后取消、伏笔线索、导入资料并查找、版本对比、回退新建 v3。配 --video 录评审视频 |
剧情与伏笔标签 | 是 | Review gate |
refs-timing |
100 章、每章 5 稿,用夹具模型整理好剧情树并停在剧情树页;计时从点版本历史到第 100 章出现在章节列表(historyOpenMs),再从点剧情树到第 1 章事件出现在表格里(plotOpenMs),渲染进程内按帧计时 |
剧情树 | 是 | perf |
perf:trunk 与 head 交替各跑 5 次,取两项各自的中位数。head 加 --shell stage,trunk 用旧外壳的左栏「历史」「剧情」进入。
node scripts/redesign/drive.mjs --scenario refs-timing --app-root <trunk 工作树> --out <目录>
node scripts/redesign/drive.mjs --scenario refs-timing --shell stage --out <目录>
统一视觉层(RD-V)
场景在 scripts/redesign/visual-scenarios.mjs,都走新外壳,浅深各跑一次。断言的是浮层渲染进带 .paper-ink 的纸墨根或宿主(#ai-novel-ink-overlay),才取得到纸墨令牌与深色。对话框类场景截图前等 400 ms,让遮罩与对话框的淡入走完。
| 名称 | 检查 | 截图停在 | 夹具模型 |
|---|---|---|---|
rdv-clear |
作品菜单「清除生成内容…」:标准危险确认,焦点在「取消」,三类内容是勾选行,取消一项后后果句改成「将清除 2 类内容」;after 按 Esc 关闭 |
危险确认 | 否 |
rdv-alert |
书房里在同一目录再建一部同名作品,主进程拒绝,命令式 alertError 渲染进纸墨宿主,焦点在「确定」,旧「新建小说项目」对话框也在宿主里;after 点「确定」 |
叠在新建作品对话框上的错误弹框 | 否 |
rdv-toasts |
预置两条调用记录后写一章,在诊断分页连点三次「复制安全诊断」再让剪贴板失败点一次:三次成功合并成一条,出错的另起一条,只有一个提示栈,通知互不重叠,measured.toasts 是栈里的条数 |
右下角提示栈 | 是 |
rdv-toast-error |
同上写一章,先复制成功一次让提示栈出现,再打开 Ctrl K 面板(Radix 模态)后让复制失败:出错通知是八角符号,卡片自身不带 role,不在 aria-hidden 子树里,经挂载点 #ai-novel-ink-toasts 的 aria-live="polite" 播报(挂载点内没有任何 role="alert"),面板仍开着;after 按 Esc |
面板上方的出错通知 | 是 |
rdv-toast-flood |
打开样例作品,按 app.getAppPath() 找到构建产物 dist/assets/ToastStack-*.js,在页面里 import 同一模块(与应用共享栈状态),推入 24 条常驻出错通知:栈在顶栏以下(top >= 48)、视口以内,标 data-overflow 可滚动,最新一条露在栈底;滚到顶关掉最早那条剩 23 条,中途拍 rdv-toast-flood-top。推入函数是按压缩产物里的 exiting:!1 找到的,换压缩器或改了条目字段就要改这里 |
滚回底部的满栈 | 否 |
rdv-clear-busy |
主进程的 db:project-clear-generated-data 换成永不返回,点「清除所选」:按钮写「清除中…」、aria-busy、禁用,三个勾选禁用,Esc 关不掉,指针停在按钮上 |
清除中的危险确认 | 否 |
rdv-run-failure |
粘贴一张角色卡但假模型不回提取 JSON:运行失败,运行卡里的失败提示是朱批(没有底色);关掉导入对话框 | 运行侧页的失败提示 | 是 |
rdv-export |
作品菜单「导出…」:旧导出对话框 Portal 进纸墨宿主,外壳是 pi-dialog |
导出对话框 | 否 |
rdv-import-novel |
作品菜单「小说拆解与仿写…」:旧拆解对话框 Portal 进纸墨宿主 | 拆解对话框 | 否 |
rdv-settings |
从流程脊打开设置,先进「提示词模板」中途拍 rdv-settings-prompts,再进「项目备份」;after 点「返回作品」。两页都是旧面板,看旧按钮变体在新外壳下换成纸墨按钮 |
项目备份(中途一张提示词模板) | 否 |
rdv-tour |
30–60 秒的评审导览:清除生成内容的危险确认(勾掉一项)、旧导出对话框、写一章后连点「复制安全诊断」看提示栈(两次成功合并,一次失败另起出错通知)、粘贴角色卡看运行失败的朱批提示。配 --video 录评审视频 |
运行失败提示 | 是 |
外部审查修复(RD-X1)
场景在 scripts/redesign/x1-scenarios.mjs,都走新外壳。竞态用主进程通道上的门稳定复现:holdChannel(app, 通道, { after }) 卡住接下来的调用,after: true 时先交给原处理函数、卡住的是回复(主进程已做完、渲染进程迟迟收不到);untilHeld 等到有调用卡在门上,releaseChannel 放行。recordCalls 记下通道之后每次调用所属的作品路径,stubChannel 把通道换成固定回复并计数;两者遇到主进程没有的通道都直接报错,通道改名后断言不会因为记不到调用而假绿。seedTwoBooks 先建「港口」(三章定稿,第 3 章定稿带历史审稿),再建并打开灯塔;两部作品第 3 章的稿 id 相同。假模型另有 fake.failProse():之后的正文回复(含 streamProse 的流式回复)以 content_filter 结束,写稿在这次打开里失败。蓝图页的 generateRange 让「架构还不完整」警告与运行侧页展开竞争等待,调用前运行侧页要收起。除 x1-open-folder-cancel(RD-V 栈顶上也应通过)和 x1-import-overlap(RD-V 栈顶不适用)外,每个场景对 RD-V 栈顶的构建(--app-root)跑一次应失败;所有场景对 head 跑一次都应通过。
| 名称 | 检查 | 截图停在 | 夹具模型 | 对应 |
|---|---|---|---|---|
x1-kb-late-read |
导入两份资料;点「守塔人小传」时读取卡住,切到版本历史再切回,改「沉船名录」后放行:编辑框仍是改过的沉船名录,带未保存标记 | 知识库 | 是 | #388 T1 |
x1-setup-leave |
设定页改一句点「下一步」,保存卡住时回书房,放行后仍在书房 | 书房 | 否 | #380 C4 |
x1-settings-section |
写作 Skills 填地址不保存:Ctrl K「设置」先确认,继续编辑留在原页、输入还在;作品菜单「项目备份」确认放弃后到项目备份 | 项目备份 | 否 | #380 C1 |
x1-write-switch |
一致性预检里保存安排、回复卡住时回书房用 Ctrl K 打开港口(作品条目只在书房的 Ctrl K 里),放行后港口里没有写作的启动调用,模型没收到正文请求 | 港口 | 是 | #387 C1 |
x1-waive-all |
第 4 章 AI 审稿(复验周期由审稿写回建立,才有「不修改此项」),侧页每条都选「不修改此项」:主按钮变成「确认不修改」,确认后提示已确认;换到第 3 章再回来仍是已确认(读自数据库) | 第 4 章 | 是 | #392 T1 |
x1-cleanup-retry |
第 3 章另有草稿 v1;把 v2 定稿(真实后处理写出正文文件),另起 PowerShell 进程只共享读地占住正文 txt(按 PID 结束),删除正文:落在 v1 的单章视图上,有「删除正文后的清理没有完成」且原因是 EBUSY;放开文件后点重试清理,提示消失、文件已删 | v1 单章视图 | 是 | #392 T2 |
x1-run-recovery |
failProse 后写下一章:运行失败,运行侧页「可恢复的内容」立即列出第 3 章候选 |
运行侧页 | 是 | #381 C1 |
x1-waiver-switch |
第 4 章 AI 审稿后每条都选「不修改此项」,点「确认不修改」时读审稿原文卡住;回书房用 Ctrl K 打开港口并打开运行侧页,放行后运行侧页还开着,没有被换成灯塔那一稿的审稿侧页 | 港口运行侧页 | 是 | #405 r2 C1 |
x1-setup-save-remount |
设定页改一句按 Ctrl S,保存卡住时切到第 3 章标签再切回:下一步仍不可点,再按 Ctrl S 也不重发,放行后主进程只收到 1 次保存 | 设定 | 否 | #405 r2 复验低项 7 |
x1-generate-slow-warning |
规划 16 章,生成第 13~16 章蓝图时读架构(db:project-core-get)卡 4.5 秒:「架构还不完整」晚于 3 秒出现,generateRange 仍点继续生成,运行侧页展开 |
运行侧页 | 是 | #405 r2 O8 |
x1-generate-no-warning |
同上但主进程读架构时补上角色名单:没有警告,generateRange 在运行侧页展开时返回,记下耗时(旧写法固定多等 3 秒) |
运行侧页 | 是 | #405 r2 O8 |
x1-review-sheet-switch |
灯塔第 3 章审稿侧页开着时回书房用 Ctrl K 打开港口,再开港口同 id 的已定稿第 3 章:审稿侧页不展开 | 港口第 3 章 | 否 | #399 §1 |
x1-import-settings |
书房里导入旧项目副本(对话框与复制打桩,复制卡住),期间在设置页填地址;复制完成要打开作品时先确认,继续编辑后设置页与输入都在,作品没有打开 | 设置页 | 否 | #404 第 1 项 |
x1-open-folder-order |
设置页有没保存的输入时 Ctrl O、作品菜单「打开其他作品…」先确认,确认框出现时还没有弹选文件夹,继续编辑后也不弹 | 设置页 | 否 | #404 第 2 项 |
x1-open-folder-cancel |
选文件夹打桩成取消。设置页有没保存的输入时 Ctrl O、作品菜单「打开其他作品…」(问放弃就选放弃修改),再清空输入后 Ctrl O:三次之后设置页都还开着,输入还在。RD-V 栈顶上也应通过(它先选文件夹),上一轮 45656084 上失败 | 设置页 | 否 | #405 r1-1 |
x1-import-overlap |
同 x1-import-settings 到确认框出现,再按 Ctrl N:出现提示「请先处理『放弃未保存的修改?』」;选继续编辑:没有弹新建,输入还在,回书房后「导入旧项目副本…」可点。RD-V 栈顶没有这个确认框,不适用;上一轮 45656084 上导入入口一直禁用 |
书房导入菜单 | 否 | #405 r1-2 |
x1-open-folder-pick |
只替换 Electron 的选文件夹对话框(选到港口,授权照常签发)。灯塔设置页有没保存的输入时 Ctrl O:确认框出现前没弹选文件夹,选放弃修改后弹一次,设置页收起、打开港口,不再问。RD-V 栈顶先选文件夹,失败 | 港口 | 否 | #405 r1-1 |
x1-library-return |
先回一次书房,再从书房 Ctrl K 重新打开灯塔,读文件树卡住时进作品又回书房,放行后仍在书房(落点晚到的版本只比较提交前后的布局,两次都是作者亲手回的书房) | 书房 | 否 | #403 |
x1-run-sheet-keep |
从书房打开灯塔,读文件树卡住时打开运行侧页,放行后侧页仍开着 | 运行侧页 | 否 | #395 |
外部审查修复(RD-X2)
场景在 scripts/redesign/x2-scenarios.mjs,都走新外壳,复用 RD-X1 的 holdChannel、untilHeld、releaseChannel 与 seedHarbor。每个场景把作者看到的值收进 measured 最后一次断言,对 RD-X1 栈顶的构建(--app-root)跑一次应失败,失败消息里能看到每一项的值。假模型另有 fake.replyReview(json):之后的审稿(含合并后的复验)回这份 JSON;复验只覆盖带正文证据区间的本章目标意见,默认审稿只有文学类意见,合并后不会复验。主进程没有默认检索模型时退回默认生成模型,所以要演示「没有检索模型」得先删掉生成模型。
| 名称 | 检查 | 截图停在 | 夹具模型 | 对应 |
|---|---|---|---|---|
x2-landing |
「荒岛」只有架构(大纲分批写到第 6 章)、「北堤」再加三章蓝图、「南湾」只有第 1 章定稿没有蓝图、「空港」只有一份空的草稿、灯塔(同样的大纲)有蓝图与正文、第 3、4 章都在写:书房依次打开分别落在架构、正文第 1 章、正文第 1 章、架构(空稿不算开始)、正文第 4 章(最后一章在写的);再从书房「打开作品」选文件夹打开灯塔,仍落在第 4 章;点第 1 章再点「正文」回到第 4 章;回书房后主按钮是「继续写作 · 第 4 章 · 待审稿」 | 书房概览 | 否 | #394 §6、#407 第 2 轮第 1、2 条 |
x2-outline |
大纲带分批尾标但末尾多一个换行:徽标「不完整」、页头 3 / 4、下一步不可点;生成对话框选 1–12 章标「范围无效」、提交不可点 | 架构页 | 否 | #394 §1、§2 |
x2-library-overview |
书房预览港口后点「回到《灯塔》」,概览不再是读取中、显示摘录;再预览港口并从最近项目移除它,灯塔概览照常 | 书房 | 否 | #380 C3、O23 |
x2-history |
版本历史再点第 3 章各稿还在;读第 4 章各稿卡住时显示「正在读取…」;版本历史与单章版本切换器的时间等于库里 UTC 时刻换成本地时间 | 第 3 章 | 否 | #388 T2、T12、T8 |
x2-index-model |
有检索模型并导入资料后去掉生成模型,在设置「检索模型」页删掉检索模型:索引区回到「配置并启用检索模型后…」,没有重建按钮 | 检索模型页 | 是 | #388 T3 |
x2-kb-limit |
查找「守塔人」后在框里改字不提交,「最多显示」改成 5:主进程收到 [守塔人,10]、[守塔人,5] 两次查找 |
知识库 | 是 | #388 T15 |
x2-cast |
角色档案三个视图里只有基础设定有头像按钮;粘贴角色卡的全文框至少 9 行高 | 角色名单 | 否 | #389 X1、O#2 |
x2-recheck |
replyReview 让审稿回第 4 章关键事件未完成(带证据);审稿、按意见修稿、全部用修稿合并,自动复验跑完:提示「复验完成:x / y 项意见已解决」,审稿报告逐项标复验结果 |
审稿报告 | 是 | #392 T3 |
x2-blueprint-save |
蓝图页改第 5 章标题并「保存此章」,流程脊第 5 章显示新标题 | 第 3 章 | 否 | #377 R1 |
x2-open-chapter |
读第 4 章正文卡住时点流程脊「设定」,放行后仍在设定 | 设定页 | 否 | #377 R2 |
外部审查修复(RD-X3)
场景在 scripts/redesign/rdx3-scenarios.mjs,都走新外壳。要看修复前的样子,用 --app-root 指向 RD-V 栈顶(87097dbb)的构建再跑一次:这些场景在那边应当失败。
| 名称 | 检查 | 截图停在 | 夹具模型 |
|---|---|---|---|
rdx3-popover-1280、rdx3-popover-1024 |
视口设成 1280×720 或 1024×640,第 3 章出场三人,主进程的 db:continuity-list-before 换成三人都已死的事实:写作弹层出三条预检提醒,停在视口内(下沿留 8px)并在内部滚动,滚到底「仅本次忽略」在视口内点得到,内部滚动不关弹层;中途拍 -top,after 换回原处理函数并按 Esc |
滚到底的写作弹层 | 是 |
rdx3-keyboard |
按 Tab 走到流程脊当前阶段行、激活的内容标签、拆分主按钮两半、运行侧页分段页签的选中项,各自 :focus-visible 且 box-shadow 含强调色,逐个截图;measured 是五处的 box-shadow |
运行侧页的分段页签 | 否 |
rdx3-import-dialog |
作品菜单「小说拆解与仿写…」:对话框里只有一个 .pi-btn--primary,带 aria-pressed 的切换按钮都是次按钮;after 按 Esc |
拆解对话框 | 否 |
rdx3-toast-resize |
推入 11 条常驻出错通知(推入函数的找法同 rdv-toast-flood),1440×900 下不溢出;视口缩到 1100×640 后栈标 data-overflow、最新一条露在栈底、卡片右缘到窗口右缘的距离不变。measured.shiftWithoutCompensation 是去掉滚动条补偿时卡片会左移的像素 |
缩窗后的满栈 | 否 |
rdx3-long-title |
主进程把 project:open 返回的作品名换成 80 个字(项目文件夹不能这么长),视口 1024×640:顶栏作品名以省略号收尾,关闭按钮右缘在窗口内 |
顶栏 | 否 |
rdx3-inline-confirm-focus |
写一章让诊断分页有日志:「清空日志…」的确认条用鼠标点「保留」、按 Esc、键盘打开后 Esc 与回车「保留」,恢复候选「放弃…」的确认条点「保留」与按 Esc,每次焦点都回到打开它的按钮。measured.focusLog 是页面里记下的每次焦点移动 |
诊断分页 | 是 |
rdx3-plan-ring |
蓝图页选中第 5 章,当前章行与第 6 章行各按 Tab 聚焦:截行四周的图数强调色像素,聚焦比不聚焦多出一整圈 2px 环(不少于 4 ×(宽 + 高)× 0.8),只选中的当前章没有这圈环;withoutContainment 是去掉列表项 content-visibility 后的同一计数,与聚焦时相等说明环没被裁。像素解码在 png.mjs,与 pixel-diff.mjs 共用 |
第 6 章行聚焦 | 否 |
rdx3-work-menu-focus |
作品菜单「导出…」「小说拆解与仿写…」「清除生成内容…」打开的对话框,按 Esc、点「取消」或「关闭」关掉后焦点都回到作品菜单按钮 | 回到作品菜单按钮后 | 否 |
rdx3-toast-wheel |
作品菜单「清除生成内容…」开着(Radix 模态)时推入 24 条常驻出错通知:栈可滚动、滚动条 6px,鼠标停在栈上真滚轮往上滚超过 100px | 滚上去的满栈 | 否 |
rdx3-write-after-discard |
开着「定稿后打开下一章」,第 3 章定稿后扣住第 4 章的读取,期间在设置页改出未保存的模型名;放行后弹「放弃未保存的修改?」,点「放弃修改」:第 4 章自动弹出的写作弹层还开着、焦点在弹层里,弹层打开后焦点没有落到弹层外。measured.log 是页面里按时间记下的弹层开合与焦点移动 |
写作弹层 | 是 |
rdx3-write-after-discard-sheet |
同上,但放弃确认弹出前点过运行侧页的「历史」页签:确认关掉后的还焦点不抢走写作弹层的焦点。两者先后不定,只断言「历史」若拿到焦点是在弹层打开之前 | 写作弹层 | 是 |
rdx3-prompt-over-exit |
设定里改出未保存的输入后只勾蓝图清除生成内容,主进程扣住 db:project-clear-generated-data(原处理在 after 里放回);期间从主进程关窗弹出退出确认,再放行一个失败:「清除失败」提示画在退出确认之上(isTopmost),退出确认露在提示外的上沿命中提示的遮罩、截图亮度比提示纸面暗至少 10(exposedEdge,无重影),「确定」点得到,确定后退出确认还在且在最上层 |
退出确认 | 否 |
rdx3-exit-over-prompt |
同上但反过来:先放行一个说明很长的失败,「清除失败」提示比退出确认高;提示开着时关窗,退出确认在最上层、焦点在它里面,提示露在外的上下沿命中退出确认的遮罩并被压暗;取消退出确认后提示在最上层、「确定」点得到 | 退出确认 | 否 |
rdx3-candidates-en |
夹具模型的角色提取只回一张卡;从「角色」粘贴一张角色卡,运行侧页出确认卡后在设置的外观页把界面语言切成英文,确认卡写「1 character candidate」(不是 candidates);after 切回中文,再等批次就绪、把守塔人按新建确认,走完这次待确认的运行,退出时不再弹「创作任务仍在运行」 |
运行侧页 | 是 |
rdx3-prose-keys |
打开第 4 章草稿(新外壳单章视图或旧外壳草稿编辑器,--shell 选),末尾输入「※※※」「——他说,钟声提前了。」「◇◆◇」三段:新外壳纸面上两行分节符不缩进、对白缩进 36px(旧外壳编辑器本来不缩进,不查);Tab 插两个 em 空格,Esc 后停 2.5 秒再按 Tab 焦点移出编辑区、不插空格,Esc 后按了方向键 Tab 又插空格。两种外壳各跑一次 |
焦点移出编辑区后 | 否 |
rdx3-hover-focus |
书房里鼠标停在「新建作品」卡上再按 Tab 聚焦它,box-shadow 是焦点环(悬停样式不盖掉它);打开作品后键盘打开作品菜单,首项、方向键下一项、End 末项的 box-shadow 都是菜单自己的 2px 内侧环,不是外壳的外圈;中途拍 -start、-menu-first、-menu-last |
菜单末项聚焦 | 否 |
切换默认外壳(RD-10)
场景在 scripts/redesign/rd10-scenarios.mjs,对应计划 RD-10 的实机 lane 与功能保全矩阵的验证截图。被测构建是 RD-10 之后的纸墨外壳,--app-root 指向最终安装包的构建树。
| 名称 | 检查 | 截图停在 | 夹具模型 | 对应计划 |
|---|---|---|---|---|
rd10-keyboard |
只用键盘:Ctrl K 去蓝图,Tab 到下一章的「写第 N 章」(样例里是第 3 章)回车开写,写完 Tab 进正文补一句、Ctrl S 保存,再按 Esc、Tab 离开编辑区。每一步记下焦点落点与焦点环(:focus-visible 且 box-shadow 或 outline 含强调色;正文编辑区以插入点为标记),measured.missingRing 为空 |
保存后离开编辑区 | 是 | lane 7 |
rd10-esc-after-typing |
第 4 章正文里分别用逐键按键、insertText、CDP 模拟的输入法组字(imeSetComposition 再 insertText)各打几个字,每次打完立刻按 Esc、Tab:焦点离开编辑区,正文里不多出全角空格(measured.results 三项都 left: true、emSpacesAdded: 0) |
最后一次 Tab 之后 | 否 | lane 7 |
rd10-en |
界面语言切成英文后走书房、四个阶段、角色名单、第 3 章与第 1 章、运行侧页、三个作品资料页、导出与清除对话框、设置各页;每页的可见文字与可访问名称去掉作品内容后不剩汉字,measured.untranslated 为空 |
设置的外观页 | 否 | lane 6 |
rd10-widths |
1280×900 与 1920×1080 下依次截第 3 章、角色名单、蓝图、书房(rd10-widths-<宽>-<页>),文档与外壳都没有横向溢出。浅色、深色各跑一次(--theme) |
1920 宽的书房 | 否 | lane 10 |
rd10-knowledge-narrow |
1280×900 下打开知识库再展开运行侧页(资料栏只剩约 200px),中文、英文各一次:资料栏里每个按钮留在所在的框里、文字不伸出按钮,分段两项不折行,资料栏没有横向溢出(measured.<语言>.problems 为空) |
英文界面的窄资料栏 | 否 | lane 10、F27 |
rd10-tab-menu |
打开设定与蓝图共三个标签,展开「标签操作」:已打开的页面与关闭当前、其他、右侧、全部四个动作 | 标签操作菜单 | 否 | F-183、F-184 |
rd10-tab-overflow |
1280×900 下开着运行侧页,打开作品资料各页与几章直到标签条横向滚动,最后打开的标签在最右端激活:「标签操作」按钮中心那一点上是按钮本身,在那里真实点一下打开菜单,标签一个不少 | 打开的标签菜单 | 否 | F-183、F-184 |
rd10-candidate-page |
运行侧页可恢复的正文候选「继续编辑」打开纸墨正文页,候选正文在纸面上 | 恢复候选正文页 | 否 | F-072 |
rd10-tour |
评审视频(配 --video,约 45 秒):书房概览、打开作品走四个阶段与角色名单、正文第 3 章,设置的外观只有浅色与深色两套(没有皮肤与界面布局),切到深色再切回,回书房 |
书房 | 否 | Review gate |
Version History
- bb4affb Current 2026-10-18 19:05


