zizi 9712589bfe 工程(测试): 旧库迁移工具链退场;共享库种子登记与例前兜底清空
- 删除 数据库/旧库迁移 工具树、旧库迁移用例与旧库样本夹具;摘除 Makefile/pyproject/ruff/pyright 与 PYTHONPATH 引用,同步 README/AGENTS/设计文档与索引、分片工具
- 清空业务数据改按 种子表 登记过滤:未知 schema 与新增运行时表默认清空,迁移账本/索引代次单例/原文命名空间/结构种子保留;迁移新增种子表漏登记由新单测机械拦截
- 共享库复用前兜底清空,防上例强杀残留;例间只清数据不删表,个案探针表须自带 DROP TABLE IF EXISTS(规则与迁移用例同步)
- 底座生命周期单测由 15 例精简为 5 例(保留清理、未封存模板、失败清理相关用例),其余 11 例随本批移除
2026-09-18 14:13:52 +08:00

412 lines
61 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!-- 导航元信息: {"内容描述": "旧知识记录分流(已退役)", "使用场景": "追溯已退役的旧库迁入合同", "使用要求": "不作为现行产品入口"} -->
# 旧知识记录分流
**现行状态:已退役。** `数据库/旧库迁移/` 工具链与对应测试已删除,不再提供分流/导入命令。下文只保留当时合同文本,供历史对照;新工作以现行 B03 资料导入与灾难备份恢复为准。见[R2 改造历史留痕](../../实现回顾/R2改造历史留痕.md)。
本文当时定义混合知识记录的迁移规则。输入是隔离快照中的旧表、结构版本、作品用途映射和确认依据;不查询或改写正式库。迁移不使用模型推断归属,也不以 work_id=0 或 draft_type=entity 单独确定业务含义。
## 先固定源身份
每条输入保留来源数据库、表、主键、revision、完整 payload 与源哈希;删除状态、来源状态、授权策略及确认引用只保留源中实际存在的列。不得为满足转换条件向原行补写旧DDL不存在的列。映射键包含来源命名空间,PG 与 SQLite 中同号记录不能合并。
先建立显式 legacy_work_map:作者作品映射 B01 work,参考作品映射 B03 source;同一本书同时具有两种用途时分别登记两个对象和关联。example_reference_work 等档案是用途证据,歧义需要列入差异清单;不按书名、作品号大小或当前脚本入口猜测。work_id=0 是旧公共范围哨兵,目标中使用作者方法库作用域,不创建“作品 0”。
## 独立快照与分流命令
纯分流命令接收快照 JSON 与显式映射 JSON,不连接数据库。快照每条包含 `source`(`system/database/table/id/revision`)和完整 `record`;`system` 为 pg、sqlite 或 file,`database` 是来源库或导出集合的稳定标识,不是连接串。源内容哈希由确定性 JSON 计算;可携带的 `source_hash` 必须与计算值一致。对象身份不含版本,源记录身份包含版本;同一对象的不同版本不能因此变成不同实体。
映射配置包含:`works`(明确 author/reference/method 用途、目标与作者)、`sources`(旧来源类别/编号到所属作品及来源引用,`chapters` 将旧章号映射到稳定定位)、`objects`(同来源库、旧作品、`use` 与目标 `scope` 内的 entity/draft ID 或明确别名到目标)、`type_aliases`、`schemas`(固定动态字段 JSON Schema)及 `confirmations`(已确认目标与原决定来源)。缺少映射、字段合同或确认依据不猜补。同书多用途通过 `routes` 的 `source_key/source_hash/use` 按记录明确选择,不向原行注入迁移用途,不按脚本名替代选择。引用别名只在显式配置中解析,不能把“拆书@…”字符串当授权。
纯分流只输出 `待转换/历史保留/隔离` 之一及原因、拟归属、原快照和哈希,不声称目标已经落库或作者已经批准。`导入新库.py` 核对真实目标与来源后才能把“待转换”记为已映射。每条输出保留完整原行,未知值不会因为尚无目标字段而丢弃。
运行入口:
```bash
uv run python 数据库/旧库迁移/入口.py 分流 \
--快照 /private/快照.json --映射 /private/映射.json --输出 /private/分流计划.json
```
快照文件是记录数组;单文件上限16MiB,超限必须显式分批,不截断。命令退出0表示计划没有隔离项,退出2表示计划已保全但含隔离项,退出1表示输入、配置或文件操作错误;均不代表导入成功。输出包含源集合与映射配置的哈希、逐条判定和完整原行。计划以私有文件权限原子创建;同内容可重放,不覆盖不同内容或输入文件。
## 只读源加载
PG读取使用显式连接说明文件、数据集标识、schema、租户和表集合;连接说明是一行包含host/dbname/user的DSN,不回落默认环境,不进入快照或驱动错误输出。服务器事务固定为只读可重复读;有tenant_id的表必须明确租户,不能跨租户读取后再靠分流过滤。无租户表须显式选择全局范围。SQLite只读取显式副本路径,使用URI只读模式及query_only;不创建缺失文件。
两类读取器只允许Git中旧DDL登记的物理表,主键从数据库元信息获取;单列id沿用原编号,其他单列或复合主键以确定性JSON编码。没有原生revision列时必须使用操作者提供的快照版本,不把它描述为旧表的原生修订号。读取结果的source.database由数据集标识与schema/租户范围确定性编码;映射使用导出的完整标识,不放入连接串或凭据。
读取有行数与序列化大小上限,超限失败、不静默截断;读取不等于导入、确认或当前授权。旧元数据表也作为原快照读取,实际结构/字段与用途解释由转换和对账负责;不执行旧DDL来建设新库。
只读导出示例(路径、数据集和租户均为示例值):
```bash
uv run python 数据库/旧库迁移/入口.py 读取PG \
--连接说明 /private/旧库连接.txt --数据集 合成旧PG --schema public --租户 7 \
--表 muse_knowledge_entity --快照版本 export-v1 --输出 /private/PG快照.json
uv run python 数据库/旧库迁移/入口.py 读取SQLite \
--副本 /private/旧库副本.db --数据集 合成旧SQLite --表 runs --表 events \
--快照版本 export-v1 --输出 /private/SQLite快照.json
```
无租户PG表使用`--全局`而非`--租户`,二者必须明确选择一个。分批可加`--主键范围 /private/范围.json`,例如`{"events":{"start":["run-1",1],"end":["run-1",100]}}`;每个边界按原主键列顺序给完整数组,start包含、end不包含。未指定范围时读取所选表/租户的完整集合,仍受`--最大行数`与16MiB上限约束。
## 字段归一
| 旧载体 | 规范含义与目标 | 冲突处理 |
|--------|----------------|----------|
| payload.type / 型 | type_id;按固定旧结构身份和已登记别名解析 | 两键同时存在但不同,或未知类型,记录歧义,不按取值优先级吞掉另一键 |
| name / 名称 | 名称与独立别名集合 | 保留原字符串及规范值;不同记录同名不据此合并 |
| brief / 一句话摘要 / description / 描述 | 描述 | 原值保留;正式表SQL NULL归空描述,非字符串不默转;不同键冲突进入差异记录,不补问号 |
| fields / 字段 / attributes | 按固定结构版本映射的动态值 | 多键须一致且为对象;未知字段、类型不符或缺必填保留在隔离记录,不包成sourcePayload |
| 别名、出场章、字段.演变历程 | 名称索引、来源位置、时点事实或参考分析轨迹 | 章号通过源作品与顺序映射到稳定章节/来源定位;缺章或冲突不能补猜 |
| source / 来源 / 出处 / 实例 | 来源版本、定位与引文;字符串“拆书@…”只作来源提示 | 不把字符串变成已验证引用;实例中的“书”单独解析,不能全部绑定 source_id 指向的第一本书 |
| 状态、目标库、可见范围、_work_id | 旧描述信息与一致性校验线索 | 不覆盖表级确认、作品映射和当前用途授权;冲突留在差异记录 |
旧 payload 原样随迁移来源保存;归一后的字段使用 S04 结构绑定。原文、不确定字段、归并审计和被合并卡的全文不能因没有目标字段就被静默丢弃。
### 旧载荷兼容、名称端点与章级来源
输入白名单扩展恰为`description/描述/evidence/证据/attributes`;`source_hint`是派生内容,不是输入白名单字段,其余未知输入仍报unknown_fields。描述四键、字段三键用稳定JSON作一致性比较,冲突报field_conflict;字段非对象报field_type_mismatch。实体名称保原显示值,不为复制旧内部normalized_name而改变S04名称。
关系先判型,source/target只作端点,不交给实体来源解释器。表级source_entity_id/target_entity_id及甲方draft/乙方draft为明确强ID(非空str/int,拒bool);表级SQL NULL表示未提供外键,不生成强引用。顶层source/target整数严格用`type(v) is int`形成entity引用;字符串形成name引用,数字字符串也不按外观改成ID。匹配名称用strip去首尾空白,原串保原快照,不做casefold/Unicode规范化;空白名拒绝。名称对象只接受name/名称两键中的至少一个,双键须稳定JSON一致、值为非空字符串;未知键、冲突、空对象、数组、bool、None均拒绝,不再str容器。甲方/乙方/甲方名称/乙方名称及字段中的同名提示也只接收非空字符串。
objects.refs须显式登记name:<匹配名>、entity:<旧编号>或draft:<旧编号>;这些迁移引用不是新对象ID或业务别名。强引用优先但核所有提示一致,同端各提示必须指向同作用域唯一对象。错误沿missing_endpoint/ambiguous_endpoint/endpoint_conflict、unknown_fields/field_type_mismatch/field_conflict;所有端点错误detail固定为relation.source或relation.target,不包含原值;关系端点解析先于动态结构校验,避免字段内坏端点被通用结构错误遮蔽。缺失端为missing_endpoint。分流只解析身份,真实类型由B02/S04校验;character_relation两端须为同作品已确认character,不从名字或关系词推断类型,不更改不兼容对象的类型。
实体source/来源/出处多键须稳定JSON一致。缺失表示无声明,明确提供的值只接受字符串提示或对象;字符串只保原提示,不产生授权。对象键须为workId/chapter/chapterId的子集,未知键报unknown_fields;各值为非空str/int且非bool。只有author用途且source_type=chapter_extract可解释该对象,其他用途/来源遇此对象报unknown_source并保全,不静默忽略。关系的source/target不按此解释;其余未解释的原来源提示仍保原快照,不凭提示产生引用。
章声明与来源表共同核对:workId若给出,str值须等于表级work_id和已映射来源work_id;chapterId若给出须等于表级source_id,否则source_scope_conflict。chapter与顶层章序若同给,须str值相等,否则scope_conflict;都要求非空str/int非bool。章序采用明确给出的chapter,未给才用顶层章序,二者均未给不猜第一章;给定章经sources.chapters[str(章)]解析稳定定位,缺失报missing_location。标识比较只用str,不去前导零或重写原值。source_hint保实际提供的旧对象键和evidence,不回填缺失键,不注入原record;原旧整数与新B01章节ID通过显式映射关联。
`evidence/证据`用稳定JSON比较双键,只接收str或None;缺失、None、空字符串不构成证据。非空证据按原码点保留,不strip、不归一化。仅author+chapter_extract的B02目标执行章级交叉核对:body_bindings按source_key/source_hash唯一绑定且sources是非空对象数组;至少一条真实依据满足chapter_id等于分流首来源target_ref、str(revision)等于首来源revision。revision只接受str/int且拒bool。非空旧evidence必须与这些同章同版本依据中至少一个锚点quote逐码点相等,不能在别章找到相同句子便算成功。身份/版本/引文等式不满足报target_source_mismatch;缺绑定仍为target_source_missing。拒绝产生零S01命令/领域写入,台账保留原记录与拒绝。满足等式之后B02仍核真实正文、哈希、位置、归属和S04类型;匹配不是批准。不把章级等式套到parse_book/upgrade_book的书级引用。
character/character_relation没有brief或description目标字段,归一描述留在分流content.brief及原快照/台账,不发明新S04字段、不把描述塞进source_hint。结构化来源与引文提示留source_hint;实际依据由body_bindings固定。实体目标字段显式映射名称←name、身份定位←fields.身份;关系映射甲方←source、乙方←target、关系类型←relation_type。仍拒绝未消费动态字段target_field_unmapped;目标结构允许且已明确映射的其他字段遵原合同。
## 业务分流矩阵
按明确用途、具体类型和来源共同匹配;多条冲突或无匹配均进入隔离清单。
| 规则 | 旧记录条件 | 目标模块、类型与作用域 |
|------|------------|------------------------|
| K01 | draft_type=entity,source_type=parse_book,work_id=0,型为 craft/combat/emotion/scene_pattern/trope | B04 方法候选,保留原 type_id;source_id 映射 B03 原书,出处/实例映射来源定位。公共范围不等于已批准或无限制可用 |
| K02 | 作者作品中的 entity;type 为 character/location/item/faction/power_system/event;来源与作品一致 | B02 的实体或事件提案;固定作者作品、原来源及结构。pending 不直接变成正式事实 |
| K03 | 参考作品中的相同六型,来源为 upgrade_book/parse_book 等已登记抽取来源 | B03 的分析版本和分析项,仍为参考知识;不得落成当前创作作品的已知事实 |
| K04 | draft_type=entity 且 type=character_relation | 这是旧升格管线的关系卡。根据作品用途进入 B02 关系提案或 B03 关系分析;端点从字段.甲方/乙方、原 draft ID 或明确名称解析,不作为普通实体保存 |
| K05 | draft_type=relation,端点为 source/target 或甲方/乙方,关系类型为 type/关系类型 | 同样进入 B02 或 B03 的关系对象;先解析端点再写关系,不能与 K04 因行类型不同而重复建立同一来源对象 |
| K06 | 已确认 muse_knowledge_entity / relation 及对应草稿的 entity_id / target_object_id | 根据用途进入 B02 正式对象、B03 已确认分析或 B04 方法版本;草稿保留确认历史并指向同一个目标对象,不能再次复制为新候选 |
| K07 | character 公共写法、style/pacing 或其他可复用模具 | 只有明确方法用途及证据才进入 B04;本书 style 属 B06 声音,pacing 规划属 B01。类型名本身不足以判定用途 |
| K08 | 具备明确作用域与端点的向量记录;SQLite cards、snapshots另核原列条件 | PG向量记录只承接 B09 来源与索引身份,不造知识卡、不提升正式状态。普通cards缺当前授权,snapshots缺作品身份,现行默认隔离;不能以旧确认引用代替缺失的身份与用途授权 |
SQLite `cards` 的实际列为 `id/kind/title/payload_json/embedding/work_id/source_path/content_hash/created_at`;`snapshots` 只有 `id/kind/payload_json/created_at`。正常payload的snapshots报 `unknown_use`,即使payload内带作品提示也不据此补work_id;已知作品用途的普通cards仍报 `permission_conflict`。坏payload先报 `payload_invalid`。以PG身份伪称cards/snapshots报 `unknown_table`,向镜像快照注入授权等非原列报 `unknown_fields`,原行与源哈希仍保留。
以后承接镜像内容须先获准独立作品、用途及授权映射合同,映射绑定 `source_key/source_hash`,另有映射版本与哈希;原快照始终不补授权字段。当前尚未提供该映射入口,增加确认引用不会自动解除隔离。向量身份用例不代表普通内容镜像迁移成功。
其他已登记类型按[内置类型承接表](内置类型承接表.md)及明确实例用途扩展规则。没有对应生命周期的旧值先隔离,不以“元数据可扩展”为由创建无行为归属的新实体。
## 确认状态与当前有效性
| 旧状态 | 目标处理 |
|--------|----------|
| pending、payload 写“草稿” | 所属模块未决候选或分析草稿;置信度高不能代替作者确认 |
| confirmed 且正式目标、确认记录及来源可关联 | 保存同一目标正式版本与决定来源;候选成为已采纳历史;当前可用性再按来源和授权计算 |
| confirmed 但目标缺失、身份矛盾或确认依据无法证明 | 原状态进入历史,目标标为迁移待复核且不可用于当前生成;不伪造作者决定 |
| rejected、discarded、superseded、deleted=true | 原拒绝、替代或删除历史;不复活为活跃候选、别名或索引 |
| 来源撤回、用途不允许或结构不可解释 | 保留记录但退出当前消费;补证或改用途须经所属正式流程 |
引用顺序是来源/作品/结构 → 实体或方法 → 关系/绑定 → 候选与正式版本对应 → 运行、决策、向量和历史审计。名称端点须在同一作用域唯一匹配;旧数值 draft ID 先查映射,不当作新实体 ID。向量记录保留原模型、维度和哈希,内容或模型合同改变时重建;冲突 owner 不按导入顺序抢占。
## 隔离目标与迁移台账
迁移目标必须是获准PG实例中的新建随机库:支持独立本地测试实例,也支持明确获准的infra远程实例与旧源同实例、不同库隔离。应用业务用途为production、角色为muse_app,以复用S01的真实提案和幂等回执;此用途标记不授权生产切换,也不扩大S01的evaluation写入权限。目标初始化不接受调用者指定库名,源库与任何既有业务库均不能作为目标,不以另一schema替代数据库隔离。
允许实例配置来自受控的实例创建/核验记录,不来自待迁快照或映射。端点记录明确包含endpoint_type(unix或tcp)、host及整数port;unix的host是绝对socket目录,tcp的host是单个明确批准的IP字面量(infra为100.64.0.8:5433,不接受DNS名称、通配地址或多主机)。旧本地测试记录{socket,port,system_identifier,data_directory}仍仅按unix解释。完整允许记录另含实际查询取得的system_identifier(十进制字符串)和data_directory(绝对路径),不得用示例指纹核准真实实例。连接必须显式指定相同host、dbname、user;port须显式等于允许端点,或在连接串缺省且允许端口为libpq默认5432时按等价效核准;同时拒绝PGPORT环境覆盖,避免缺省端口与实际连接端口背离。拒绝hostaddr、service、多端口、可展开的dbname、options及未列入连接白名单的参数,同时拒绝PGHOSTADDR、PGSERVICE、PGSERVICEFILE、PGOPTIONS、PGPORT环境覆盖。凭据与TLS参数只用于认证或传输,不改变核准端点。
初始化及写入前均须实际查询实例,并比较系统标识、数据目录和端点。目标回执version=1,字段固定为:target_id、system_identifier、data_directory、host、port、database、database_oid、role、run_purpose、created_at;数据库名由初始化程序随机产生,role=muse_app、run_purpose=production。端点类型在允许实例记录中登记,回执沿用host字段绑定实际端点,不更改库内标记结构。管理/应用凭据引用单独保存,不将值写进回执。
目标回执还须与目标库中唯一的初始化标记一致;应用角色只能读该标记,不能自造或更换。实际端点/实例、数据库OID/名称、角色/用途任一不符或回执缺失都拒绝。回执只证明目标身份,不替代操作者授权或作者身份认证。
数据演进owner的public迁移台账只保存来源、映射与回执,不代替业务对象。每条以(author_id,source_key)唯一,保存完整原快照、source_hash、mapping_hash、固定命令ID、分流理由/冲突、拟业务身份、实际产物与版本、原用例回执;原始身份和哈希不可改写。状态为reserved/mapped/historical/quarantined,reserved不是成功终态,mapped必须有真实公共用例回执与目标引用。
台账与业务同一隔离库、同一production用途,但分连接各用短事务。先reserved,再调用真实领域提案,最后mapped;中断时重放作者与source_key推导的同一命令,以S01公开回执补齐,不按新内容哈希换命令绕过漂移。同键异原文或映射前置拒绝;映射修改按丢弃隔离目标重跑处理。
B02有源抽取固定independent=False并核对真实正文依据,缺依据零领域写入、原记录仍保台账;B04证据钉住B03真实版本,拟方法ID与实际提案ID分别记录。工具不调用确认/启用,不把旧分析或运行伪成新模型任务。缺公开目标入口、缺真实目标/确认链均明确保留缺口;入了台账不等于业务对象已迁。
### 目标字段与有源事实绑定
目标结构映射使用`target_schemas["B02:character"]`或`target_schemas["B04:craft"]`等owner/type_id键,明确schema_id、base_version和fields。fields是“目标字段名→源取值”的一层映射,只允许name、brief、source、target、relation_type或`fields.<原动态字段名>`,不执行表达式、不补默认值;未消费的动态字段使该条隔离。关系的source/target/关系类型取已核对的归一值,不把旧数值ID或名称当作新实体身份。
B02正文依据另由body_bindings逐source_key/source_hash固定:sources包含真实目标chapter_id、branch_id、revision、document_hash和段落引文锚点,effective_from明确时一并提供。目标请求保持非independent,S01/B02核对实际正文及结构;不从缺失章号猜生效时点。B04使用sources引用的真实B03版本。拟业务身份与实际提案ID/创建版本分别落台账,创建版本取S01原回执,不以作者之后编辑的版本冒充导入版本。
### 作品声音与节奏画像候选
K07明确author用途的pending style/pacing分别通过B06`提出声音`和B01`保存人工候选`承接。`target_schemas["B06:style"]`、`target_schemas["B01:pacing"]`沿既有字段映射,全部旧动态值须有明确去向;不把描述或源载荷塞进未知S04字段。台账保存完整原值与拟逻辑卡身份,实际产物ID由S01原回执取得,分别标为voice_proposal/plan_candidate,不将拟逻辑卡ID当作已确认声音或规划。
`asset_bindings`每条恰含source_key/source_hash/sources/parameters,按旧源键唯一匹配。sources使用B06公开声音样张引用结构(kind/ref_id/revision/source_hash/branch_id),正文须属于同作品,资料须允许analysis,哈希及全部旧来源身份/版本逐项一致;不能用别的样张替换旧来源。声音parameters只接受明确expected_voice_revision及可选verbal_tics/protected_expressions;节奏parameters只接受明确expected_revision,保持作品级规划范围。扩展及结构版本来自target_schemas,未定义参数拒绝。
冻结外壳另存asset_sources与legacy_source,用于旧新来源对账;payload为对应owner的真实DTO。声音来源同时由B06在S01提交内复检;节奏导入为人工规划候选,旧来源留在迁移台账中供人工审阅,不伪造成模型依赖或自动确认。后续规划采纳仍执行B01自身的基线、结构和作者审阅保护。中断重放原迁移命令补既存回执,不能再创建或批准。旧confirmed声明未提供真实新版确认链时保持历史,不通过pending导入复活。
### 旧规则版本与质量案例
本迁移范围只解释两类来源:`example_ai_flavor_rule` 与
`example_ai_flavor_sample`组成的规则版本,以及`example_ai_flavor_case`或明确卡片
YAML中的质量案例。`example_ai_flavor_rule_event`只保留旧激活/停用历史。
PostgreSQL `example_lesson`和SQLite `lessons`是经验记录,仍隔离交由作者经验与交付模块处理;
表名、标题或`promoted`状态都不能把它们改解为质量案例。
`quality_bindings`按每个`source_key/source_hash`唯一选择`rule_version`、
`rule_example`或`quality_case`,并冻结`author_id/sources/parameters`。规则绑定的
sources每项明确例证源键、源哈希、本源选用的sample ID、许可和来源引用;
parameters只含`rule_id/version`。转换先核PostgreSQL投影列、完整payload及
`content_sha256`,或文件快照原字节哈希;然后核规则引用的sf/snf/boundary/
regression四类例证与冻结样本集完全相等。旧`active`或批准状态只存在
legacy_source中,新版规则固定写为`candidate`,不生成B10凭据或启用记录。
投影比较仅在列与payload键同名、payload完全缺该键且投影严格等于已登记默认时解释等价:
规则`case_card_ids=[]`,样例`source_license='synthetic'`、`source_ref=''`,
对应旧DDL `111-example-humanization规则与样例.sql`的三列默认。
不补写原payload、原行或任何源哈希;显式null、非默认投影、错误类型、其他字段缺省及
内容哈希不符均不能使用此兼容。`synthetic`只保留旧默认许可,不产生正式资格;
冻结绑定仍须提供非空来源引用,迁移出处引用与旧出处分开,不以默认空串代替冻结依据。
规则导入调B06`导入规则候选`公开用例,不使用S01命令回执。台账只保存
该用例实际返回的owner回执,并要求B06提供精确单版读回:
`读取规则版本(身份, rule_id: str, version: int) -> dict`。返回必须含
`version_id/rule_id/revision/status/payload/payload_hash/activation_recorded`,其中payload恰为该版
`{rule,samples}`。迁移为候选时要求该版没有实际启用记录,即activation_recorded为false;
读取历史版本不授予新的消费或启用资格。只有最新整库fingerprint不足以证明被导入的单项;此接口缺失时
原迁移条目保持reserved,不先调owner。接口存在后,同ID同版同内容重放取
真实重复回执,同ID同版不同内容沿B06只追加版本合同拒绝并隔离。
案例绑定的sources只有一个before,分开冻结legacy的source_ref/work_ref/
source_sha256/excerpt_sha256/location、旧许可与许可证明,以及新版真实
document/candidate/source的ref_id/revision/source_hash/start/end/excerpt_hash/branch_id/
work_ref。parameters只含旧card_id与preserve_text。转换先逐字节核旧片段与
excerpt_sha256,再用B03/B05公开读取核新版作品、确切版本、全文哈希、范围和
片段哈希。两侧都可证保全许可时才preserve_text;否则只保哈希与定位。
旧标签保存为新候选的初始标签,没有可解释标签时隔离,不自动重分类;新请求
固定`mode=backfill/disposition=ask`,旧live_feedback或canonical只留台账历史。
案例通过B06`采集案例`的S01原命令保存为shadow版本,再用B06
`读取案例(..., revision=...)`对账。S01已提交而台账未转终态时,重放只读原
command receipt和原案例版本补登记,不新建案例。缺绑定、引用漂移、作品不同、
片段或许可不一致在业务操作前隔离,原快照、旧决定和准确原因留台账,不写B06案例或
S01命令。
### B03参考分析真实导入
K03的pending参考卡由B03公开`提出参考分析`保存为未决分析版本;K04/K05关系引用只在同一参考来源内校验,不写作者事实。scope必须是works.reference映射的真实B03 source_id,主来源引用同scope且revision明确;目标结构使用target_schemas["B03:"+type_id],按S04 reference_entity族及真实基础版本校验,不允许作品扩展。描述与旧来源定位保存于分析payload,不能丢弃或塞入未知动态字段。
create冻结外壳沿owner/scope/subject_ref/payload,owner=B03;payload包含analysis_id、source_id、source_revision、source_content_hash、type_id、schema_id、base_version、content、title、brief、references、legacy_source(source_key/source_hash)。固定身份和哈希须与不可变路由、原快照一致;S01人工保存动作只创建proposed分析版本,回执results含analysis_id/revision=1/content_hash,targets.kind=analysis。回执不是作者批准,model_verified=false且无研究任务。
重放与对账经B03读取确切analysis_id,逐项核owner、来源版本/hash、origin=legacy_import、content_hash及原冻结请求;原值/映射漂移拒绝。既有同ID异内容拒绝,不换命令绕过;删除/撤回旧源仍沿历史分流。B03已confirmed旧记录仍不借pending通道恢复批准,保既有历史缺口。
完整分析归属与S02旧检查点衔接统一见[B03合同](../模块设计/B03-资料研究.md#分析持久化合同),不另建旧分析专表或伪造研究任务。
### 既存确认的受限历史关联
`link_confirmed`仅适用于明确author用途、B02的K06既存目标关联,不创建正式对象/候选/作者审阅/决定/索引。旧decision_ref只是操作者登记的旧声明,新S01确认单独读取;两者不视为同一历史事件。旧草稿只有目标ID时不推断它当时的目标版本;新指定版本只对应明确提供的正式旧源快照。本模式不等于从空库恢复所有旧批准,mapped不授予当前生成资格。
confirmations条目沿原system/database/source_key/source_hash/target_ref/decision_ref,显式增加`existing_confirmation={command_id,receipt_id,revision}`(ID非空str,revision正int拒bool)。草稿还必须有`target_source={source_key,source_hash}`,正式旧源禁止该输入字段;未知键、多条、错误hash拒绝。target_ref是新世界对象ID,不带world:。未声明新字段的旧分类记录不因旧decision_ref得到新批准,仍不走本模式。
正式旧源仅为同PG命名空间/旧work_id的muse_knowledge_entity或muse_knowledge_relation;已confirmed草稿的entity_id或target_object_id必须与其原主键一致,草稿型与正式表族一致,objects.refs明确包含entity:<旧ID>或relation:<旧ID>。正式源和草稿的新目标、既存确认、作品映射须相同,旧decision_ref各自保留。关系两端先按同作品objects的entity:<旧端点ID>解析为新ID,再映字段/核哈希。正式源在显式输入中或本作者同目标台账中按精确key/hash读取,不回旧库或文件查找,不用当前目标补造旧源。
实体原status须active;关系表没有status/source_type/source_id,不填假列。两表源资格必须明确active/authorized且allowed,删除/撤回/不允许仍走历史保留。两正式表attributes的SQL NULL只在归一层作空字段,其他非对象拒绝;类型、未知动态值和未消费字段继续验证。正式实体source_type/source_id可空,不借此补造正文来源。草稿空payload/未知历史键仅保历史,不生成业务内容;豁免仅限原行已confirmed且新关联模式声明,pending不适用。
纯分流接收显式源集合,导入层可补指定的已存正式源;按“正式源→草稿”二层处理,不依赖输入顺序、不建通用图引擎。同键漂移仍整批零新写。草稿的正式源缺失或quarantined/historical时保全拒绝;正式源仍reserved时返回legacy_dependency_pending并保留本条reserved,重试只续核依赖,不伪造终态。已mapped正式源的原值/hash/mapping_hash/状态在草稿终态事务中再核。
冻结外层恰为`{mode,owner,scope,subject_ref,payload}`。mode只允许create/link_confirmed,旧冻结缺mode按create,未知值拒绝;link只允许owner=B02。link payload恰含`source_key/source_hash/mapping_hash/target_source/decision_ref/existing_confirmation/target/s04`:target_source在正式源冻结中为自身key/hash,在草稿中为所指正式源;target恰为`{instance_family,type_id,revision,system_revision,content_hash}`;s04恰为`{schema_id,base_version,extension_version,effective_schema_hash,projection_version}`,基础版本正整数,扩展为正整数或null。来源字段、关联指针、作品/目标及模式必须与原快照和不可变route一致,不信传入kind/state。正式源的旧字段与显式target_schemas映射结果在不可变route留存,S04真实校验后再比目标哈希,不能用传入目标JSON跳过核验。
所有合取核验都必须通过:
1. 台账/S01/B02数据库工厂相同,production用途/认证作者及隔离目标身份通过。link无同库世界读取能力即拒绝。
2. S01活读冻结的既存command_id,receipt_id/command_id一致,action=adopt、author_review_id非空、target_ref=world:+新ID;basis有候选ID/正版本/哈希、目标、object变更项、原数据版本、有效结构/投影/来源摘要哈希。拒绝、暂缓、manual_save、复合正文根回执不能替代独立世界确认。
3. results唯一匹配object_id,revision/system_revision为正int,content_hash完整;revision等于声明版本且为basis数据版本+1,不能用proposal_id/candidate_id冒充。
4. 公共世界历史核同作品/族/型、确切revision/system_revision/content_hash;当前指针允许更晚,不取当前内容或当前提案decision代旧版。
5. S04按固定schema_id/base_version/extension_version读取有效结构;有效结构哈希等于S01 basis,旧正式归一内容经公开校验值得到规范值,其公开固定哈希等于真实历史content_hash。不用UI投影后的content算全量哈希,不用当前策略投影版本替换S01的历史投影版本。
台账工程command_id仍按作者/source_key确定;link不向S01提交该键。create读原迁移命令回执,link读既存确认命令,receipt原样保其真实command_id/receipt_id,不改成迁移键。link targets恰为`[{id,revision,kind:world_object,owner:B02,subject_ref,scope}]`,kind=proposal/candidate拒绝。
link保存终态在同一台账事务中按source_key排序锁本条与正式源(根为自身),重验原值/冻结/父状态;通过S01 `读取回执于`、B02 `读取实体轨迹于`在同一受控连接中核不可变历史,接口不提交或回滚事务。根正式源允许当前reserved→mapped,依赖草稿必须见正式源mapped。期间没有网络/模型调用;不裸查他域私表。只读核对/点名重放/切换同样使用冻结模式、真实回执、世界历史和父源留存,不能省略依赖。
缺正式源报legacy_target_source_missing,源/目标指向矛盾报legacy_link_conflict,无真实确认或错误动作/回执报existing_confirmation_invalid,历史版/结构/内容不符报existing_target_mismatch;模式/冻结坏结构报target_request_invalid。空缺目标结构/错型沿target_schema_missing/target_type_mismatch。失败零S01/领域/索引写,原记录保台账。恢复只重读原确认/历史并补台账,不再次创建或批准。多个旧记录可关联同一确认与版本,源条数不等对象数。
目标后续编辑/当前来源撤回不倒改历史关联,也不复活当前消费;新传源内容改变仍触发drift,旧mapped不被重写。初次已撤回/删除的旧源仍历史保留。source_hash与模式证明只针对冻结资料,当前资格由原B02/B09规则负责。报告分别标明新候选创建与既存确认关联,并提供旧草稿/旧目标身份、旧声明及明确新版本/真实回执;不输出already_confirmed暗示本次执行确认。
### 旧来源追加的只读回放
`核对目标 --来源回放 /private/回放请求.json`可对PG中已留存且已核关联的旧正式实体和旧草稿作追加试算。请求恰为`{base:{source_key,source_hash},steps:[{source_key,source_hash},...]}`,步骤1—500项,文件仍受16MiB限制。这是查询参数,不改变迁移映射或任何库内记录;顺序由调用方明确选择,不按ID大小、回执时间或当前世界版本推断旧时序。
base必须为已mapped的正式旧实体根;每一步为同根、同旧作品/命名空间、同新目标的已confirmed实体草稿,并活核相同映射哈希、原快照哈希、真实S01确认和世界历史。不能凭请求中的source_key/hash假定记录存在或资格。缺源、错hash/根/作用域/状态、畸形lineage_payload或非对象来源引用均报legacy_lineage_invalid或原证据错误,整体核对不通过,原值不变。
从base.original.lineage_payload复制初始链:SQL NULL表示没有旧链,试算从空对象开始而不改原record;其他值必须是对象,sourceRefs缺失时为空,存在时必须是对象数组,不把畸形值清空。每一步从原草稿payload的source/来源/出处对象读取完整旧引用(多键须一致),evidence/证据若给出须一致、为str或null且不与引用内证据冲突。未知旧引用键原样留在回放结果,不解释为权限或当前对象。非空引用用稳定JSON相等判断是否已出现,只追加未见引用;不删除原列表元素。lastDraftId取原record.id(若未给则取来源ID字符串),lastSourceType取原行明确source_type;不调用旧确认实现,不运行模型。
结果提供初始值、逐步结果及最终值,固定声明`order_basis=caller_selected_order`、`historical_order_verified=false`、`canonical_written=false`。这恢复“给定旧链+指定引用的追加/去重”可观察算法,不认证选择顺序是真实旧历史、不重写B02当前来源。所有输入权威在PG留存原记录;回放结果是可重算报告,不建第二张来源权威表。缺少回放请求时不执行试算;请求失败也不影响已完成的迁移终态,但核对结果为失败。
### 工程命令
`检查实例`是具名只读元数据入口:先用明确批准的端点记录及管理凭据引用连接,在只读事务内查询PG系统标识、数据目录、版本、当前数据库/角色及pg_database的库名、OID、owner和模板标记;不读业务表、不提供任意SQL参数、不创建数据库或角色。输出为私有JSON,标准输出不打印DSN或秘密。检查结果仅为实测证据,必须经操作者核准后将其instance对象保存为允许实例记录,工具不会自动授权。
```bash
.venv/bin/python 数据库/旧库迁移/入口.py 检查实例 \
--端点记录 /private/端点.json --管理引用 /private/admin.txt --输出 /private/实例检查.json
```
远程端点文件恰为`{"endpoint_type":"tcp","host":"100.64.0.8","port":5433}`;本地可用`{"endpoint_type":"unix","host":"/明确/socket目录","port":5432}`。检查返回的数据库清单用于确认源库与已有业务库身份,不授予对清单中任意库的写入或删除权限。
初始化目标接收核准后的完整允许实例记录和分离的管理/维护/应用凭据引用,只创建随机新库(muse_maint/muse_app必须已由受控角色流程准备,本命令不创建或修改实例角色):
```bash
uv run python 数据库/旧库迁移/入口.py 初始化目标 \
--允许实例 /private/允许实例.json --管理引用 /private/admin.txt \
--维护模板 /private/maint.txt --应用模板 /private/app.txt --输出目录 /private/新目标
```
新目标目录保存私有应用/维护连接和无凭据的目标回执;缺最终回执不可使用。连接引用在创建库前落盘,用于异常终止后定位本次随机库;初始化失败只在实例指纹、本次随机target_id对应库名及创建后捕获的OID一致时清理本次新库和文件,不处理其他目标。身份缺失或变化时拒绝删除并保留定位文件。此自动清理只覆盖同一次初始化调用;初始化完成后的错误导入、进程被杀或清理连接失败不提供独立删除入口,不能凭库名前缀或连接文件删除既有库,需另经核对实例/OID/target_id与本次创建证据的受控恢复合同。
`导入目标`、`核对目标`与`切换检查`使用`--快照/--映射/--配置/--允许实例/--管理引用/--目标回执/--输出`;配置是已有应用TOML,本地作者从其HTTP作者身份取得,不采用映射文件中的作者作为认证。切换检查额外要求`--当前快照`,比较源增量;它不执行切换、不声明整包验收或授予生产权限。报告私有原子创建,不覆盖输入或不同内容,标准输出不回显正文/凭据。
同批同一source_key有不同source_hash时,目标命令整批拒绝、零台账和领域写入;先用纯分流查看保全的冲突记录,不选择其中一份抢占。已隔离行重放的报告从终态台账生成,不因本轮未重复触发错误而清空原因。
## 文件保全与正文候选合同
### 输入、界限与私有输出
```bash
uv run python 数据库/旧库迁移/入口.py 读取文件 \
--源根 /private/显式旧源 --清单 /private/文件清单.json \
--数据集 合成文件集 --输出目录 /private/新保全
uv run python 数据库/旧库迁移/入口.py 核对文件 \
--文件回执 /private/新保全/文件回执.json --输出 /private/文件核对.json
```
文件输入的导入目标、核对目标和切换检查另外显式传`--文件回执`;不从快照路径自动猜保全根。PG/SQLite输入不要求该参数。保全目录的绝对位置不进入源身份或mapping_hash,复制到另一合格私有目录后仍须实际核对原快照/回执/字节。
`读取文件`接收源根、数据集和清单数组;每项恰有`relpath/revision/sha256`(相对POSIX路径、非空显式版本、小写64位十六进制字节SHA)。单文件原始字节不超过8MiB,清单1—500项,完整快照数组的稳定JSON(含base64)不超过16MiB;任一超限失败并要求显式分批,不截断。
源根和输出根用真实路径作路径分量比较,禁止相等或互含。清单拒绝绝对路径、反斜线、空路径、空白路径段、`.`/`..`和重复路径;不按归一结果放行含`..`的输入。根只解析一次,内部逐级用固定目录描述符和O_NOFOLLOW/O_DIRECTORY打开,最终以O_NOFOLLOW/O_NONBLOCK打开后fstat确认普通文件,避免符号链接替换或FIFO阻塞。内容读取同时受大小和预期SHA保护;映射不扩大源目录读取授权。
新输出根0700,副本与JSON在同目录0600临时文件中写完、fsync,再以不覆盖目标的硬链接原子公开;内部路径同样拒绝符号链接。目录/文件现有权限不符合私有约束时拒绝,不替操作者修改既有目录。副本位于`原始文件/<relpath>`;快照为`快照.json`,`文件回执.json`最后落盘并fsync目录。失败只清理当前操作创建的临时文件,不删除原文件或既有目录;缺最终回执的中断目录拒绝重用。已完整目录的重放只读核对清单、快照、回执和副本,同内容返回原结果,不同内容报output_conflict。
文件源身份为`system=file/table=legacy_file/id=relpath/revision=显式版本`,database由显式数据集和固定files范围生成,不含绝对根路径。record恰为`{id,revision,relpath,size,sha256,content_base64}`;id与relpath一致,id/revision与source一致。base64严格解码后大小/SHA必须一致;原字节完整保存,不注入作品、作者或用途。
文件回执恰有`version=1/snapshot_hash/entries`。snapshot_hash绑定完整快照数组;entries每项恰为`{source_key,source_hash,relpath,sha256,size}`,集合和顺序与快照一致。副本位置由`原始文件/relpath`推导,不接收任意绝对路径。文件核对活读快照、回执和各副本;缺失、篡改、链接、多义或超限均为问题,不回显原文/base64。
### 显式路由与无损正文
只有`source.system=file`使用file_routes,不复用知识routes猜用途。file_routes按source_key唯一命中并核source_hash;缺失、多义、漂移失败。archive路由恰含`source_key/source_hash/route=archive`,只历史保留原字节,不要求文本格式或作品映射。body_candidate路由另外须有`format/legacy_work_id/target`,format为text_utf8或document_v1,target恰含`chapter_id/branch_id/base_revision`(两个非空标识和非负整数);legacy_work_id在同文件命名空间的works中唯一指向author用途及当前认证作者。未知字段拒绝。只有text_utf8可选paragraphs分段表。
text_utf8严格UTF8解码,BOM作为码点保留,不用utf-8-sig,不strip/NFC/NFKC或折叠空白。未给分段表时使用单段,显式换行节点保存每个LF/CRLF/CR;空文件是一个空段且不附加换行。验收等式为`可见文本(草稿)==解码原文`逐码点相等。
paragraphs每项恰含`id/start/end`,可选scene_id;ID非空、同表唯一,范围为解码后Python str码点下标的左闭右开区间。首段从0起、末段到len(原文),相邻段正文范围之间恰为原文的单个LF;段正文范围与这些分隔符共同完整覆盖原文,不重叠、不丢字。分隔符由B05段落间LF表达而不再写入段内;禁止在CRLF的两个码点之间切边界。无法满足等式的划分拒绝,不补字、不吞CR。目标段ID按来源对象键(不含revision/内容哈希)+旧段ID确定,默认单段旧ID为`#p0`。scene_id仅进入来源对照,不进入正文额外字段或创建B01场景。
document_v1读取严格JSON并通过公开正文草稿DTO的extra=forbid、format_version=1、段ID非空唯一校验;段ID原样保留,不前缀化。这里原字节是JSON而不是可见正文:原JSON字节SHA及完整base64单独保留,可见文本哈希/结构哈希针对解析后的正文计算,不把JSON语法串与可见文本作相等比较。节点合并遵守B05规范,不替代原字节留痕。未知格式、字段、节点或坏编码保原隔离,不回显输入。
### B05冻结、回执与双面对账
B05冻结请求使用既有外壳`owner/scope/subject_ref/payload`:owner=B05,scope为真实work_id,subject_ref为真实chapter_id,payload包含`source_key/source_hash/mapping_hash/file_route/kind=candidate/chapter_id/branch_id/base_revision/base_document_hash/draft`;draft恰含`document/document_hash/visible_text_hash/paragraph_map`。paragraph_map记录旧段/场景ID、源码点范围和目标段ID,document_v1用原段ID和其规范可见位置。冻结时公开读取章节及当前正文,要求作者、映射work和章节实际work一致,当前revision必须等于路由明确给出的base_revision;不能悄悄换成更新基线。base_document_hash取真实公开读取值,提交只使用冻结值。
提交只调B05创建人工候选(首建候选版本0),不调人工正文保存/确认/模型候选。台账读取不可变冻结owner来选择回执键,B02/B04仍为proposal_id,B05为candidate_id;拒绝未知owner、错kind、错scope或错版本。B05要求S01原回执target_ref与唯一candidate_id结果相等;再公开读取确切候选版本,核chapter/branch/base_revision、origin=author,以及公开正文函数算得的document_hash/visible_text_hash与冻结draft一致。candidate_hash不是document_hash:它必须在真实S01结果和确切B05候选间一致,不复制B05私有哈希算法或假称提交前已经取得它;对应基线正文原版本的公开哈希还须等于冻结base_document_hash。
新候选仍用author+source_key固定命令,reserved→S01实际候选→mapped分短事务。S01提交后台账未完成时取原命令回执和确切候选恢复;不以当前候选编辑版覆盖原版本,不新建命令或确认。原始文件行与映射留在PG台账,B05的author来源仅表示作者提交待比较输入,不是模型使用证明。
文件输入导入前须通过文件保全核对,缺回执或副本未闭合时零台账/业务写入。核对目标/切换检查遇file源时需要显式文件回执路径。file_checks活读整个保全集合及所核file源的匹配副本;pg_checks核源行、台账和真实目标。两面各有passed/issues,任一缺口都使data_checks_passed=False;历史archive也必须通过文件面,不能只看PG保留行数。无file源时文件面标为不适用且不阻旧PG/SQLite用例。production_switch_authorized/package_acceptance_claimed恒False;常规B05读取、采纳与模型使用不依赖库外保全副本。
T4复用V0025通用表,无需新增DDL;若发现确需结构改变,必须先解释并新增单调迁移,不改已应用V0025。本合同只定义数据语义,不声明实现已通过。
## 歧义与对账
隔离记录保存 source_key、rule_id、reason_code、原 payload、冲突取值、关联源键和可选择的处理。类型双键冲突、未知用途、缺失端点、正式目标缺失、权限冲突分别使用不同原因,不合并成“导入失败”。隔离内容不进入生产查询。
每条旧输入都必须有“已映射到一个或多个明确关联目标 / 保留历史 / 隔离待裁决”之一;多目标只允许拆分已明确定义的对象与来源关系。不得出现输入无归宿、两个正式 owner、静默丢弃字段或自动补批准。重复导入按 source_key、revision 与源哈希幂等;相同记录身份不同内容报告漂移。同一旧对象跨版本出现不同目标、业务 owner 或目标作用域时,整批该对象的记录进入 `identity_conflict` 隔离,并在 `conflicts` 保留冲突目标;不等到导入顺序抢占后再发现。相同目标的多个版本不因此隔离。
知识记录分流.py 负责纯判定及别名冲突;转换业务对象.py 调用各所属模块的迁移入口;建立映射.py 保存旧新身份;核对结果.py 对账状态、来源、动态字段和引用。PG承接由 `PG作品映射.py` 固定清单与原生父子身份,`转换PG作品.py`、`转换PG正文.py` 负责转换,`PG台账接线.py` 对接同一迁移台账;不绕过B01/B03/B05 owner。历史目标文件清单与逐文件设计冻结为当时目标,不再逐项手工同步当前工具;现行导航以实际源码与派生目录为准。测试身份以[现行用例清单](../../../../tests/用例清单.json)登记,登记不表示通过。
验收至少包括 K01 中文公共范式、K02 英文作品卡、K03 同模具参考实体、K04 entity 形状的关系、K05 关系两端缺失、K06 已确认重复导入、双键冲突、work_id=0 非范式、跨书归并实例、软删不复活、未知字段隔离和 PG/SQLite 同号不同来源。纯转换和隔离 PG 导入分别验证,不能只检查导入行数。
源码依据:[公共范式写入](../../../../src/muse/资料研究/拆书分析.py)、[作品与关系卡写入](../../../../src/muse/资料研究/分章切窗.py)、[知识确认](../../../../src/muse/故事世界/事实提案.py)。本合同基于文件证据,实际库内取值仍须在实施迁移时逐项对账。
## PG作品、章与block候选接缝
`pg_author_id` 必须逐字等于应用配置HTTP作者身份;它是映射绑定,不是认证来源。`pg_works` 是PG内容专用显式输入清单,不使用file_routes,不修改原record或source。每组为
`{work:{source_key,source_hash},use:author|reference,chapters:[{chapter:{source_key,source_hash},blocks:[{source_key,source_hash}],block_separator:"\n"}]}`。
章按原order_no严格递增,块也按原order_no严格递增;源键不得重复。清单声明本次作品完整目录与各章完整block集合,导出范围完整性由源回执对账负责,不能把未提供的块推断为不存在。无块章的blocks为空;空content_text仍是一个真实块。多块之间的LF是调用方显式选择的拼接参数,单块不添加分隔符。不得按tenant推断用途。
原DDL的作品id为全表主键,无租户复合主键或外键。源owner_user_id=1只核对已确认的旧单作者范围,新作者必须来自应用身份。作者作品ID与章ID按原对象键、B01种类及应用作者确定,不复制另一namespace的同号作品。父子关系必须同时绑定两端原source_key/hash,核原work_id/chapter_id和同数据集/schema;跨namespace边保留原tenant,不重写来源。目录/正文之外的跨namespace知识关联不由内容清单隐式授权。
作者作品经B01公开work_core档案保存,名称逐字取原title;其余原列(状态、owner、tenant、概要、规划快照等)全部留在迁移台账original,不声称成为当前动态档案字段。章节经B01公开追加目录,按原顺序保存;无需直写owner私表或新增作者身份。B01公开`读取档案版本依据(身份,work_id,版本)`先核当前作者归属,仅返回原`work_id/revision/schema_binding/content_hash`,不返回历史原字段而绕过字段投影;版本须为正整数,不存在报WORK_NOT_FOUND。目录复用`读取节点目录(...,版本=原目录版本)`。两者精确核原保存版本,不以当前版本替代。作品/目录是必要依赖创建,不是正文确认。
content_doc为NULL时要求content_text是字符串,逐码点保留空字符串、首尾空白、BOM、LF/CRLF/CR。每个块作为独立源段,段内换行用B05显式换行节点保存;不strip、分词或改写。非空文档仅接受已有document_v1严格结构,保源段ID与目标段ID对照;未知形状明确拒绝,不能丢弃content_doc只取content_text。若同时有两种表示,必须逐码点一致。原source_key/hash、block order、原段/场景、源范围与目标段、章可见文本哈希和结构哈希保留在冻结请求;原行完整留存。
同章所有块合成一个B05人工候选,由首块原source_key确定共享命令;每个块分别占用台账、冻结自身来源与完整块组、保存同一真实候选回执和精确版本。共享引用必须核对根原记录、mapping_hash及根冻结操作,不能凭一个聚合根mapped替代逐块落账。请求先冻结再执行;S01已提交但台账未完成时只读原命令恢复,不自动确认。正文基线固定为main/0,新候选不覆盖既有正式正文;缺源分片时保留reserved,目录或基线改变时明确失败。
reference不进入B01。复用B03公开来源导入保存按清单拼接的原文,origin固定绑定作者及原作品对象键;authorized_uses为空,不补旧授权、不授检索/模型消费。章间LF也在该原文归档合同中明确,逐章/块位置及空章保留为来源对照,不把聚合文本当原表快照。所有成员各自关联同一B03原版本并公开读回正文哈希及导入者。完整原文/逐章块对照仅冻结在作品根,成员冻结`payload={member_of:{source_key,source_hash}}`及根/自身两个依赖,避免每个成员重复保存整书。核对须核自身原行、根来源与成员集合、映射和真实回执;同一次导入/核对可复用已经公开精确读回的不可变根结果,不跨命令缓存。全书原文为空时现有B03拒绝空来源,记录具体缺口,不塞作者作品或伪造非空文本。B03回执是owner来源导入结果,不伪装S01确认;幂等重放保原首次回执。
旧作品/章状态以及旧block作为正式正文的来源事实始终在original保留。此接缝只交付未决正文候选/无消费授权参考来源,不恢复旧Canonical、旧确认或新S01 adopt。旧正式状态恢复仍缺独立owner历史恢复合同:旧正文版本、旧决策与来源归因的历史对应及恢复权限;禁止迁移器调用adopt或伪造作者确认补齐。
### PG分片与冻结台账
沿用读取/导入命令每个快照文件16MiB上限;总映射在开始前固定,后续批次不得改mapping_hash。
作者作品可先传作品与完整章元数据,再传各章块;无块章只建目录,空字符串块照常产生空候选。
参考作品可先传作品/章、再逐个正文分片:资料原文根缺成员时不导入B03,相关行保reserved;后续批次从台账公开迁移记录读取已有原源,加上当前输入,依固定清单推动先前reserved父源和成员。无需每次重新传送整书正文,也不通过改映射跳过漂移保护。
分流身份只由固定清单决定,父子归属、序号、原表列和正文形状在冻结前严格核对;因此缺分片与未知/冲突形状分别是reserved等待与quarantined隔离,不因分片到齐更改已占用路由。父源已隔离的共享成员也隔离,不假称目标存在。
完成某一分片只报告该输入集合的状态;全作品验收必须对全部源分片逐条运行核对,确保没有残留reserved。依赖原行从台账读取,不访问旧PG或库外正文副本。B03完整源的聚合发生在受控应用进程内,输入文件上限不放宽。
分片继续判定取导入报告`fragment_wait`,不能仅依据CLI退出2或台账state=reserved。`can_continue=true`只在全部受影响reserved均未冻结请求、按固定清单实缺原源、已到源哈希吻合,且受影响集合无quarantined或缺台账时成立;此时`reason_code=pg_dependency_missing`、`classified_pending_count=pending_record_count>0`、`missing_source_count>0`。`affected_states`覆盖本轮处理的既有依赖与输入;其他情况code=not_fragment_wait、can_continue=false。台账reserved的reason_code不改成终态原因,报告是基于本轮已提供及库内已有原源的机械诊断。异常中断、已冻结但未完成、哈希漂移或任何隔离都不允许按分片等待继续。报告只含计数,不嵌入正文、冻结请求或重复展开整书成员。
B03导入请求只要求非空content,没有字符串长度上限;V0007来源版本content为text,V0025迁移根frozen_request为jsonb,均未另设16MiB长度约束。16MiB限制仍只施加于CLI所读的每个快照/映射文件;总映射只含身份/哈希,需事先验证自身不超限。聚合的B03请求、根冻结和重放都在应用进程及PG台账内流转,不要求写成CLI输入文件。根包含原文与结构对照,进程内存和驱动序列化可能为文本大小的多倍;此实现不是流式大文件导入,真实DB写入、读取和内存峰值须按目标规模另行验收,不由字段无业务长度限制推断无限容量。不得截断原文或自动提高CLI上限。
## 非空范围与现行承接边界
`导入目标`、`核对目标`及对应服务在创建目标连接前检查非空快照与完整来源身份。`切换检查`同时检查基线和当前两份范围;双空、单空均以 `snapshot_empty` 拒绝,无身份记录拒绝为 `snapshot_invalid`,CLI退出1且不生成成功报告。入口先检查两份快照,再读映射、配置并装配应用。记录的来源身份和哈希证明的范围仅为本次明确输入集合,不证明源库所有表已经扫描;合法空源须另有表覆盖与扫描凭据合同,现行不接受空数组作为该凭据。
切换检查仅组合源新增、删除、变更与目标逐项对账,没有执行生产切换、生产回退或判定回退可行性的入口。`production_switch_authorized` 与 `package_acceptance_claimed` 始终为false;没有增量和本次数据对账通过不授予上线权限。
冻结旧DDL登记66个表名,分流器 `已登记表` 明确处理26个:其中包括历史保留、延期隔离、需要映射与身份授权的分支,26不等于26张表均能成功导入。差集40张在分流前统一 `unknown_table` 隔离;旧status=deleted或伪造其他生命周期信息也不能让未承接表转为成功。以下逐表登记当前差集,不为补齐计数增加空转换。
| 冻结旧表 | 当前处置 |
| --- | --- |
| `example_agent_event` | `unknown_table` 隔离 |
| `example_agent_role` | `unknown_table` 隔离 |
| `example_ai_flavor_revalidation` | `unknown_table` 隔离 |
| `example_ai_flavor_revalidation_batch` | `unknown_table` 隔离 |
| `example_clean_log` | `unknown_table` 隔离 |
| `example_context_freeze` | `unknown_table` 隔离 |
| `example_fact_delta` | `unknown_table` 隔离 |
| `example_fact_ledger` | `unknown_table` 隔离 |
| `example_llm_quota` | `unknown_table` 隔离 |
| `example_parse_outline` | `unknown_table` 隔离 |
| `example_parse_scaffold` | `unknown_table` 隔离 |
| `example_parse_task` | `unknown_table` 隔离 |
| `example_planning_section` | `unknown_table` 隔离 |
| `example_projection_run` | `unknown_table` 隔离 |
| `example_raw_content` | `unknown_table` 隔离 |
| `example_raw_lease` | `unknown_table` 隔离 |
| `example_reference_authorization_snapshot` | `unknown_table` 隔离 |
| `example_reference_work` | `unknown_table` 隔离 |
| `example_skill` | `unknown_table` 隔离 |
| `example_upgrade_alias` | `unknown_table` 隔离 |
| `example_upgrade_audit` | `unknown_table` 隔离 |
| `example_upgrade_card_state` | `unknown_table` 隔离 |
| `example_upgrade_presence` | `unknown_table` 隔离 |
| `example_upgrade_window` | `unknown_table` 隔离 |
| `example_voice_baseline` | `unknown_table` 隔离 |
| `muse_content_block_source_attribution` | `unknown_table` 隔离 |
| `muse_content_command_log` | `unknown_table` 隔离 |
| `muse_content_export_task` | `unknown_table` 隔离 |
| `muse_content_import_task` | `unknown_table` 隔离 |
| `muse_knowledge_base` | `unknown_table` 隔离 |
| `muse_knowledge_binding` | `unknown_table` 隔离 |
| `muse_knowledge_document` | `unknown_table` 隔离 |
| `muse_knowledge_document_version` | `unknown_table` 隔离 |
| `muse_meta_field` | `unknown_table` 隔离 |
| `muse_meta_function_chain` | `unknown_table` 隔离 |
| `muse_meta_protection_node` | `unknown_table` 隔离 |
| `muse_meta_schema` | `unknown_table` 隔离 |
| `muse_meta_schema_version` | `unknown_table` 隔离 |
| `muse_meta_visibility_policy` | `unknown_table` 隔离 |
| `schema_migrations` | `unknown_table` 隔离 |
## 历史迁移编号与执行合同
2026-09-17优化实施基线含45个SQL,最高V0055;缺号为V0008、V0010、V0011、V0012、V0013、V0014、V0015、V0017、V0018、V0019。历史文件设计曾列出 `V0013__上下文与检索索引.sql` 与 `V0015__运行配置版本.sql`,但两者不存在于基线,不能把目标列举视为已经落地。各空号的历史取舍原因尚无可核依据,保留待核,不补空SQL、不重编号、不推断丢失迁移。
迁移执行器 `src/muse/基础设施/数据库/迁移.py` 以实际资源文件、唯一版本号、内容校验和及 `muse_migration` 账本为准;不要求编号连续。必须经维护入口获取会话锁,并将每版SQL与登记放入同一事务,失败回滚;不直接逐文件裸跑。已有45条SQL及冻结旧DDL连注释也不回改,后续扩展只新增前向迁移。原SQL的DROP约束、权限授予与初始枚举按历史字节保留;后续枚举/空值等变化由后续迁移解释,发现真实权限或兼容失败另立新迁移,不通过重写历史“修整”校验和。