Repository navigation
Releases: yimuhub/yimu-lit
Release list
一幕·YIMU 神笔 v4.26.1
以真人操作走完「新建作品→引导→选书名→总编辑接管→连续创作」全流程(《请一次假涨一甲子》
100 章 30 万字量级),实测揪出并修复 4 个问题:
- 分数停滞止损(token 失控):实测前 5 章烧 106 万 tokens(review 占 92%),低分章在
「管线验收重写+总编辑重写」叠加下每章 19-27 次调用,且第 3 章 4 轮重写 68→56 分反向。
修复:_auto_rewrite_chapter加两道止损——提分 <2 分视为模型能力到顶(分数在 ±5 内
随机震荡),接受当前版本直接前进;未提分回滚后同样不再继续抽卡。实测第 6 章起
每章调用 25+ → 13 次,token 减半。 - 开机孤儿扫描自指污染:新增 sweep_orphans(服务重启后总编辑自动接管中断的书),
首版用文件 mtime 判「最近活跃」——扫描自己写接手宣言刷新了 mtime,66 本旧书
(含十几本当天测试书)全部被误拉起写作。修为「最后一条非 supervisor 事件」时间 +
6h 窗口,实测 66 → 2 本(真在写的两本)。 - 有害的恢复冷却:30 分钟最小间隔本意防双开,实测把「重启后注册表为空」时必要的
恢复也拦住——书卡死到冷却过期。撤销(防双开已由 3 次/24h 预算 + 引擎真实状态判据覆盖)。 - 重启自愈盲区:看护线程随服务进程死亡,重启后 in_progress 的书无人接管。
sweep_orphans 挂到 app 启动(15 秒后),真机验证:重启→扫描→接手→自动断点恢复→
续写第 6 章,全程无人工介入。
E2E 其余环节实测通过:向导创建(都市/爽文/滚动规划/短篇30万字/批量全部)、
选书名闭环(采用→改名→确认回复→自动开写→总编辑接手宣言)、黄金三章质量(对外出口
无规划产物泄漏,正文有梗有节奏)、第 1 章守护(69.5→57 分自动回滚)。
完整对比:v4.26.0...v4.26.1
一幕·YIMU 神笔 v4.26.0
用户需求:一个总的、最后汇总的 Agent,开写起自始至终统领书稿创作,对整体性负责,
自动发现并自动修复问题,不等人工审核——创作者只管给想法,对话里看全程。
新增 bot/supervisor.py(总编辑看护线程,每本书一个)
- 看(确定性体检,0 token):停滞/孤儿线程、每章评分与字数、空章、超期坑、大纲耗尽;
- 判(规则写死):停滞→断点恢复;未评分→派评分;低分→派 3 岗位定向重写(沿用
「改写分不升自动回滚」守护);空章/字数<70%→打回重写(以实际正文为准,不信任
可能脱节的 wordCount 字段);超期坑→派巡检;大纲写尽→重规划提案; - 派(全部复用既有机制):tasks/引擎 resume、run_parallel_rewrite、score_chapter、
audit——总编辑是指挥不是新引擎; - 报:以「总编辑」岗位在对话活动流全程汇报每个决定;
- 断路器:停滞自动恢复 24h≤3 次 + 两次间隔≥30 分钟(防双开);单章重写每周期 1 轮;
用户暂停绝不自动恢复(实测:暂停后明确「待命」);极速模式只管不停不派改写; - 自动化程度(设置→总编辑自动化程度):guarded(默认,结构级重规划出提案等确认)/
auto(低风险重规划自动应用);接入点 writer.mark_pipeline 收口(0→1 上车、→0 延迟
判定),小说主链路本次补齐 mark_pipeline(此前缺失——这正是总编辑首检暴露的盲区,
停滞判据改为 注册表∪活动流新鲜度 双通道防误判)。
修复「选完书名就停」(用户报告的严重流程断裂)
右栏「采用」走的是改名接口(/api/title/set→_apply_title),只改目录名不启动创作;
真正开写的 /api/pick-title 前端该链路从不调用。现在 _apply_title 检测到
awaiting_title 书:清标记→启动创作→对话流写入「已收到,将以《书名》进行创作,
现在马上安排创作」确认回复,总编辑随即接手汇报分工。
真机验证(都市异能爽文):继续→总编辑接手宣言→第58章评 78.2 分(<80)→
总编辑自动派 3 岗位定向重写→去味师跟进;点暂停→总编辑明确待命不越权。
新增 9 项回归测试(test_v4260_supervisor.py);全量 pytest 通过。
完整对比:v4.25.0...v4.26.0
一幕·YIMU 神笔 v4.25.0
用户提供《商业化网络小说创作 Skill》全套方法论(选题评估→平台适配→故事策划→章节
生成→三轮编辑→连载质控),与现有技能库/引擎深度融合。目标:正文产出即为可直接
投稿连载的生产级质量,而非「能读的草稿」。
技能库新增 4 件(自动进注入链)
- 「故事引擎与承诺契约」(P0):一句话故事引擎公式+五查、故事承诺契约五问、
主角五要素(外在目标/内在需求/缺陷/能力代价/边界)、对手压力系统六要素、
冲突升级必须换维度。 - 「因果链与爽点纪律」(P2):因果链唯一合法推动方式+六条低质量推动禁止、
爽点五条件+九类轮换、情绪节奏、单章任务底线七选一。 - 「平台适配与作品包装」(P0):付费长篇/免费推荐流/女性向/短中篇四类平台节奏校准,
书名-简介-标签-开篇一致性验收。 - 「三轮编辑与章节五项快评」(P3-P5):结构→商业阅读→语言三轮顺序、交付前硬检查、
章节五项 0-2 分快评。
现有技能增补
- 「卷弧结构与滚动规划」+分卷设计九项(开卷前逐项过)+中期防疲劳七问;
- 「反AI腔总纲」+机械句式红线十条(同一主语连排/空洞反应词/三重复/机械转场口头禅…)。
引擎接线(提示词级,不改评分 schema)
- 人物规划:主角档案强制五要素+反派六要素,注入故事引擎方法论;
- 大纲规划:强制输出「## 故事承诺」章节,注入故事引擎+平台适配要点;
- 逐章写作系统提示:新增【因果与爽点纪律】固定切片(与章纲规范/钩子/反AI腔并列);
- 五角色审校评分 rubric:追加章节五项快评(任务/事件变化/主动行动/回报/引出下一步,
各 0-2 分),<7 分必须在 weak+evidence 里给原文证据——六维评分口径不变。
验证:技能库 92 文件 validate_all 零错误;P0/P2 注入块实测含新纪律;
新增 8 项回归测试(test_v4250_commercial_skill.py);全量 pytest 通过。
完整对比:v4.24.16...v4.25.0
一幕·YIMU 神笔 v4.24.16
按用户要求以代码审查员身份逐行重读全仓(后端核心 / 九体引擎 / 前端+测试三路并行审查 +
主线程 AST 不可达检测、pyflakes、ESLint bug 规则组、静默 except 清点),53 条发现逐条
人工复核,42 条确认为真问题并全部修复,其余为误报或有意设计。按危害分级:
内容丢失 / 数据损坏(P0-P1)
- api.js 26 处「三参 timeout」被 JS 静默丢弃——重写场次(600s)/多方案规划(600s)/蒸馏/技能
评测等分钟级任务全按 45s 超时,用户重试→后端重复执行;统一改{...jsonBody, timeout}。 - 新闻稿引擎:字数守护续写的内容永不落盘(先写 F_FINAL 再拼接内存变量),文件与字数
统计永久分叉;对照 copy 引擎的正确顺序修正。 - 论文引擎:
_gen超时/异常静默返回空串,空章照样写盘并标 completed——resume 永不重试,
T5 定稿把空章拼进正式论文;现在空稿标 failed,继续时自动重写。 - 剧本引擎并行分场失败路径:保存 LLM 调用前的过期计划快照,把其他岗位刚写完的
completed 状态整体回滚;改锁内重读。 - 「其他创作」引擎整体脱管:极速模式跳阶段判据被无视、全流程无暂停检查点、O3 打磨
每次恢复都重跑全文改写——三连修。 - 会话菜单死分支(v4.22.0 同族缩进事故):回复「2」(快车道)被外层准入元组挡住,
永远得到「请回复 1/2/3/4」。
竞态 / 并发(P1)
- /api/continue 非小说分支无防重入,双击起两条恢复流水线;/api/parallel-write、
/api/one-shot、_start_rewrite 的检查-置位 TOCTOU 补注册表互斥;并行写作纳入
_acq_book 同书串行(此前只串行重写/门禁)。 - book-agents / book-skills / assist 字数同步的读-改-写全部纳入按书锁;
计划文件读取失败时拒绝整文件覆盖写(防一次瞬时读错误清空整本计划)。 - longform 摘要/章卡 jsonl 并行写加锁;skillkit「强制注入」技能豁免预算裁剪。
- run_parallel_rewrite 线程池补 llm.book 线程标记 + 整体 try/finally(进度标志不再卡死)。
功能静默失效(P1-P2)
- 阶段式引擎(儿童/新闻/文案/其他)有阶段失败仍谎报「已完成」——改置 paused 给出
真实重试路径;进度口径 5/0、5/3 错位修正(children 按篇计、单文档引擎按阶段计)。 - 按分数阈值改写按文本顺序取数:「改到95分,低于85分的重写」会得出 95/110 颠倒阈值、
「100」被切成「10」;改语义绑定提取。 - longform 题材化卷/弧名模板用英文 key 匹配中文题材,特性静默失效;经 _genre_key 归一。
- medium.wizard_payload 写死 basic[0] 注入 agents 词表(basic[0] 早已是笔名)。
- 改名不写 rename_map,重启后旧 key 全部 404;一键完稿/继续对运行中任务的重复执行
检查;彻底删除后 PROJECT_INDEX/活动流/运行标志不清(已删的书会被写路径「复活」);
/api/consistency-audit/run 实为同步分钟级阻塞改后台线程;GET /api/feedback 被
app.py 的 stats 版遮蔽(v2api 列表版永不可达);/api/branch 允许复制创作中的书。
前端(P1-P2)
- 候选技能「驳回」按钮 on 传裸函数——dom.js 只认 {click: fn},按钮完全无效。
- 切书竞态三处:guardedRefresh 五件套(旧书数据画进新书 + inflight 挡住新书刷新,
改 name+key 维度去重 + currentKey 复核)、loadChatHistory、参考检索。 - chat 订阅签名漏 approval.done 与 rating:审批卡不刷新可重复提交、点赞无反馈;
思维链增量游标 stream_think_offset 后端早就支持但 HTTP 层从未接(每 1.5s 全量重发);
深链冷启动 + library 失败永久「正在加载作品…」;工作台弹窗不响应 Esc(叠层时关错);
协作浮窗 document 级拖拽监听泄漏;并行改写/评分轮询无退出条件;mediumbench 三个
工作台重复 final 页签(同时高亮、点击无响应);流式失败回退后「正文全文」卡与实际
章文不一致(final_text 以返回值为准);hydrate 重复灌入;去重水位跨重启碰撞。
测试基建:conftest 新增全局状态统一清理 autouse;三个 v1 文件的 _mock_llm
同名遮蔽改名(本仓库 3 次烧真网事故的病灶模式)。
全量 pytest 通过;ESLint bug 规则组与样式/接线体检全绿;IAB 实测(书页启动、岗位徽章、
Esc 关弹窗、剧本工作台)正常。审查方法与「9 引擎 × 5 机制」检查清单已沉淀进 功能表.md。
完整对比:v4.24.15...v4.24.16
一幕·YIMU 神笔 v4.24.15
用户接着问:「那我如果想要继续使用极速模式呢?开关点不开了。不能让它成为动态的
吗——随时可以启用,也随时可以关闭。」
能。v4.24.13 的「运行中一律拒绝」是过度防守,代价是用户想换速度就必须先停下整条
流水线,而长篇一写就是几小时。
一、后端:小说运行中允许切档
POST /api/express-toggle 对小说不再检查 running,直接在 proj.lock 里
读改写落盘,返回体带 running,提示语说明「当前这一章写完即生效」。
非小说仍然拒绝——那 7 个引擎在启动时把要跑的阶段算定了,中途改只会标签变了、
阶段没变,说清楚比假装生效好。
二、写作循环:速度不是启动快照
_write_loop 原先把 _expr 存下来用到底:启动时是标准,写到一半开极速,
这一批仍然按 batch_size 停、收尾仍跑规划师校准。现在新增 _live_express(),
每章重新读 config.express:
- 批次上限检查读实时值(中途开极速 → 不再按批停);
- 完结前的规划师校准读实时值;
- 逐章的去味/评分/字数线本来就在
_write_chapter里按章读,天然跟随。
粒度是「章」:一章写到一半不换档,否则同一章的字数线与评分逻辑会被撕成两半。
三、前端:开关不再因「正在写」而禁用
createExpressSwitch 去掉 disabled: running,运行中提示改为
「当前这一章写完即生效」。createExpressButton(极速续写)仍在运行中隐藏——
它的语义是「改速度 并 开写」,不能起第二条线程。
回归用例:test_toggle_works_while_running_novel、
test_express_ignores_batch_size_in_write_loop(改为断言 _live_express())、
test_frontend_express_switch_stays_clickable_while_running,
jsdom 用例 planbar_express_test.mjs 同步改成「运行中仍可点、提示写完即生效」。
完整对比:v4.24.11...v4.24.15
一幕·YIMU 神笔 v4.24.11
用户反馈:在开书引导里按提示绑定了几个 Agent,但找不到任何地方能看到这些绑定。
排查结论:向导 → payload → 计划文件的存储链路本身是通的(浏览器拦截请求体 + mock
端到端验证),真正的问题是 ①唯一的展示藏在右栏「协作」页签深处,不显眼;
②/api/book-agents 只认小说的 02-写作计划.json,剧本/诗词等文体的协作页签
「本书创作岗位」永远为空。
- 作品面板徽章行:右栏「作品」页签(小说 + 非小说两个 pane)头部新增
「创作岗位」徽章行——开书引导绑定的岗位以标签呈现(如 规划师/作家/审稿人/去味师),
未绑定不占位;点任意徽章直接跳「协作」页签,那里可增删岗位、绑技能、改模型。 - book-agents 全文体:按 key 前缀读写各自文体的计划文件(剧本计划.json、
诗词计划.json、散文计划.json…),GET/POST 都支持;修复旧逻辑对非小说会误建
02-写作计划.json 的隐患。 - IAB 实测:小说书(4 岗位)与非小说书(剧本 编剧/审剧人)徽章行渲染、点击跳转、
协作页签增删全部正常;全量 pytest 通过。
完整对比:v4.24.10...v4.24.11
一幕·YIMU 神笔 v4.24.10
用户反馈:诗词/剧本/散文等非小说文体的创作过程在对话框里一个都没有显示。本轮四引擎全面接线 + 顺手揪出并修掉两个更深的问题:
- 四引擎流式接线(script/poetry/prose/thesis):
_gen全部改走llm.chat_stream,
正文+思考双流经 emit_delta 实时进对话框活动流(失败自动回退 chat);剧本每场开写
埋「写第 N 场…」步骤事件(chapter=场号);散文/诗词/论文补线程书标记(llm.book),
token 归账不漏。 - 修复测试烧真网:test_v1_poetry/prose/script 三文件自定义
_mock_llmfixture
遮蔽 conftest 同名 autouse fixture,v4.24.10 起 _gen 走 chat_stream 后这些模块
拦不住直连真 LLM(全量测试从 19 秒挂到 5 分钟+)。三个模块 fixture 补 chat_stream
stub(委托各自 chat mock,绝不连网),另修 prose_writer 一处 NameError。 - 修复规划器分发失效(v4.22.0 遗留):app.py 补丁叠加导致规划器分发块(63 行)
被误缩进进_run函数体、三个意图分支(补评分/批量写/继续创作,79 行)又被误缩进
进 consistency_audit 分支——attached 会话下所有自然语言指令全部漏到「并入创作要求」
兜底,规划器形同虚设(test_v230_chat_bound 7 个用例红)。两层反缩进归位后,
「继续」「进度」「第12章重写」在 LLM 不可用时也能正确回退到传统意图理解并执行。 - 全量 pytest 通过(exit=0,0 FAILED)。
完整对比:v4.24.0...v4.24.10
一幕·YIMU 神笔 v4.24.0
新功能。给全部 9 个文体加一个「只求写完、不求写好」的执行规格:跳过评分、
去味、重写、润色、多版本这类不产出新内容的环节,把一本书从开书到成书的时间
压到最短。产出是初稿——这一点在界面上明确标出,不做暗示。
一、先修掉一个前提问题:创作模式 三张卡片一直是假选项
bot/medium.py 早就定义了 rolling / outline / one_shot,向导会提交它,
longform.py 会把它存进 plan.mode——但全仓库没有任何一处读它来决定走哪条
流程。用户选「一次成稿」和选「滚动规划」,执行的代码完全一样。
所以极速模式没有新建一条流程,而是把这个从未生效的字段变成第一个真正驱动
流程的开关。好处是不必再抄一遍那 9 套 create_project,坏处是它同时暴露了
上述事实——三个老选项至今仍只是标签,这一版没有精力一并修好,先如实记在这里。
二、bot/express.py:全仓库唯一的判定解释器
质量环节散落在 9 个引擎里,且大多读全局 config.json。极速模式必须是每本书
的开关——开一本极速书不该把整台机器都变快。更重要的是「跳哪些环节」得有唯一
口径,否则以后新增一个质量环节就得在 9 处各补一次判断,漏一处就变成「极速模式
里偷偷还在评分」。
约定:所有 writer 只问 express.on() / express.skip_stage(),不自己拼
cfg.get(...) 条件。
保留原则(这是本模块最要紧的边界):跳过的只有评估/修订/打磨/去味/
多版本;章卡规划、章节摘要、连续性索引、格律校验、时代校验、场次结构一律
保留——它们产出的是一致性与结构,砍掉就不是快,而是写出一本前后矛盾的书。
| 文体 | 跳过 | 保留(都是确定性检查或结构产出) |
|---|---|---|
| novel | 去味、逐章评分、撞车重写、失败章重写、五角色审校、放行门禁、标题回流、文风校准 | 章卡、章摘要、连续性索引、规划校准 |
| script | —(一张评审阶段都不跳) | 时代校验、场次结构 |
| poetry | R 评改、审美评分 | K 格律校验(纯 CPU,跳了就是废品) |
| prose | A 去味与反 AI 腔 | P 定稿拼接 |
| thesis | T4 降 AIGC 润色 | 引用核查、字数统计 |
| news | N3 事实核查、N4 多版本 | 正文撰写 |
| other | O3 润色 | 创作与交付 |
| children / copy | —(全部是创作内容) | 全部 |
字数规则(用户定稿):目标字数照给,但验收线从 90% 降到 60%,不足时只补写
一次。不给目标会让章卡的目标/冲突/转折/兑现装不下、连续性从第 3 章就崩;
按字面「无最低字数」则与「保持一致性」自相矛盾。其余的束缚全部解除:不重写、
不评分、不按批停(batch_size 被忽略,一口气到底)。
三、两条界面入口,一个归一化出口
小说的「创作模式」新增第四张卡片 express;其余 8 个文体新增「创作节奏」
两选一(标准 / 极速)。两者提交的字段不同(mode=express vs express=express),
app._express_into 统一折成 cfg.express。只在为真时写键——老项目里没有
这个字段,写 false 只会让用户可见的 02-写作计划.json 变脏。
四、短表单:极速模式下向导自动收成 5 项
前端 isVisible 原先只支持正向条件 when.in。加了反向 when.not_in,
schema 就能声明「极速模式下不显示」。小说极速下只剩:
题材 · 创作模式 · 一句话简介 · 规模(章数)· 每章字数
发布平台 / 基调 / 叙事视角 / 核心卖点 / 书名 / 专属 Agent 全部收起;其余文体
的风格页(全是打磨与排版设置)整页收起。
有一处刻意不收:批量写作 是必填项,而「必填项不被隐藏」是短表单的硬规则。
改为保留在表单上、由 express 效果自动选中「全部写完」——把「一口气写完」
亮出来反而更自解释。(写测试时它先被抓成矛盾:必填却被隐藏。)
五、诚实标识:产出是初稿,界面上必须看得出来
/api/plan 的两种视图(_plan_view / _medium_plan_view)都显式输出
express: bool。判据取 plan.config 而不是 plan.mode——后者存的是原始
token(rolling),且非小说走 _medium_plan_view 时已被换成文体标签,拿来
判断会漏。规划条与右栏的模式徽章在极速下显示「⚡ 极速模式 · 初稿」(强调色),
而不是混在普通模式文案里。
六、测试
新增 tests/test_v424_express.py(17 例)分四层:判定口径(含「未知文体一律
不跳」的保守默认)、入口归一(含「不写 False 污染计划」)、短表单(含「必填项
不隐藏」与「格律开关不被覆盖」)、接口标识。
完整对比:v4.23.2...v4.24.0
一幕·YIMU 神笔 v4.23.2
这一版没有新功能。它处理的是 v4.23.1 交付后遗留的四类欠账:lint 告警、
没人调的接口、红了很久的测试、没有样式的类名。原则是——能改代码的不加
noqa,能补数据的不编数据,能写理由的不含糊留着。
一、ruff 44 条 → 0,其中 3 条是真 bug 不是风格问题
自动修 19 条(import 排序、dict() 字面量、f-string 无占位符等),
剩下 25 条逐条按语义判断,挑出来的真问题:
script_writer.write_scenes白读三份大文件。 它把「读配置→读圣经/人物/
结构→算时代」整套做了一遍,8 个变量一个都没用——真正实现在_write_scenes_inner
里又原样做了一遍。每次开写都多读三份大文件。改为只做前置校验 + 状态标志。copy_writer._stage_titles拿空输入让模型编标题。 它_read了正文却
没拼进 prompt,模型看不到文案,「为以下文案出标题」实际是对着空气出的。
news_writer._stage_check同款:事实核查对着空文本做,结论必然全 ✓。
两处都补上正文,并在正文为空时直接跳过(不产出假报告)。v2api._bg_score把全书一致性扫描跑了两遍、扔一遍。 单独调
continuity.run_project的返回值从未使用,紧接着validate_project内部
会以同样参数再跑一次。删掉前一次,进度文案保留。
其余按语义归类:raise ... from None(B904)、zip(..., strict=False)(B905)、
open() 去掉冗余 "r"(UP015)、asyncio.TimeoutError 并入内置 TimeoutError
(UP041,本仓库下限 py3.13)、children_writer._stage_final 用落盘命名规则
直接拼路径,不再内层遍历 1..N 猜序号。pyproject.toml 删掉已从 ruff 移除的
UP038 ignore(它让每次运行都报一条 warning)。
二、8 个红测试全部转绿,根因各不相同
| 用例 | 真因 |
|---|---|
test_agent_registry_sync / test_skill_evo(poetry、novel/P2) |
技能文档从未写出来:novel-volume-arc-planning、novel-multithread-pov 在 git 全历史里都搜不到,而 DEFAULT_AGENT_SKILLS 已按这两个名字绑定 |
test_v1_poetry ×4 |
skillkit/poetry/data/pingshui.json 不存在,_rhyme_index() 返回 0 条 |
test_v1_script::test_script_create_api |
断言假定同步创建,实际是后台线程规划——只有线程恰好先跑完才过 |
test_v230_chat_bound |
writer._RUNNING_BOOKS 是模块级 set(按 basename),前一个用例的 running 串到后一个 |
test_v310_fixes |
沙箱里 Path.mkdir(exist_ok=True) 的 EEXIST 会被直抛,绕过 exist_ok 语义 |
补齐方式:两份技能文档按既有规格(frontmatter 8 字段、stages、weight)新写;
平水韵表不自己编,从两个 MIT 许可公开数据源合并——charlesix59/chinese_word_rhyme
的 Pingshui_Rhyme.json(105 韵,缺上声三讲)+ pypi pingshui_rhyme 的
organized_ping_ze_rhyme_dict.json(补三讲),交叉核对后 106 韵齐、8240 字,
抽查「东→上平一东」「楼→下平十一尤」「雪/一→仄」。
CI 第一次真正跑起来,就抓到 2 个「本地全绿、CI 必红」的假绿:
test_quality_shape / test_book_live_shape 直接 assert key, "无书可测",
而 projects/ 是 .gitignore 里的运行态目录,干净检出必然为空——它们只在
「本机恰好有作品」时通过。改为统一的 _require_book():无书时显式
pytest.skip(报告里看得见原因),不再静默 return;同文件里原本静默 return 的
test_skeleton_route_and_shape 一并对齐。这类用例以前一直被前序失败挡住,
从没真正执行到。
三、接线体检:从「一堆警告」变成三态结论
v4.23.1 建的 tools/audit_wiring.py 当时报「75 个接口前端零引用」。逐个核实
发现其中大半是扫描器自己的误报:
PATH_RE字符类缺(),/api/library/${enc(key)}/trash在(处截断,
25 个真在用的 REST 路由被判死;- 只扫
static/v2/js,漏了仍挂在/classic的static/index.html; - 前端拼接写法
"/api/live/"+key抓到的是/api/live/,归一后对不上
/api/live/{key}——补**跨段通配; - 有些模块不直接写
api.xxx(),而是走collabCall('agentsSet', …)/
callApi('bookSkills', …)这类薄包装,内部api[name]动态取用。
本轮一度把这 10 个在用方法报成「定义了没人调」,已加动态派发识别
(含api['xxx']字面量下标),并且动态派发出的名字同样核对存在性——
名字打错一样是运行时才炸。
收敛后:前端 158 个 /api 路径全部有路由;后端剩余 27 个接口属「能力有、
界面有意不接」,逐条写进 API_ONLY 并注明理由(不写成纯白名单,带「过期告警」;
某个接口后来被 UI 接上时会提示收缩)。134 个客户端方法全部有真实调用,0 处悬空。
四、新增 tools/audit_css.py:类名有没有样式,现在可守门
v2 前端不写 class="...",而是 h('div', { class: 'x' }),按 HTML 字符串扫描
一个都抓不到,于是「类名没样式」长期没人核对。本轮核实出 21 个,结论是只有 3 个
是真缺口:
.rp-section .section-head(右栏小节标题裸 div)、.set-group-subhead
(设置页小标题)、.wiz-ai-inline(向导 AI 按钮)——补纯排版语义。
其余 18 个要么是 JS 查询钩子,要么布局/间距已由父级或兄弟规则提供。后者尤其
不能乱补:.rp-section 本身是 flex column + gap:8px,再加 margin 会把 8px
变成 18px;.set-row + .set-row 靠 0.5px 分隔线成列,加 gap 会顶开分隔线;
.mb-prev 的父级 .modal-body 已有 padding 与滚动,再补 padding 就是二次内缩。
这些全部写进 shell.css 末尾的清单与 NO_STYLE 白名单,逐条带判定依据。
白名单同样有「过期告警」:某个类后来真的被删了会提示清理。
五、门禁与 CI
- CI 恢复
push/pull_request触发(此前只留workflow_dispatch)。
当时不挂 push 的理由是「ruff 一挂就 skip 测试,20 秒一个红叉」——现在 lint
归零、测试全绿,红叉重新代表真回归。公开仓库标准 runner 分钟数免费不限量;
另加concurrency取消同分支的排队运行。 - 新增
tools/test.sh:统一 pytest 入口。沙箱环境里 teardown 一次删 >50 个路径
会触发删除守卫直接SystemExit(1),表现为 fixture setup 阶段几十个 ERROR;
脚本里摘掉这两个环境变量后归零。 tools/commit.sh增加样式体检步骤(原先只有接线体检)。app._spawn_project在当前线程预建项目目录:原先目录要等后台线程真正开始
跑才创建,而各引擎get_project都是「目录不存在 → None」,前端拿到 key 立刻
轮询 status 会吃 404(提示「项目不存在或未加载,请刷新作品库」),网速快就必现。- 后台线程异常改为打印完整堆栈(原先只有
str(e),排查不到落点)。 bot/safeio.py加_ensure_dir:某些环境os.makedirs返回时目录尚未落盘,
紧接mkstemp会 ENOENT,报「No such file or directory: .tmp-xxx.part」,
从堆栈完全看不出是目录问题。writer.run_guided_rewrite在缺少写作计划时给出可读失败原因(原先plan为
None时.get抛AttributeError落在后台线程,用户只看到「没反应」)。app._script_scenes_or_reparse的except Exception: pass改为打印失败原因。
原先这里有两个问题:写盘失败完全无声(用户下次打开又要重解析一遍,日志里却
什么都没留);而且proj.log写在同一个try里——磁盘没写成也会记一条
「已回填」,日志说做了、磁盘上没做。CI 在 3.14 上让
test_script_scenes_reparse_fallback偶发红过一次(接口返回了场次、计划文件里
没有 scenes),本地连续 60 次未复现;现在至少这类失败会带异常类型打到 stderr,
测试断言也会列出 plan 的键,下次一眼能定位。
六、.gitignore 的一处静默陷阱
data/、references/、skills/、styles/、projects/ 原本没锚定根目录,
会匹配任意层级的同名目录——skillkit/novel/references/ 与
skillkit/poetry/data/ 全被吞掉。本轮新写的 3 个技能文件差点因此不入库,
CI 上必然红(本地因为文件在磁盘上而全绿)。已改为 /data/、/references/ 等
根锚定写法,并把 .pytest-tmp*/ 一并纳入忽略。
七、验证
ruff check → All checks passed;bash tools/test.sh → 622 passed;
audit_wiring.py --strict / audit_css.py --strict → 退出码 0;
v2 首页与设置页在 1440×1000 下实机截图核对,无错位/裁切/重叠。
完整对比:v4.23.1...v4.23.2
一幕·YIMU 神笔 v4.23.1
一、现象
点「新建作品」,弹窗只剩标题和副标题,正文与按钮全空。向导代码本身
自 v4.15.6 起一行没动——坏它的是 v4.21.1 那次「深度体检」。
二、根因(两处,同一次提交埋下)
v4.21.1(213c9e4,59 文件 / −1532 行)做了两件事,各自都合理,合起来致命:
- 清「死 API」时删掉了
api.onboarding。 唯一调用方views/wizard.js
是await import()懒加载的,扫描只覆盖首屏闭包 → 判成死代码。
于是openWizard建完弹窗、还没走到render()就抛
TypeError: api.onboarding is not a function,弹窗定格成空壳。
后端/api/onboarding一直好着。 settings.css从「常驻」改成「进设置页才加载」。 向导样式
(.wiz-*/.genre-card/.wizard .modal-header)全在这个文件里,
而向导可以从首页、作品库随时打开——样式根本不在场。
三、同类第二处:剧本「整本预览」
mediumbench.js 一直调 api.scriptPreview(key),但 api.js 里从来没有这个方法。
点「预览剧本」必炸。后端 GET /api/script/preview 一直是好的,补上客户端方法即可。
两个 bug 存活多个版本而无人发现,原因是检查全都不看这一层:
eslint no-undef 认为 api.onboarding 是合法属性访问;pytest 只测后端;
手工点不全 9 种文体的每个按钮。
四、修法
api.js补回onboarding/scriptPreview,并注明「懒加载模块里的调用
不能只靠首屏闭包判死」。app.openWizard()打开前loadCss(settings.css)(loadCss本身幂等)。- 新增
tools/audit_wiring.py:用 node 直接读出 api 对象真实方法表,
整文件扫描api.xxx(能识别api\n .onboarding()这种换行写法),
再与app.py真实路由双向比对。--strict有悬空即退出码 1。 - 新增
tests/test_v4231_wiring.py(5 例):悬空调用、404 路径、
向导样式在位、openWizard先加载 CSS、onboarding专项。
已做反向验证:把onboarding:改名,两条测试立刻变红。 commit.sh提交前跑接线体检,不通过直接中止。
五、顺带修掉的假绿
tools/static_check.sh 的 Python 门禁一直空转:本工作树没有 .venv、
主工作树的 .venv 里也没装 pyflakes,命令直接失败、grep 抓不到东西,
却照样打印「✅ undefined name: 0」。现在工具缺失即失败,并回显所用解释器;
requirements-dev.txt 补上一直没声明的 pyflakes。
完整对比:v4.23.0...v4.23.1