✨ feat: WP-02 角色域——完整生命周期、铸魂、内驱力与随缘
- 迁移 6:character(生命周期六态检查约束、起源、现实人物治理标记、道体基线、内驱力)+ character_version(baseline/first_statement/drive_revision/reforging/persona_candidate 五类不可变版本与审核态) - 创建:手动与随缘(确定性词库组合,同种子同候选、一次一个——不是抽卡);现实人物治理(已故拒绝、未声明授权拒绝) - 启镜(draft→active + 首个 baseline 版本)与初照自陈(候选→确认归真并入道体) - 生命周期端点:静修/归藏/复照(归档可恢复、复照不抹历史)+ 死亡两步确认(7 天冷静期可撤销、未满确认 422);非法状态迁移 422 - 铸魂(显式 confirm 强确认,直接更新道体)与人格候选(pending→审核批准才并入道体,不静默覆盖) - 内驱力编辑:写当前值并落 drive_revision 版本(可追溯,ADR-018) - 测试 52 项全绿(+8):状态机全路径、随缘确定性、现实人物三例、铸魂确认、候选审核与重复审核 409、跨域 fail-closed
This commit is contained in:
1 parent
603a683c14
commit
40221170ae
7 files changed
+859
No files matched your search
@@ -300,3 +300,77 @@ class RunEvent(Base):
|
||||
# Run 内 sequence 单调且唯一(重放去重的服务端保证)
|
||||
Index("uq_run_event_run_sequence", "run_id", "sequence", unique=True),
|
||||
)
|
||||
|
||||
|
||||
class CharacterVersion(Base):
|
||||
"""角色版本链:baseline/初照自陈/内驱力修订/铸魂/人格候选(不可变版本)。"""
|
||||
|
||||
__tablename__ = "character_version"
|
||||
|
||||
id: Mapped[str] = mapped_column(
|
||||
String, primary_key=True, default=lambda: new_id("character_version_")
|
||||
)
|
||||
character_id: Mapped[str] = mapped_column(
|
||||
ForeignKey("character.id", ondelete="cascade"), nullable=False, index=True
|
||||
)
|
||||
kind: Mapped[str] = mapped_column(String, nullable=False)
|
||||
status: Mapped[str] = mapped_column(String, nullable=False, default="approved")
|
||||
payload: Mapped[dict[str, Any]] = mapped_column(JSONB, nullable=False, default=dict)
|
||||
created_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True), nullable=False, server_default=func.now()
|
||||
)
|
||||
|
||||
__table_args__ = (
|
||||
CheckConstraint(
|
||||
"kind IN ('baseline', 'first_statement', 'drive_revision', 'reforging', "
|
||||
"'persona_candidate')",
|
||||
name="kind_values",
|
||||
),
|
||||
CheckConstraint("status IN ('pending', 'approved', 'rejected')", name="status_values"),
|
||||
)
|
||||
|
||||
|
||||
class Character(Base):
|
||||
"""角色:稳定身份、生命周期状态、道体基线与内驱力(WP-02)。"""
|
||||
|
||||
__tablename__ = "character"
|
||||
|
||||
id: Mapped[str] = mapped_column(
|
||||
String, primary_key=True, default=lambda: new_id("character_")
|
||||
)
|
||||
personal_domain_id: Mapped[str] = mapped_column(
|
||||
ForeignKey("personal_domain.id", ondelete="cascade"), nullable=False, index=True
|
||||
)
|
||||
name: Mapped[str] = mapped_column(String, nullable=False)
|
||||
# 生命周期:灵胚 → 启镜 → 静修/归藏(可复照);死亡走两步确认,deceased 不可逆
|
||||
status: Mapped[str] = mapped_column(String, nullable=False, default="draft")
|
||||
origin: Mapped[str] = mapped_column(String, nullable=False, default="original")
|
||||
based_on_real_person: Mapped[bool] = mapped_column(nullable=False, default=False)
|
||||
real_person_attested: Mapped[bool] = mapped_column(nullable=False, default=False)
|
||||
# 道体基线(identity_baseline):最小稳定身份锚点,普通对话/记忆不可静默覆盖
|
||||
identity_baseline: Mapped[dict[str, Any]] = mapped_column(JSONB, nullable=False, default=dict)
|
||||
# 内驱力(character_drives):声明式动机维度,用户可审阅编辑(ADR-018)
|
||||
drives: Mapped[list[dict[str, Any]]] = mapped_column(JSONB, nullable=False, default=list)
|
||||
current_version_id: Mapped[str | None] = mapped_column(
|
||||
ForeignKey("character_version.id", ondelete="set null", use_alter=True), nullable=True
|
||||
)
|
||||
death_requested_at: Mapped[datetime | None] = mapped_column(
|
||||
DateTime(timezone=True), nullable=True
|
||||
)
|
||||
created_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True), nullable=False, server_default=func.now()
|
||||
)
|
||||
updated_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True), nullable=False, server_default=func.now(), onupdate=func.now()
|
||||
)
|
||||
|
||||
__table_args__ = (
|
||||
CheckConstraint(
|
||||
"status IN ('draft', 'active', 'resting', 'archived', 'death_pending', 'deceased')",
|
||||
name="status_values",
|
||||
),
|
||||
CheckConstraint(
|
||||
"origin IN ('original', 'serendipity', 'template', 'import', 'fork')",
|
||||
name="origin_values",
|
||||
),
|
||||
)
|
||||
Reference in new issue
Block a user