Files
chenxin 7e23d6fa84 M6:缘契、人格与世界——契约版本链、铸魂分灵、河图境界与三界分流
- 缘契域 domains/yuanqi:covenants(当前版)+ covenant_events(不可变历史);提议—问心—铭契—撤回全链;边界变更立即生效;多维关系并存,服务层拒绝 affinity/好感度单一键;浪漫维度成人资格标记位
- 道体铸魂与分灵 domains/jingsheng/soul.py:soul_forgings 确认流(锚点变更 pending→confirmed 应用并签发新魂籍版本,确认前人物锚点不变);分灵创建新人物(继承资料与谱系 lineage 链、不继承原身份,魂籍从 v1 起)
- 河图域 domains/hetu:persistent_worlds 境界 + world_entities/world_relations 境界作用域重建 + 世谱挂接;境界正史视图(scope=persistent_world 归真集合);canonize 后置推进正史计数
- 三界分流:reality→息壤提取(不变);persistent_world→境界实录+正史推进;simulation→只记试演实录;factual_records 增 scope 列——境界/幻境实录与真界本相隔离
- 正影打通:引文 target_type=memory 时被引记忆 superseded → 返回 successor_memory_id 提示,不静默替换
- 前端:人物详情页缘契面板(提议维度选择/铭契/撤回/事件史)+ 世界页重建(境界目录/实体/正史概览)+ covenants/worlds api 库
- 退役:旧 personality/drive/evolution/world 模块、服务、端点、仓储、schema、前端五页与组件样式;迁移 007 退役九张旧表与 characters.current_personality_version_id
- 验收(test_m6_domains 六用例):多维无单一好感度/铭契版本链/事件不可抹除/撤回立即生效/边界即时/铸魂确认流+魂籍版本/分灵谱系/境界正史不进真界(实录 scope 隔离+真界候选=0)/引文正影后继
- 四套件:后端 379、前端 199、BFF 4、神识 5 包全绿(2 个预存环境失败不变);迁移 007 净库+±1 干净
2026-08-27 20:10:11 +08:00

106 lines
5.1 KiB
Python
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.
"""镜生域模型:灵胚、执镜关系、命台、魂籍(data-model.md §1)。
- 灵胚只有预备身份,启镜(activate)才产生正式人物与执镜关系;
- 命台人物粒度唯一(UNIQUE(character_id)),租约到期可被接管,epoch 递增;
- 魂籍版本不可变(UNIQUE(character_id, version)),签名绑定人物与版本。
"""
from datetime import datetime
from sqlalchemy import DateTime, ForeignKey, Integer, String, Text, UniqueConstraint
from sqlalchemy.orm import Mapped, mapped_column
from app.core.ids import new_custodianship_id, new_embryo_id, new_id, new_identity_record_id, new_seat_id
from app.core.time import utc_now
from app.db.base import Base
class EmbryoDraft(Base):
"""灵胚:启镜前的可审阅草稿。放弃灵胚是删除草稿,不是人物死亡。"""
__tablename__ = "embryo_drafts"
id: Mapped[str] = mapped_column(String(80), primary_key=True, default=new_embryo_id)
owner_scope: Mapped[str] = mapped_column(String(80), nullable=False, index=True)
# drafting / previewing / confirming / activated / abandoned
status: Mapped[str] = mapped_column(String(40), nullable=False, default="drafting", index=True)
# original / adopted / imported / serendipity
source: Mapped[str] = mapped_column(String(40), nullable=False, default="original")
name: Mapped[str] = mapped_column(String(120), nullable=False)
description: Mapped[str | None] = mapped_column(Text)
identity_baseline_json: Mapped[str] = mapped_column(Text, nullable=False, default="{}")
# 照心试演引用:[{run_id, prompt, performed_at}],内容在事件日志,不入正式经历
rehearsals_json: Mapped[str] = mapped_column(Text, nullable=False, default="[]")
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=utc_now)
updated_at: Mapped[datetime] = mapped_column(
DateTime(timezone=True), default=utc_now, onupdate=utc_now
)
class Custodianship(Base):
"""执镜关系:治理责任(1.0 一对一),与缘契(covenants)严格分离。"""
__tablename__ = "custodianships"
id: Mapped[str] = mapped_column(String(80), primary_key=True, default=new_custodianship_id)
character_id: Mapped[str] = mapped_column(
String(80), ForeignKey("characters.id"), nullable=False, unique=True, index=True
)
custodian_scope: Mapped[str] = mapped_column(String(80), nullable=False, index=True)
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=utc_now)
class RuntimeSeat(Base):
"""命台:人物唯一权威运行位置;holder 持有租约,过期可接管,epoch 每次获取递增。"""
__tablename__ = "runtime_seats"
id: Mapped[str] = mapped_column(String(80), primary_key=True, default=new_seat_id)
character_id: Mapped[str] = mapped_column(
String(80), ForeignKey("characters.id"), nullable=False, unique=True, index=True
)
epoch: Mapped[int] = mapped_column(Integer, nullable=False, default=1)
holder: Mapped[str | None] = mapped_column(String(120))
lease_expires_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True))
updated_at: Mapped[datetime] = mapped_column(
DateTime(timezone=True), default=utc_now, onupdate=utc_now
)
class IdentityRecord(Base):
"""魂籍:可验证、版本化的身份与状态包。版本不可变;复制不能凭相同 ID 冒充原人物。"""
__tablename__ = "identity_records"
__table_args__ = (UniqueConstraint("character_id", "version", name="uq_identity_char_version"),)
id: Mapped[str] = mapped_column(String(80), primary_key=True, default=new_identity_record_id)
character_id: Mapped[str] = mapped_column(
String(80), ForeignKey("characters.id"), nullable=False, index=True
)
version: Mapped[int] = mapped_column(Integer, nullable=False)
payload_json: Mapped[str] = mapped_column(Text, nullable=False)
digest: Mapped[str] = mapped_column(String(64), nullable=False)
signature: Mapped[str] = mapped_column(String(128), nullable=False)
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=utc_now)
class SoulForging(Base):
"""铸魂提案:道体锚点重大变更必须走确认流(identity-continuity.md §3)。
pending → confirmed(应用锚点 + 签发新魂籍版本)/ rejected;
确认前人物锚点不变——日常对话、模型输出、普通工具不可静默覆盖。
"""
__tablename__ = "soul_forgings"
id: Mapped[str] = mapped_column(String(80), primary_key=True, default=lambda: new_id("forge"))
character_id: Mapped[str] = mapped_column(
String(80), ForeignKey("characters.id"), nullable=False, index=True
)
proposed_anchor_json: Mapped[str] = mapped_column(Text, nullable=False)
reason: Mapped[str] = mapped_column(Text, nullable=False, default="")
# pending / confirmed / rejected
status: Mapped[str] = mapped_column(String(20), nullable=False, default="pending", index=True)
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=utc_now)
confirmed_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True))