# 旧知识记录分流 **现行状态:已退役。** `数据库/旧库迁移/` 工具链与对应测试已删除,不再提供分流/导入命令。下文只保留当时合同文本,供历史对照;新工作以现行 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,再以不覆盖目标的硬链接原子公开;内部路径同样拒绝符号链接。目录/文件现有权限不符合私有约束时拒绝,不替操作者修改既有目录。副本位于`原始文件/`;快照为`快照.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约束、权限授予与初始枚举按历史字节保留;后续枚举/空值等变化由后续迁移解释,发现真实权限或兼容失败另立新迁移,不通过重写历史“修整”校验和。