M2a:镜树域后端核心——树/节点/引文/归真/移栽全量 API 与 Kernel 完成回调(芽体固化/残答封存),8 用例钉死 PRD 场景 1/2/3/5/6/7/8

This commit is contained in:
chenxin committed 2026-08-21 23:00:07 +08:00
1 parent 1cd0069d65
commit e6a3b7121f
16 files changed
+2002 -74

No files matched your search

@@ -0,0 +1,125 @@
"""镜树域:主题树、节点、引文锚、归真记录、移栽谱系
Revision ID: 002
Revises: 001
Create Date: 2026-08-21 22:49:03.731149
"""
from typing import Sequence, Union
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision: str = '002'
down_revision: Union[str, Sequence[str], None] = '001'
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None:
"""Upgrade schema."""
# ### commands auto generated by Alembic - please adjust! ###
op.create_table('tree_transplants',
sa.Column('id', sa.String(length=80), nullable=False),
sa.Column('source_tree_id', sa.String(length=80), nullable=False),
sa.Column('source_node_id', sa.String(length=80), nullable=False),
sa.Column('new_tree_id', sa.String(length=80), nullable=False),
sa.Column('created_at', sa.DateTime(timezone=True), nullable=False),
sa.PrimaryKeyConstraint('id')
)
op.create_index(op.f('ix_tree_transplants_new_tree_id'), 'tree_transplants', ['new_tree_id'], unique=False)
op.create_index(op.f('ix_tree_transplants_source_tree_id'), 'tree_transplants', ['source_tree_id'], unique=False)
op.create_table('mirror_trees',
sa.Column('id', sa.String(length=80), nullable=False),
sa.Column('character_id', sa.String(length=80), nullable=False),
sa.Column('title', sa.String(length=300), nullable=False),
sa.Column('status', sa.String(length=40), nullable=False),
sa.Column('default_realm', sa.String(length=40), nullable=False),
sa.Column('working_entry_node_id', sa.String(length=80), nullable=True),
sa.Column('transplanted_from_json', sa.Text(), 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_mirror_trees_character_id'), 'mirror_trees', ['character_id'], unique=False)
op.create_index(op.f('ix_mirror_trees_status'), 'mirror_trees', ['status'], unique=False)
op.create_table('canonizations',
sa.Column('id', sa.String(length=80), nullable=False),
sa.Column('tree_id', sa.String(length=80), nullable=False),
sa.Column('character_id', sa.String(length=80), nullable=False),
sa.Column('scope', sa.String(length=40), nullable=False),
sa.Column('world_id', sa.String(length=80), nullable=True),
sa.Column('endpoint_node_id', sa.String(length=80), nullable=False),
sa.Column('path_nodes_json', sa.Text(), nullable=False),
sa.Column('confirmed_by', sa.String(length=80), nullable=False),
sa.Column('created_at', sa.DateTime(timezone=True), nullable=False),
sa.ForeignKeyConstraint(['tree_id'], ['mirror_trees.id'], ),
sa.PrimaryKeyConstraint('id')
)
op.create_index(op.f('ix_canonizations_character_id'), 'canonizations', ['character_id'], unique=False)
op.create_index(op.f('ix_canonizations_endpoint_node_id'), 'canonizations', ['endpoint_node_id'], unique=False)
op.create_index(op.f('ix_canonizations_scope'), 'canonizations', ['scope'], unique=False)
op.create_index(op.f('ix_canonizations_tree_id'), 'canonizations', ['tree_id'], unique=False)
op.create_table('tree_nodes',
sa.Column('id', sa.String(length=80), nullable=False),
sa.Column('tree_id', sa.String(length=80), nullable=False),
sa.Column('parent_node_id', sa.String(length=80), nullable=True),
sa.Column('node_type', sa.String(length=40), nullable=False),
sa.Column('status', sa.String(length=40), nullable=False),
sa.Column('author', sa.String(length=40), nullable=False),
sa.Column('content', sa.Text(), nullable=False),
sa.Column('realm', sa.String(length=40), nullable=False),
sa.Column('generation_meta_json', sa.Text(), nullable=False),
sa.Column('supersedes_node_id', sa.String(length=80), nullable=True),
sa.Column('created_at', sa.DateTime(timezone=True), nullable=False),
sa.Column('updated_at', sa.DateTime(timezone=True), nullable=False),
sa.ForeignKeyConstraint(['parent_node_id'], ['tree_nodes.id'], ),
sa.ForeignKeyConstraint(['tree_id'], ['mirror_trees.id'], ),
sa.PrimaryKeyConstraint('id'),
sa.UniqueConstraint('tree_id', 'supersedes_node_id', name='uq_tree_node_supersedes')
)
op.create_index(op.f('ix_tree_nodes_node_type'), 'tree_nodes', ['node_type'], unique=False)
op.create_index(op.f('ix_tree_nodes_parent_node_id'), 'tree_nodes', ['parent_node_id'], unique=False)
op.create_index(op.f('ix_tree_nodes_status'), 'tree_nodes', ['status'], unique=False)
op.create_index(op.f('ix_tree_nodes_tree_id'), 'tree_nodes', ['tree_id'], unique=False)
op.create_table('citations',
sa.Column('id', sa.String(length=80), nullable=False),
sa.Column('node_id', sa.String(length=80), nullable=False),
sa.Column('target_type', sa.String(length=40), nullable=False),
sa.Column('locator_json', sa.Text(), nullable=False),
sa.Column('snapshot', sa.Text(), nullable=False),
sa.Column('source_id', sa.String(length=200), nullable=False),
sa.Column('source_version', sa.Integer(), nullable=False),
sa.Column('created_at', sa.DateTime(timezone=True), nullable=False),
sa.ForeignKeyConstraint(['node_id'], ['tree_nodes.id'], ),
sa.PrimaryKeyConstraint('id')
)
op.create_index(op.f('ix_citations_node_id'), 'citations', ['node_id'], unique=False)
# ### end Alembic commands ###
def downgrade() -> None:
"""Downgrade schema."""
# ### commands auto generated by Alembic - please adjust! ###
op.drop_index(op.f('ix_citations_node_id'), table_name='citations')
op.drop_table('citations')
op.drop_index(op.f('ix_tree_nodes_tree_id'), table_name='tree_nodes')
op.drop_index(op.f('ix_tree_nodes_status'), table_name='tree_nodes')
op.drop_index(op.f('ix_tree_nodes_parent_node_id'), table_name='tree_nodes')
op.drop_index(op.f('ix_tree_nodes_node_type'), table_name='tree_nodes')
op.drop_table('tree_nodes')
op.drop_index(op.f('ix_canonizations_tree_id'), table_name='canonizations')
op.drop_index(op.f('ix_canonizations_scope'), table_name='canonizations')
op.drop_index(op.f('ix_canonizations_endpoint_node_id'), table_name='canonizations')
op.drop_index(op.f('ix_canonizations_character_id'), table_name='canonizations')
op.drop_table('canonizations')
op.drop_index(op.f('ix_mirror_trees_status'), table_name='mirror_trees')
op.drop_index(op.f('ix_mirror_trees_character_id'), table_name='mirror_trees')
op.drop_table('mirror_trees')
op.drop_index(op.f('ix_tree_transplants_source_tree_id'), table_name='tree_transplants')
op.drop_index(op.f('ix_tree_transplants_new_tree_id'), table_name='tree_transplants')
op.drop_table('tree_transplants')
# ### end Alembic commands ###