|
|
@@ -0,0 +1,110 @@
|
|
|
+# 批次 2:全链行为审计报告
|
|
|
+
|
|
|
+> 任务:07-10-knowledge-integration-audit
|
|
|
+> 审计范围:knowledge-runtime.md 契约与错误矩阵、调用者与字段矩阵.md 第 2 节调用链的真实测试/代码证据。
|
|
|
+> 最终结论(2026-07-22 校正):初轮按既有测试名盘点时误判为“0 缺口”;随后逐条对父 A1–A32 做生产数据流与对抗审计,共发现 13 个绿灯未覆盖的契约缺口并完成修复。最终错误矩阵扩为 22 行,负向断言仍成立;下表取代初轮“无需补测”的结论。
|
|
|
+
|
|
|
+## 最终校正:既有绿灯未覆盖的缺口
|
|
|
+
|
|
|
+| 缺口 | 为什么初轮漏掉 | 最终修复与证据 |
|
|
|
+|---|---|---|
|
|
|
+| 序 1 未声明明确/模糊/空白作者分流 | 只测菜单与命令存在 | DTO + 技能增加三态契约;pipeline 回归;`反同质化实测.md` 人工语义轨迹 |
|
|
|
+| 差异化点未进入写作/审稿切片 | 校验器只证明有三条,不证明下游消费 | 纳入 writing/review sections,编辑审增加大纲/人物/设定连接核对,pipeline 回归 + `语义审查样例.md` |
|
|
|
+| 序 6 规划未读取作品契约 | prep/review 同源绿灯掩盖规划断链 | 序 6 经同一 `ContractReader` 读取,缺失/损坏阻断;pipeline 回归 |
|
|
|
+| 契约修订不强制证据与影响范围 | 旧测试只测版本与生效章 | 更新 payload 必填并写入选择记录;contract/persist-contract 回归 |
|
|
|
+| 故事对象知识依据可省略或含糊 | 样例主动填写,但校验器没要求 | `知识依据` 改必需;每个来源必须是同维或命名维的安全 canonical `维度/文件.md@sha256:<64 位小写十六进制>` 或精确自定义/共创,并有唯一非空 `本书适配`;design 回归 |
|
|
|
+| 近期历史只支持同名机械降权 | 候选测试只测合法复用不被删除 | 序 6 携带完整近期选择语义和比较要求,覆盖同名递进/异名同质;pipeline 回归 + 人工语义样例 |
|
|
|
+| 事实冲突只说“须裁决” | 原子零写入测试未检查作者看见什么 | 冲突/歧义强制差异、影响、处理选项;阶段返回可见且裁决后才写;fact-changes/finalize 回归 |
|
|
|
+| sample-book 仍有题材默认关系结算 | 正式 references 格式测试不扫描文风夹具 | 删除“反和解/圣母”旧段,新增 fixture 防回流测试与四案语义审查 |
|
|
|
+| 卷复盘持久化边界未重验作品契约 | 状态机入口绿灯不能证明写盘服务独立安全 | `persistVolumeReview` 写前通过同一 `ContractReader`;缺失/损坏时零文件、零 commit;persist/router 回归 |
|
|
|
+| 章级来源在定稿时才读取当前通用条目 | H1 只测“能归档”,未测确认后来源漂移 | 确认细纲时原子写 `细纲.md` + schema 1 快照并绑定原文 hash;引用变更/删除不改来源,缺/旧/不匹配 fail closed;chapter/staging 回归 |
|
|
|
+| 事实选项没有可执行语义 | 原测试只区分 decision 标签,没有证明“不改事实”真无副作用 | 每项强制 `applyChange:boolean`;作者裁决保留 options 并从 `optionId` 派生,false 不写事实、不删计划、不碰撞、不暂存/叠加;fact-change decision 矩阵 |
|
|
|
+| 契约失效在暂存时提前解除 | 旧测试只验证 stage 前阻断,未验证 stage 后篡改、状态洗回和提交未知 | 生效章收紧为下一未定稿章;持久 guard 使用待重做/待提交原包 hash 证明,finalize 重验并只在 commit confirmed 后精确释放;覆盖 restage/reject/discard、坏 guard、坏 meta、包篡改和二次更新 |
|
|
|
+| 两审结果只绑定正文 hash | 旧测试只证明另一份正文不能冒充,未覆盖相同正文跨契约或上下文延迟回流 | 完整 ReviewInput 增确定性令牌,绑定章号、完整草稿/章档案、契约版本/内容及全部审稿上下文;外层与两份报告三处原样回传,save-review 在共享锁内重组核对,暂存/定稿再验 sidecar;input-binding、命令链、staging/finalize 与宿主壳回归 |
|
|
|
+
|
|
|
+## 2.1 调用覆盖盘点
|
|
|
+
|
|
|
+按调用者矩阵第 2 节调用链逐点核对(测试文件相对 `v7/test/`)。
|
|
|
+
|
|
|
+| 调用点 | 生产入口 | 测试证据 |
|
|
|
+|---|---|---|
|
|
|
+| 建书 knowledge-pack(路由归一+材料+未命中) | `src/commands/knowledge-pack.js` / `resolveBookKnowledge` | knowledge/pipeline.test.js「knowledge-pack 命令:归一 + 材料 + 未命中如实(A1 未命中降级)」;index.test.js「resolveBookKnowledge:主/副题材/流派分别归一、去重,兼容只提醒不删除」「跨维输入如实未命中」「兼容范围为空表示无需窄范围提醒」 |
|
|
|
+| 建书 knowledge-query(少量材料/可拒绝/受控类型) | `src/commands/knowledge-query.js` / `queryKnowledge` | query-command.test.js「只给少量材料并明确允许拒绝、自定义」「无命中不回退全量菜单;非法维度前置拒绝」「创意约束按未决问题给材料,不按题材固定选择」「故事对象类型筛选使用受控字段并拒绝未知类型」;index.test.js「queryKnowledge:按真实问题机械命中、最多三条、近期只软降权提醒」 |
|
|
|
+| 建书 persist-book(契约+选择记录原子落盘) | `src/commands/persist-book.js` / `validateCreateBookPayload` | pipeline.test.js「persist-book:作品契约与选择记录作为必需真源原子落盘」;contract.test.js「建书契约:作者确认、八小节、三差异化、五结算全有效才通过」「book、最终选择和来源版本必须同一份答案」 |
|
|
|
+| 建书 persist-contract(版本递增/下一章立即生效/持久失效守卫) | `src/commands/persist-contract.js` / `validateContractUpdatePayload` / `src/staging/contract-invalidation.js` | contract.test.js、persist-contract.test.js:版本严格加一、`生效起章 === nextChapter`、证据与影响范围、全部未发布工件失效、二次更新阻断、待重做/待提交证明与提交三态 |
|
|
|
+| 对象 persist-design(写计划对象/冲突拒绝) | `src/commands/persist-design.js` / `validateDesignPayload` `buildDesignChangePlan` | design.test.js「计划对象最小 schema」「拒绝嵌套/非法类型/缺一致性边界」「ID 英文必须大写」「落盘前检查 ID/正名/别名冲突」「现有目录重复 ID 读取前发现」「payload 必须作者确认,保存与放弃不能同一 ID」 |
|
|
|
+| 对象 read-design(精准读取计划对象) | `src/commands/read-design.js` | design-pipeline.test.js(管线读取);chapter.test.js「本章对象声明只加载命中计划,并明确计划不等于事实;缺失只提醒」 |
|
|
|
+| 对象 factChanges(事实转正/冲突/选项执行) | `src/knowledge/fact-changes.js` / `validateFactChanges` | fact-changes.test.js、commands/fact-change-decisions.test.js:首次转正、完整冲突呈报、选项强制 `applyChange`、作者裁决保留原选项并命中 `optionId`、false 全链 no-op、hash 与路径安全 |
|
|
|
+| 章级 声明解析 | `src/knowledge/chapter.js` `parseChapterDeclarations` | chapter.test.js「章级声明一次性切换到四维、变体与对象,四维均可多选」 |
|
|
|
+| 章级 候选(序6 DTO) | `src/state-machine/dto.js` `chapterKnowledge` | dto.test.js「序6 DTO:四维只给按本章语料命中的少量候选,不暴露全量菜单」「批内前章选择只触发软重复信号」「技法维度使用同一候选接口」 |
|
|
|
+| 章级 落笔注入(prep 只读选中切片) | `src/prep/*` | knowledge/pipeline.test.js「备料注入:契约常驻 + 声明命中切片 + 自定义声明降级(A2)」「备料阻断:契约缺失不从文风旧路径补造」「备料降级:无 packageRoot 零报错(A3)」 |
|
|
|
+| 章级 审稿注入(review 只读审稿切片) | `src/review/*` | pipeline.test.js「审稿输入:冻结契约 + 声明命中审稿切片,不回读当前题材/流派」「审稿输入阻断:契约损坏时不回读当前题材条目」 |
|
|
|
+| 章级 审稿输入绑定(签发/回流/消费) | `src/review/input-binding.js`、`review/index.js`、`review/outcome.js`、`commands/review-input.js`、`save-review.js` | input-binding.test.js、input-binding-integration.test.js:确定性、任一字段漂移、v1→v2 同正文延迟回流、同版本细纲/批内上下文变化;orchestration/outcome/command/staging/finalize 测试:三处令牌、完整 front matter 与 sidecar 复核;host-shell/CLI 测试:角色和技能协议进入全部生成壳 |
|
|
|
+| 章级 章档案(确认时来源冻结/严格归档) | `chapter.js` `buildChapterKnowledgeSnapshot` `archiveChapterKnowledgeFromOutline` | chapter.test.js、staging/chapter-knowledge-validation.test.js:细纲与快照原子写;引用变更/删除仍保留 H1;缺失/旧版/hash 漂移停止;无细纲只保留并校验现行三段式选择/两段式变体 |
|
|
|
+| 章级 近期历史(软降权) | `chapter.js` `readRecentChapterKnowledge` | chapter.test.js「近期历史合并定稿章与批内前章,按章倒序且不读取额外反馈表」「细纲声明到近期软降权闭环:未选候选不持久化、自定义不阻断」 |
|
|
|
+| finalize(章+事实+计划删同一原子/契约证明释放) | `src/finalize/*` / `src/commands/finalize.js` / `src/staging/index.js` | fact-changes.test.js:真写入与正文同 commit、false no-op、冲突/碰撞零写;finalize 与 persist-contract/staging 回归:断电回滚、提交未知保留工件与 guard、批量入口重验原始包 hash 并仅在 confirmed commit 后精确释放 |
|
|
|
+| 卷末复盘(序4) | `src/commands/persist-volume-review.js` / `persistVolumeReview` | state-machine/persist.test.js、router.test.js、commands/f1-seams.test.js:收卷触发、卷摘要/下卷纲与 vol commit;写盘边界缺失/损坏契约时零文件、零 commit |
|
|
|
+| 契约问题→复盘信号 | `src/knowledge/contract-issues.js` | contract-issues.test.js「阈值:同类连续两章或同卷三次才产生复盘信号」「定稿章档案是唯一输入,空章不制造占位」;dto.test.js「契约重复问题在细纲停顿点呈报,卷末固定汇总」 |
|
|
|
+
|
|
|
+**初轮清单(已被上方最终校正取代):** 当时每个已知调用节点都有测试,但测试集合没有覆盖父 AC 的全部语义。最终补测和修复见上表。
|
|
|
+
|
|
|
+## 2.2 降级路径核对(错误矩阵逐行)
|
|
|
+
|
|
|
+对照 knowledge-runtime.md §4 错误矩阵,每行给测试/代码证据:
|
|
|
+
|
|
|
+| 矩阵行 | 证据 |
|
|
|
+|---|---|
|
|
|
+| 通用维度目录缺失/查询无命中 → 空候选不阻断 | index.test.js「queryKnowledge:对象子类筛选有消费者,缺目录与非法维度空集降级」;query-command.test.js「无命中不回退全量菜单」;pipeline.test.js「知识库整体缺失时序1/序6 DTO 零报错(A3)」 |
|
|
|
+| 作品契约缺失/损坏 → 停止+中文错误,不读旧路径补造 | pipeline.test.js「备料阻断:作品契约缺失时不从文风旧路径补造」「审稿输入阻断:契约损坏时不回读当前题材条目」;`validateWorkContract`(contract.js:122)返回中文 errors |
|
|
|
+| 序 4/序 6 契约缺失/损坏 → 阻断 DTO,不调用 AI 或写盘 | router.test.js、state-machine/persist.test.js:起草细纲与卷复盘入口/持久化边界双层阻断,零文件、零 commit |
|
|
|
+| canonical 路由未命中 → 原样报告 | index.test.js「resolveBookKnowledge:跨维输入如实未命中,保留显式流派选择」;「resolveLabel 边界:快穿/种田只归流派,歧义和复合词不猜题材」 |
|
|
|
+| 流派兼容范围为空 → 不产生提醒,无「全部」占位 | index.test.js「resolveBookKnowledge:流派兼容范围为空表示无需窄范围提醒」;`loadRoutes` 无「全部」分支(index.js:92-117) |
|
|
|
+| 类型/副题材含非正式题材名 → 建书/契约失败 | contract.test.js「book、最终选择和来源版本必须同一份答案」;`CANONICAL_TOPIC_NAMES` 校验(contract.js:38、validateCreateBookPayload) |
|
|
|
+| 类型=衍生但无正式副题材 → 失败 | contract.test.js「衍生契约:必须同时选择至少一个实际世界副题材」 |
|
|
|
+| 数值节奏配额缺任一说明 → 失败 | contract.test.js「节奏数值配额:必须同时写明统计对象、使用目的和失效条件」 |
|
|
|
+| 计划对象 ID/正名/别名冲突 → 写盘前拒绝零变更 | design.test.js「计划变更在落盘前检查 ID、正名与别名冲突」「现有计划目录重复 ID 读取前发现」 |
|
|
|
+| 计划对象知识依据/本书适配/来源格式错误 → 写盘前拒绝 | design.test.js、design-pipeline.test.js:缺来源、多个/空适配、traversal、错维、反斜杠、绝对/嵌套路径及畸形 hash 反例 |
|
|
|
+| 故事对象 --类型 非受控值 → 前置拒绝并列允许值 | query-command.test.js「故事对象类型筛选使用受控字段并拒绝未知类型」;index.js `KNOWLEDGE_FILTER_VALUES` |
|
|
|
+| 故事对象目录缺失/无命中 → 空候选可自定义,不回退旧 CSV | chapter.test.js「故事对象候选只在规划阶段本书化;prep/review 不回读通用条目」;index.test.js「queryKnowledge:缺目录与非法维度空集降级」 |
|
|
|
+| 契约修订缺证据/影响范围或缓存不可确认下一章 → 零变更 | contract.test.js、persist-contract.test.js:payload 前置拒绝;缓存查询失败不猜第 1 章,契约/记录/失效状态均不落盘 |
|
|
|
+| 生效章不等于下一未定稿章或既有 guard 未收口 → 更新停止 | contract.test.js、persist-contract.test.js:早/晚生效均拒绝;待重做或待提交证明存在时二次更新 fail closed |
|
|
|
+| factChanges 冲突详情或选项不足 → review 前置拒绝 | review/schema.test.js、review/outcome.test.js、commands/fact-change-decisions.test.js:差异、影响、至少两个唯一选项缺一即拒绝并完整呈报 |
|
|
|
+| factChanges 选项/作者裁决执行语义畸形或篡改 → 整章零写 | knowledge/fact-changes.test.js、finalize/fact-changes.test.js、staging/fact-changes.test.js:每项 `applyChange:boolean`,裁决保留 options 并命中 `optionId`;false 真 no-op |
|
|
|
+| factChanges 冲突/hash 漂移/路径逃逸 → 整章零写入 | fact-changes.test.js「冲突/歧义/未说明裁决写盘前停止」「覆盖既有事实必须匹配哈希」「路径逃逸和同批重复目标被拒」「finalize:冲突零写入」 |
|
|
|
+| `save-review` 外层/任一报告缺失、混用令牌,或当前完整 ReviewInput 已变化 → 两审零写入 | review/orchestration.test.js、commands/f1-seams.test.js、review/input-binding-integration.test.js:三处令牌必须相等;sidecar 自洽且与锁内重组的当前 DTO 相同;旧 v1 报告不能跨到 v2 契约回流 |
|
|
|
+| 审稿结果令牌/sidecar/正文/完整章档案漂移 → 暂存、重审或定稿停止 | review/outcome.test.js、commands/persist-contract.test.js、staging/index.test.js、finalize 测试:缺/坏 sidecar、相同正文不同标题/伏笔/收卷、章号错配均零写;批内重审必须使用 `batch-status` 给出的暂存草稿路径 |
|
|
|
+| 细纲来源快照缺失/旧版/结构错/hash 漂移 → 暂存/定稿停止 | knowledge/chapter.test.js、staging/chapter-knowledge-validation.test.js:不从当前 references 重建历史来源;无细纲只接受严格现行章档案 |
|
|
|
+| guard/marker/ready proof/批次或原始定稿包不一致 → 暂存、叠加、定稿停止 | commands/persist-contract.test.js、staging/finalize-batch.test.js、staging/fact-changes.test.js:坏 guard、坏/缺 meta、状态洗回、包替换、提交未知均保留守卫与工件 |
|
|
|
+| installer 缺治理文档或 README 链接目标 → 测试失败 | references/format.test.js、installer 测试与 `scripts/pack-install-e2e.mjs` 同验源码、npm 包、中文路径安装和治理链接 |
|
|
|
+
|
|
|
+**错误矩阵映射完整性:22/22 行全部有证据,无空白行。**
|
|
|
+
|
|
|
+## 2.3 负向断言
|
|
|
+
|
|
|
+grep 生产代码(`v7/src/`)确认下列不存在:
|
|
|
+
|
|
|
+- **评分/满意度/章后反馈字段(持久化层)**:`grep 评分|满意度|章后反馈|反馈表|rating|satisfaction` 在 `src/` 无命中。唯一出现的 `score` 是 `queryScore` 的临时候选排序分,不落盘——`renderKnowledgeSelectionRecord` 只写「维度:名称/来源/本书变体」与「实际裁决」,`buildChapterKnowledgeArchive` 只写最终 `维度|名称|来源` 和独立 `变体|…`,均无评分/反馈字段。对应正向:contract.test.js「知识选择记录只保存最终采用和真实裁决,不制造评分或空反馈」。
|
|
|
+- **作者扩库/投稿命令**:`grep 扩库|投稿|submit-knowledge|作者提交|contribute` 在 `src/` 无命中;`src/commands/` 中无任何写通用 `references/` 的入口(策展只在 Trellis 开发治理)。
|
|
|
+- **旧 v7 知识协议 fallback**:`grep 题材流派指导|恩怨清算|规划这一章时` 在 `src/` 无命中。作品契约不回读旧路径,知识条目不双读旧标题;对应正向:index.test.js「readEntry 规划切片只认『规划时』标题,不再双读旧标题」。既有 v6→v7 书仓迁移不在此断言范围。
|
|
|
+- **解析而无人读取的字段**:对照矩阵 §3 条件式字段,节拍/追读的 `适用题材` 不在任何维度 `索引字段` 中(DEFINITIONS,index.js:51-86 只含 名称/编号/一句话/关键词/类别/作用层级/触发问题/对象类型/人物类别/命名对象),queryScore 也只读 `索引字段`——即「适用题材」无消费者,且 spec 已禁其回流章级 FM。无「解析但无人读」的残字段。
|
|
|
+
|
|
|
+**负向断言结论:四项全部成立。**
|
|
|
+
|
|
|
+## 2.4 挂账 #4/#8 核对
|
|
|
+
|
|
|
+- **#4 章级候选纪律(每维≤3、可组合/拒绝/自定义)**:序6 DTO 的 `期望产物` 明确写「章级候选只是少量材料,不是固定答案。可组合、变体或完全自定义,作者确认整份细纲即确认这些软策略」;`chapterKnowledge` 对四维统一走 `queryKnowledge`,`MAX_KNOWLEDGE_CANDIDATES=3` 硬顶三条。测试 dto.test.js「序6 DTO:四维只给按本章语料命中的少量候选,不暴露全量菜单」佐证。**结论:已在 DTO 提示文本和查询上限双重覆盖。**
|
|
|
+- **#8 技法候选无优先级**:技法与其余三维共用同一 `queryKnowledge` 接口和 `MAX_KNOWLEDGE_CANDIDATES=3` 上限(dto.js:156-166 对 `CHAPTER_KNOWLEDGE_DIMENSIONS` 无差别处理),受「≤3 条 + 可拒绝/自定义」纪律统一约束,无需独立优先级机制;技法 `索引字段` 含 `触发问题`(index.js:78-81)参与 queryScore 排序,同维内已按问题相关度排序。测试 dto.test.js「序6 DTO:技法维度使用同一候选接口,并把规划切片交给真实消费者」佐证。**结论:技法「无优先级」担忧被『≤3 + 同问题排序 + 可拒绝』纪律覆盖,不构成缺口。**
|
|
|
+
|
|
|
+## 测试结果
|
|
|
+
|
|
|
+初轮 `PYTHONUTF8=1 npm --prefix v7 test` 为 579 / 579 绿,但该数字只代表二次审计前的历史基线,不能作为最终签收。完成 13 项纠偏后的最终全量结果以本任务 `质量门记录.md` 的同次收口运行准,二者在签收时同步。
|
|
|
+
|
|
|
+审计过程中一度出现 1 红 `v7/test/knowledge/index.test.js:163`「queryKnowledge:每条创意约束都能从真实未决问题首位命中」——非生产代码 bug:有人把 audit-neardup 初版报告的锐化建议逐字应用到 `v7/references/创意约束/不可逆代价.md`,把 `一句话` 里「能力没有代价、金手指太万能」删掉,而这正是该维(创意约束 `索引字段=['名称','一句话']`、queryScore 不读正文)唯一的检索命中语料,也是下一行那条真实作者查询串。经核实 `queryKnowledge` 按维度隔离检索,创意约束(不可逆代价)与设定(能力代价)分属两次独立查询,不存在跨维误召,删词纯属自损可发现性、零去重收益。该红灯捕到的是真回归。audit-neardup 已复原条目(一句话保留「能力没有代价」命中词 + 前置不可逆区别键,设定条改多维边界表述)并撤回错误建议。测试是正确探针;为处理这次临时红灯没有修改生产代码或测试。
|
|
|
+
|
|
|
+## 批次 2 结论
|
|
|
+
|
|
|
+- 初轮按调用点名称盘点为 0,最终逐 AC 数据流与对抗审计发现并修复 **13 项**绿灯盲区;新增/加厚行为测试覆盖见本报告开头校正表。
|
|
|
+- 错误矩阵映射完整性:**22/22 行全部有测试或代码证据**。
|
|
|
+- 负向断言:**四项(评分反馈/作者扩库/旧路径双读/无消费者字段)全部成立**。
|
|
|
+- #4/#8:章级候选「≤3 + 可组合/拒绝/自定义」在 DTO 文本+查询上限双重覆盖;技法「无优先级」被同一 ≤3 纪律覆盖,非缺口。
|
|
|
+- 审计期间一度 1 红,系 audit-neardup 初版锐化建议误删真实检索命中语料所致(真回归);条目已复原,测试本身是正确探针未改。最终全量数字只取收口质量门的同次运行。
|