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 干净
This commit is contained in:
chenxin committed 2026-08-27 20:10:11 +08:00
1 parent 684261f4b4
commit 7e23d6fa84
108 files changed
+2600 -9732

No files matched your search

@@ -0,0 +1,170 @@
"""缘契域_契约与事件_铸魂分灵_河图境界与实体_实录作用域_退役旧人格驱动演化世界表
Revision ID: 007
Revises: 006
Create Date: 2026-08-27 19:32:08.478484
"""
from typing import Sequence, Union
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision: str = '007'
down_revision: Union[str, Sequence[str], None] = '006'
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None:
"""Upgrade schema."""
# 旧世界表退役重建(世界权威移交河图域 hetu;开发数据丢弃)
op.drop_table('world_entities')
op.drop_table('character_world_entities')
op.drop_table('world_relations')
# 缘契域
op.create_table('covenants',
sa.Column('id', sa.String(length=80), nullable=False),
sa.Column('character_id', sa.String(length=80), nullable=False),
sa.Column('owner_scope', sa.String(length=80), nullable=False),
sa.Column('dimensions_json', sa.Text(), nullable=False),
sa.Column('primary_title', sa.String(length=120), nullable=True),
sa.Column('boundaries_json', sa.Text(), nullable=False),
sa.Column('adult_consent', sa.Boolean(), nullable=False),
sa.Column('status', sa.String(length=20), nullable=False),
sa.Column('version', sa.Integer(), nullable=False),
sa.Column('created_at', sa.DateTime(timezone=True), nullable=False),
sa.Column('updated_at', sa.DateTime(timezone=True), nullable=False),
sa.ForeignKeyConstraint(['character_id'], ['characters.id'], ),
sa.PrimaryKeyConstraint('id')
)
op.create_index(op.f('ix_covenants_character_id'), 'covenants', ['character_id'], unique=False)
op.create_index(op.f('ix_covenants_owner_scope'), 'covenants', ['owner_scope'], unique=False)
op.create_index(op.f('ix_covenants_status'), 'covenants', ['status'], unique=False)
op.create_table('covenant_events',
sa.Column('id', sa.String(length=80), nullable=False),
sa.Column('covenant_id', sa.String(length=80), nullable=False),
sa.Column('character_id', sa.String(length=80), nullable=False),
sa.Column('type', sa.String(length=20), nullable=False),
sa.Column('payload_json', sa.Text(), nullable=False),
sa.Column('actor', sa.String(length=20), nullable=False),
sa.Column('created_at', sa.DateTime(timezone=True), nullable=False),
sa.ForeignKeyConstraint(['covenant_id'], ['covenants.id'], ),
sa.PrimaryKeyConstraint('id')
)
op.create_index(op.f('ix_covenant_events_character_id'), 'covenant_events', ['character_id'], unique=False)
op.create_index(op.f('ix_covenant_events_covenant_id'), 'covenant_events', ['covenant_id'], unique=False)
op.create_index(op.f('ix_covenant_events_created_at'), 'covenant_events', ['created_at'], unique=False)
op.create_index(op.f('ix_covenant_events_type'), 'covenant_events', ['type'], unique=False)
# 铸魂
op.create_table('soul_forgings',
sa.Column('id', sa.String(length=80), nullable=False),
sa.Column('character_id', sa.String(length=80), nullable=False),
sa.Column('proposed_anchor_json', sa.Text(), nullable=False),
sa.Column('reason', sa.Text(), nullable=False),
sa.Column('status', sa.String(length=20), nullable=False),
sa.Column('created_at', sa.DateTime(timezone=True), nullable=False),
sa.Column('confirmed_at', sa.DateTime(timezone=True), nullable=True),
sa.ForeignKeyConstraint(['character_id'], ['characters.id'], ),
sa.PrimaryKeyConstraint('id')
)
op.create_index(op.f('ix_soul_forgings_character_id'), 'soul_forgings', ['character_id'], unique=False)
op.create_index(op.f('ix_soul_forgings_status'), 'soul_forgings', ['status'], unique=False)
# 河图境界
op.create_table('persistent_worlds',
sa.Column('id', sa.String(length=80), nullable=False),
sa.Column('owner_scope', sa.String(length=80), nullable=False),
sa.Column('name', sa.String(length=120), nullable=False),
sa.Column('description', sa.Text(), nullable=False),
sa.Column('rules_json', sa.Text(), nullable=False),
sa.Column('lorebook_id', sa.String(length=80), nullable=True),
sa.Column('canon_count', sa.Integer(), nullable=False),
sa.Column('status', sa.String(length=20), nullable=False),
sa.Column('created_at', sa.DateTime(timezone=True), nullable=False),
sa.Column('updated_at', sa.DateTime(timezone=True), nullable=False),
sa.PrimaryKeyConstraint('id')
)
op.create_index(op.f('ix_persistent_worlds_lorebook_id'), 'persistent_worlds', ['lorebook_id'], unique=False)
op.create_index(op.f('ix_persistent_worlds_owner_scope'), 'persistent_worlds', ['owner_scope'], unique=False)
op.create_table('world_entities',
sa.Column('id', sa.String(length=80), nullable=False),
sa.Column('world_id', sa.String(length=80), nullable=False),
sa.Column('kind', sa.String(length=30), nullable=False),
sa.Column('name', sa.String(length=120), nullable=False),
sa.Column('description', sa.Text(), nullable=False),
sa.Column('attrs_json', sa.Text(), nullable=False),
sa.Column('created_at', sa.DateTime(timezone=True), nullable=False),
sa.ForeignKeyConstraint(['world_id'], ['persistent_worlds.id'], ),
sa.PrimaryKeyConstraint('id')
)
op.create_index(op.f('ix_world_entities_world_id'), 'world_entities', ['world_id'], unique=False)
op.create_table('world_relations',
sa.Column('id', sa.String(length=80), nullable=False),
sa.Column('world_id', sa.String(length=80), nullable=False),
sa.Column('source_entity_id', sa.String(length=80), nullable=False),
sa.Column('target_entity_id', sa.String(length=80), nullable=False),
sa.Column('relation', sa.String(length=80), nullable=False),
sa.Column('note', sa.Text(), nullable=False),
sa.Column('created_at', sa.DateTime(timezone=True), nullable=False),
sa.ForeignKeyConstraint(['source_entity_id'], ['world_entities.id'], ),
sa.ForeignKeyConstraint(['target_entity_id'], ['world_entities.id'], ),
sa.ForeignKeyConstraint(['world_id'], ['persistent_worlds.id'], ),
sa.PrimaryKeyConstraint('id')
)
op.create_index(op.f('ix_world_relations_source_entity_id'), 'world_relations', ['source_entity_id'], unique=False)
op.create_index(op.f('ix_world_relations_target_entity_id'), 'world_relations', ['target_entity_id'], unique=False)
op.create_index(op.f('ix_world_relations_world_id'), 'world_relations', ['world_id'], unique=False)
# 实录作用域
with op.batch_alter_table('factual_records') as batch:
batch.add_column(sa.Column('scope', sa.String(length=40), nullable=False, server_default='reality'))
batch.create_index('ix_factual_records_scope', ['scope'])
# 旧人格/驱动/演化域退役(人格基线=道体锚点 identity_baseline_json + 魂籍版本链)
with op.batch_alter_table('characters') as batch:
batch.drop_column('current_personality_version_id')
op.drop_table('personality_versions')
op.drop_table('personality_proposals')
op.drop_table('curiosity_questions')
op.drop_table('exploratory_subgoals')
op.drop_table('evolution_candidates')
def downgrade() -> None:
"""Downgrade schema."""
op.drop_table('evolution_candidates')
op.drop_table('exploratory_subgoals')
op.drop_table('curiosity_questions')
op.drop_table('personality_proposals')
op.drop_table('personality_versions')
with op.batch_alter_table('characters') as batch:
batch.add_column(sa.Column('current_personality_version_id', sa.String(length=80), nullable=True))
with op.batch_alter_table('factual_records') as batch:
batch.drop_index('ix_factual_records_scope')
batch.drop_column('scope')
op.drop_index(op.f('ix_world_relations_world_id'), table_name='world_relations')
op.drop_index(op.f('ix_world_relations_target_entity_id'), table_name='world_relations')
op.drop_index(op.f('ix_world_relations_source_entity_id'), table_name='world_relations')
op.drop_table('world_relations')
op.drop_index(op.f('ix_world_entities_world_id'), table_name='world_entities')
op.drop_table('world_entities')
op.drop_index(op.f('ix_persistent_worlds_owner_scope'), table_name='persistent_worlds')
op.drop_index(op.f('ix_persistent_worlds_lorebook_id'), table_name='persistent_worlds')
op.drop_table('persistent_worlds')
op.drop_index(op.f('ix_soul_forgings_status'), table_name='soul_forgings')
op.drop_index(op.f('ix_soul_forgings_character_id'), table_name='soul_forgings')
op.drop_table('soul_forgings')
op.drop_index(op.f('ix_covenant_events_type'), table_name='covenant_events')
op.drop_index(op.f('ix_covenant_events_created_at'), table_name='covenant_events')
op.drop_index(op.f('ix_covenant_events_covenant_id'), table_name='covenant_events')
op.drop_index(op.f('ix_covenant_events_character_id'), table_name='covenant_events')
op.drop_table('covenant_events')
op.drop_index(op.f('ix_covenants_status'), table_name='covenants')
op.drop_index(op.f('ix_covenants_owner_scope'), table_name='covenants')
op.drop_index(op.f('ix_covenants_character_id'), table_name='covenants')
op.drop_table('covenants')