Skip to content

Releases: yimuhub/yimu-lit

一幕·YIMU 神笔 v4.26.1

Choose a tag to compare

@yimuhub yimuhub released this 03 Nov 18:24

以真人操作走完「新建作品→引导→选书名→总编辑接管→连续创作」全流程(《请一次假涨一甲子》
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

Choose a tag to compare

@yimuhub yimuhub released this 03 Nov 17:23

用户需求:一个总的、最后汇总的 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

Choose a tag to compare

@yimuhub yimuhub released this 03 Nov 16:31

用户提供《商业化网络小说创作 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

Choose a tag to compare

@yimuhub yimuhub released this 03 Nov 16:15

按用户要求以代码审查员身份逐行重读全仓(后端核心 / 九体引擎 / 前端+测试三路并行审查 +
主线程 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

Choose a tag to compare

@yimuhub yimuhub released this 03 Nov 07:06

用户接着问:「那我如果想要继续使用极速模式呢?开关点不开了。不能让它成为动态的
吗——随时可以启用,也随时可以关闭。」

能。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

Choose a tag to compare

@yimuhub yimuhub released this 02 Nov 19:10

用户反馈:在开书引导里按提示绑定了几个 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

Choose a tag to compare

@yimuhub yimuhub released this 02 Nov 18:50

用户反馈:诗词/剧本/散文等非小说文体的创作过程在对话框里一个都没有显示。本轮四引擎全面接线 + 顺手揪出并修掉两个更深的问题:

  • 四引擎流式接线(script/poetry/prose/thesis):_gen 全部改走 llm.chat_stream,
    正文+思考双流经 emit_delta 实时进对话框活动流(失败自动回退 chat);剧本每场开写
    埋「写第 N 场…」步骤事件(chapter=场号);散文/诗词/论文补线程书标记(llm.book),
    token 归账不漏。
  • 修复测试烧真网:test_v1_poetry/prose/script 三文件自定义 _mock_llm fixture
    遮蔽 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

Choose a tag to compare

@yimuhub yimuhub released this 02 Nov 14:08

新功能。给全部 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

Choose a tag to compare

@yimuhub yimuhub released this 02 Nov 05:23

这一版没有新功能。它处理的是 v4.23.1 交付后遗留的四类欠账:lint 告警、
没人调的接口、红了很久的测试、没有样式的类名。原则是——能改代码的不加
noqa,能补数据的不编数据,能写理由的不含糊留着。

一、ruff 44 条 → 0,其中 3 条是真 bug 不是风格问题

自动修 19 条(import 排序、dict() 字面量、f-string 无占位符等),
剩下 25 条逐条按语义判断,挑出来的真问题:

  1. script_writer.write_scenes 白读三份大文件。 它把「读配置→读圣经/人物/
    结构→算时代」整套做了一遍,8 个变量一个都没用——真正实现在 _write_scenes_inner
    里又原样做了一遍。每次开写都多读三份大文件。改为只做前置校验 + 状态标志。
  2. copy_writer._stage_titles 拿空输入让模型编标题。 它 _read 了正文却
    没拼进 prompt,模型看不到文案,「为以下文案出标题」实际是对着空气出的。
    news_writer._stage_check 同款:事实核查对着空文本做,结论必然全 ✓。
    两处都补上正文,并在正文为空时直接跳过(不产出假报告)。
  3. 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

Choose a tag to compare

@yimuhub yimuhub released this 02 Nov 04:26

一、现象

点「新建作品」,弹窗只剩标题和副标题,正文与按钮全空。向导代码本身
自 v4.15.6 起一行没动——坏它的是 v4.21.1 那次「深度体检」。

二、根因(两处,同一次提交埋下)

v4.21.1(213c9e4,59 文件 / −1532 行)做了两件事,各自都合理,合起来致命:

  1. 清「死 API」时删掉了 api.onboarding。 唯一调用方 views/wizard.js
    是 await import() 懒加载的,扫描只覆盖首屏闭包 → 判成死代码。
    于是 openWizard 建完弹窗、还没走到 render() 就抛
    TypeError: api.onboarding is not a function,弹窗定格成空壳。
    后端 /api/onboarding 一直好着。
  2. 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