zizi 9e6f1c4481 R2 改造交付:新版模块化单体全量成果
- src/muse 新版全模块(装配/共享/上下文/任务运行/作品规划/故事世界/正文写作/审校修订/知识方法/作者经验/效果评测/交付连载/资料研究/正式变更/元数据/接入/基础设施/编排)+ 测试树(单元/契约/集成/架构/迁移/端到端/夹具)
- 129 项功能全部实现与自动验证(功能覆盖.json/矩阵),含 W31 补齐的规则与代价/节奏安排/伏笔与承诺
- 旧实现按处置清单退出(702 条中 324 删,保护合同与未迁移条目留存有据);web/app.py 旧工作台退役,新工作台为唯一写入口
- 数据库/旧库迁移:真实旧库内容批次迁移链(端点守卫/PG作品正文映射/质量资产缺省投影)
- 运行手册 docs/运行手册.md;W30 本机服务阶段一已运行(infra PG 为正式内容权威)
- R2 执行证据与私有运行材料在 .agents.local/改造/R2-20260909/(不入库)
2026-09-15 12:47:42 +08:00

422 lines
17 KiB
Python
Raw 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.

"""选择并注入数据库、宿主、模块和流程实现。
合同依据:文件设计/后端-装配与接入.md。
- 环境实现的选择集中在此唯一装配位置;更换宿主或连接实现不改业务规则。
- 只配置和注入模块、宿主、连接、资源与流程;不承载创作规则。
- 数据库工厂随配置与用途注入,取得连接时才访问外部;模型与角色循环读取任务已绑定配置。
"""
from __future__ import annotations
from dataclasses import dataclass, field
from pathlib import Path
from typing import Any, Protocol
import psycopg
from muse.上下文.接口 import 上下文服务
from muse.交付连载.接口 import 交付服务, 登记交付参与者
from muse.任务运行.接口 import (
任务服务,
原文服务,
只读工具集,
执行上下文,
未知计价,
模型执行器,
登记任务参与者,
角色策略目录,
证据服务,
调用计价,
配置版本管理,
预算管理,
领取凭证,
)
from muse.作品规划.接口 import 作品服务, 创作进度服务, 探索服务, 登记作品参与者, 规划服务
from muse.作者经验.接口 import 作者经验服务, 登记经验参与者
from muse.共享.时间 import 时钟, 真实时钟
from muse.共享.错误 import Muse错误, 配置错误
from muse.基础设施.受控文件 import 受控文件
from muse.基础设施.宿主.Pi import Pi宿主
from muse.基础设施.宿主.直接调用 import 直接宿主, 直接角色循环
from muse.基础设施.数据库.连接 import 数据库工厂
from muse.基础设施.模型.HTTP传输 import HTTP传输
from muse.审校修订.接口 import (
审校服务,
登记修订参与者,
登记声音参与者,
登记案例参与者,
登记规则参与者,
)
from muse.接入.只读工具 import 领取只读工具
from muse.故事世界.接口 import 故事服务, 登记故事参与者, 解析本书规划引用
from muse.效果评测.接口 import 评测服务
from muse.正式变更.接口 import 参与者目录, 正式变更服务
from muse.正文写作.接口 import 正文服务, 登记正文参与者
from muse.知识方法.接口 import 登记方法参与者, 知识方法服务
from muse.编排.接口 import 流程登记
from muse.资料研究.接口 import 登记分析参与者, 资料服务
from muse.配置 import 应用配置
class 数据库实现(Protocol):
"""取得按装配用途绑定的数据库连接。"""
def 连接(self, *, 只读: bool = False, autocommit: bool = False) -> psycopg.Connection: ...
def 检查连接(self) -> None: ...
class 装配未完成(Muse错误):
"""所需实现尚未注入;启动如实失败而不是静默降级。"""
错误码 = "MUSE_ASSEMBLY_INCOMPLETE"
@dataclass(slots=True)
class 应用装配:
"""已注入的实现集合;业务模块只依赖这里的成员。"""
配置: 应用配置
时钟: 时钟
数据库: 数据库实现 | None = None
任务运行: 任务服务 | None = None
原文: 原文服务 | None = None
默认计价: 调用计价 | None = None
作品: 作品服务 | None = None
正文: 正文服务 | None = None
作品进度: 创作进度服务 | None = None
故事世界: 故事服务 | None = None
规划: 规划服务 | None = None
上下文: 上下文服务 | None = None
知识方法: 知识方法服务 | None = None
流程登记: 流程登记 | None = None
资料: 资料服务 = field(default_factory=资料服务)
审校: 审校服务 | None = None
作者经验: 作者经验服务 | None = None
交付: 交付服务 | None = None
def 要求交付(self) -> 交付服务:
if self.交付 is None:
raise 装配未完成("交付服务未注入")
return self.交付
def 要求作者经验(self) -> 作者经验服务:
if self.作者经验 is None:
raise 装配未完成("作者经验服务未注入")
return self.作者经验
def 要求评测(self) -> 评测服务:
return 评测服务(数据库工厂(self.配置.数据库, self.配置.运行用途), self.任务运行)
def 要求审校(self) -> 审校服务:
if self.审校 is None:
raise 装配未完成("审校服务未注入")
return self.审校
def 要求上下文(self) -> 上下文服务:
if self.上下文 is None:
raise 装配未完成("上下文服务未注入")
return self.上下文
def 要求只读工具(self, 领取: 领取凭证) -> 只读工具集:
"""工具范围完全取自已保存任务;接入层不重新解释作者、作品或截止。"""
if self.任务运行 is None:
raise 装配未完成("任务运行服务未注入")
return 领取只读工具(self.要求上下文(), self.任务运行, 领取)
def 要求规划(self) -> 规划服务:
if self.规划 is None:
raise 装配未完成("规划服务未注入")
return self.规划
def 要求知识方法(self) -> 知识方法服务:
if self.知识方法 is None:
raise 装配未完成("知识方法服务未注入")
return self.知识方法
def 要求探索(self) -> 探索服务:
if self.配置.探索草稿 is None:
raise 配置错误("私人探索需要在作者配置中明确探索草稿目录")
return 探索服务(Path(self.配置.探索草稿))
def 要求故事世界(self) -> 故事服务:
if self.故事世界 is None:
raise 装配未完成("故事世界服务未注入")
return self.故事世界
def 要求作品进度(self) -> 创作进度服务:
if self.作品进度 is None:
raise 装配未完成("创作进度查询未注入")
return self.作品进度
def 要求作品(self) -> 作品服务:
if self.作品 is None:
raise 装配未完成("作品服务未注入")
return self.作品
def 要求正文(self) -> 正文服务:
if self.正文 is None:
raise 装配未完成("正文服务未注入")
return self.正文
def 要求资料(self) -> 资料服务:
"""注入资料公开用例;基础资料连接由调用方事务提供。"""
return self.资料
def 要求证据(self) -> 证据服务:
return 证据服务(数据库工厂(self.配置.数据库, self.配置.运行用途))
def 要求原文(self) -> 原文服务:
if self.原文 is None:
self.原文 = 原文服务(
数据库工厂(self.配置.数据库, self.配置.运行用途),
受控文件(Path(self.配置.原文暂存)) if self.配置.原文暂存 else None,
self.时钟,
)
return self.原文
def 要求数据库(self) -> 数据库实现:
if self.数据库 is None:
raise 装配未完成(
"数据库实现未注入(W03 提供);当前构建拒绝启动业务入口",
上下文={"缺少": "数据库"},
)
return self.数据库
def 要求模型执行器(self, 上下文: 执行上下文, 计价: 调用计价 | None) -> 模型执行器:
数据库 = 数据库工厂(self.配置.数据库, self.配置.运行用途)
版本 = 配置版本管理(数据库).读取任务绑定(上下文.领取.任务ID)
内容 = 版本.内容
if 内容.资源发布身份 != self.配置.资源发布身份:
raise 配置错误("任务运行配置与当前安装资源不一致")
if self.任务运行 is None:
raise 装配未完成("任务运行服务未注入")
当前 = self.任务运行.读取任务(上下文.领取.任务ID)
步骤 = next(s for s in 当前.流程.步骤 if s.步骤ID == 上下文.领取.步骤ID)
策略 = 角色策略目录.从发布包()
角色 = 策略.定义.get("aliases", {}).get(步骤.角色, 步骤.角色)
if 角色 not in 内容.角色配置:
raise 配置错误("任务角色没有对应的固定运行配置")
声明 = 内容.角色配置[角色]
提供方 = next(p for p in 内容.提供方 if p.身份 == 声明["provider"])
凭据 = next(r for r in 内容.凭据 if r.名称 == 提供方.凭据名称)
实际计价 = 计价 or 未知计价(内容.计价版本)
return 模型执行器(
self.任务运行,
预算管理(数据库, 内容.预算策略引用),
self.要求原文(),
self.要求证据(),
策略,
直接宿主(HTTP传输(提供方.地址, 凭据.来源, 凭据.位置, 提供方.协议)),
实际计价,
固定配置=版本,
)
def 要求角色循环(self, 任务ID: str) -> 直接角色循环 | Pi宿主:
版本 = 配置版本管理(数据库工厂(self.配置.数据库, self.配置.运行用途)).读取任务绑定(任务ID)
内容 = 版本.内容
if 内容.宿主 == "pi":
assert 内容.Node路径 is not None and 内容.Pi包目录 is not None
return Pi宿主(Path(内容.Node路径), Path(内容.Pi包目录), 内容.宿主版本)
if 内容.宿主版本 != "1":
raise 配置错误("未支持的直接宿主合同版本")
return 直接角色循环()
def 构建(配置: 应用配置, *, 时钟: 时钟 | None = None, 流程: 流程登记 | None = None) -> 应用装配:
"""注入按用途绑定的数据库工厂;装配与自检不建立连接。"""
数据库 = 数据库工厂(配置.数据库, 配置.运行用途)
目录 = 参与者目录()
登记作品参与者(目录, 探索服务(Path(配置.探索草稿)) if 配置.探索草稿 else None, 解析本书规划引用)
登记正文参与者(目录)
登记交付参与者(目录)
登记故事参与者(目录)
登记方法参与者(目录)
登记分析参与者(目录)
登记声音参与者(目录)
登记修订参与者(目录)
登记规则参与者(目录)
正式 = 正式变更服务(数据库, 目录)
登记案例参与者(目录, 正式.读取回执于)
作品 = 作品服务(数据库, 正式)
正文 = 正文服务(数据库, 正式)
登记 = 流程 or 流程登记()
任务 = 任务服务(数据库, 登记)
登记任务参与者(目录, 任务)
登记经验参与者(目录, 任务)
app = 应用装配(
配置=配置,
时钟=时钟 or 真实时钟(),
数据库=数据库,
任务运行=任务,
流程登记=登记,
作品=作品,
正文=正文,
作品进度=创作进度服务(作品, 正文, 任务),
故事世界=故事服务(数据库, 正式),
规划=规划服务(数据库, 正式, 解析本书规划引用),
上下文=上下文服务(数据库, 任务, 解析本书规划引用),
知识方法=知识方法服务(数据库, 正式),
资料=资料服务(正式),
审校=审校服务(数据库, 正式),
作者经验=作者经验服务(数据库, 正式),
交付=交付服务(数据库, 正式),
)
from muse.编排.定稿交付 import 登记定稿交付
from muse.编排.数据维护 import 登记数据维护
登记定稿交付(app)
登记数据维护(app)
return app
def 构建默认运行(
配置: 应用配置,
*,
时钟: 时钟 | None = None,
计价: 调用计价 | None = None,
分析配置ID: str | None = None,
抽取配置ID: str | None = None,
) -> 应用装配:
"""唯一默认运行入口:构建完整作者处理器,不连库或发布计划。"""
from muse.编排.运行装配 import _登记默认运行
装配 = 构建(配置, 时钟=时钟)
装配.默认计价 = 计价
return _登记默认运行(
装配,
计价=计价,
分析配置ID=分析配置ID,
抽取配置ID=抽取配置ID,
)
def 装配章后处理(
装配: 应用装配,
计价,
模板路径: Path | None = None,
*,
抽取配置ID: str | None = None,
) -> None:
"""登记并发布章后处理流程;抽取配置由部署装配声明,作者配置仍走验证启用链。"""
from muse.编排.接口 import 流程服务
from muse.编排.章后处理 import 登记章后处理
from muse.编排.载入模板 import 载入流程定义
登记 = 装配.流程登记
if 登记 is None or 装配.任务运行 is None:
raise 装配未完成("任务运行与流程登记未注入")
登记章后处理(登记, 装配, 计价, 抽取配置ID=抽取配置ID)
定义 = 载入流程定义(模板路径 or Path("配置/流程模板/章后处理.yaml"))
流程服务(装配.任务运行, 登记).发布(定义)
def 装配研究拆书(
装配: 应用装配, 计价, 模板路径: Path | None = None, *, 分析配置ID: str | None = None
) -> None:
"""登记并发布研究拆书流程;分析配置由部署装配声明,作者配置仍走验证启用链。"""
from muse.编排.接口 import 流程服务
from muse.编排.研究拆书 import 登记研究拆书
from muse.编排.载入模板 import 载入流程定义
登记 = 装配.流程登记
if 登记 is None or 装配.任务运行 is None:
raise 装配未完成("任务运行与流程登记未注入")
登记研究拆书(登记, 装配, 计价, 分析配置ID=分析配置ID)
定义 = 载入流程定义(模板路径 or Path("配置/流程模板/研究拆书.yaml"))
流程服务(装配.任务运行, 登记).发布(定义)
def 装配生成正文(装配: 应用装配, 计价, 模板路径: Path | None = None) -> None:
"""登记并发布生成正文流程;计价由调用方注入,模板默认取仓内可审配置。"""
from muse.编排.接口 import 流程服务
from muse.编排.生成正文 import 登记生成正文
from muse.编排.载入模板 import 载入流程定义
登记 = 装配.流程登记
if 登记 is None or 装配.任务运行 is None:
raise 装配未完成("任务运行与流程登记未注入")
登记生成正文(登记, 装配, 计价)
定义 = 载入流程定义(模板路径 or Path("配置/流程模板/生成正文.yaml"))
流程服务(装配.任务运行, 登记).发布(定义)
def 装配完整审校(装配: 应用装配, 计价, 模板路径: Path | None = None) -> None:
"""登记本书正文完整审校;调用方选择已验证judge配置并另行批准预算。"""
from muse.编排.完整审校 import 登记完整审校
from muse.编排.接口 import 流程服务
from muse.编排.载入模板 import 载入流程定义
登记 = 装配.流程登记
if 登记 is None or 装配.任务运行 is None:
raise 装配未完成("任务运行与流程登记未注入")
登记完整审校(登记, 装配, 计价)
流程服务(装配.任务运行, 登记).发布(
载入流程定义(模板路径 or Path("配置/流程模板/完整审校.yaml"))
)
def 装配审校修订(装配: 应用装配, 计价, 模板路径: Path | None = None) -> None:
from muse.编排.审校修订 import 登记审校修订
from muse.编排.接口 import 流程服务
from muse.编排.载入模板 import 载入流程定义
登记 = 装配.流程登记
if 登记 is None or 装配.任务运行 is None:
raise 装配未完成("修订任务装配缺失")
登记审校修订(登记, 装配, 计价)
流程服务(装配.任务运行, 登记).发布(
载入流程定义(模板路径 or Path("配置/流程模板/审校修订.yaml"))
)
def 装配生成规划(装配: 应用装配, 计价, 模板路径: Path | None = None) -> None:
"""登记并发布受控规划;配置和额度仍由 S02 验证及绑定。"""
from muse.编排.接口 import 流程服务
from muse.编排.生成规划 import 登记生成规划
from muse.编排.载入模板 import 载入流程定义
登记 = 装配.流程登记
if 登记 is None or 装配.任务运行 is None:
raise 装配未完成("任务运行与流程登记未注入")
登记生成规划(登记, 装配, 计价)
流程服务(装配.任务运行, 登记).发布(
载入流程定义(模板路径 or Path("配置/流程模板/生成规划.yaml"))
)
def 自检(装配: 应用装配) -> dict[str, Any]:
"""进程内自检:报告已注入实现与缺口;不连接任何外部服务。"""
return {
"包版本": __import__("muse").__version__,
"资源发布身份": 装配.配置.资源发布身份,
"数据库": "已注入" if 装配.数据库 is not None else "未注入(W03)",
"宿主": "按任务已绑定配置装配",
}
__all__ = [
"应用装配",
"构建",
"构建默认运行",
"自检",
"装配未完成",
"数据库实现",
]
def 装配效果评测(装配: 应用装配, 计价=None) -> None:
"""按评测用途装配固定发布资源;未装配计价时保留未知,不推定免费。"""
from muse.共享.调用身份 import 用途
from muse.效果评测.接口 import 评测用途越权
from muse.编排.执行评测 import 登记评测执行
if 装配.配置.运行用途 is not 用途.评测:
raise 评测用途越权("效果评测流程只允许evaluation配置")
登记评测执行(装配, 计价 if 计价 is not None else 装配.默认计价)