✨ feat: WP-03 三界归真作用域与消息版本谱系(ADR-020 落地)

- 迁移 5:conversation.realm(默认真界,检查约束);message.realm 快照、canonized_at、parent_message_id 自引用与 variant_kind(origin/revision/candidate)
- 界域端点:GET conversation(realm/当前分支)与 POST realm(入境/出境显式切换,留审计——ADR-020 切换必须可见)
- 归真端点 POST /v1/messages/{id}/canonizations:scope 必须与消息界域一致(不一致 422);幂等(重复归真 200 原状态);境界归真产出 world.canonized Outbox 事件(世界知识候选入口,WP-04 消费);幻境归真仅标记试演记录
- 编辑版本 POST /v1/messages/{id}/revisions:新消息 variant=revision 引用原消息(markdown 修订同样经灵台引擎规范化),原消息永不修改
- 测试 44 项全绿(+8):界域快照、归真正/反/幂等、幻境试演、revision 原消息不变、跨域 401/403/404 fail-closed
This commit is contained in:
chenxin committed 2026-09-10 13:28:25 +08:00
1 parent 37c53862c4
commit 603a683c14
6 files changed
+432 -6

No files matched your search

+20
View File
@@ -142,6 +142,11 @@ class OutboxEvent(Base):
)
CONVERSATION_REALM_CK = CheckConstraint(
"realm IN ('reality', 'world', 'simulation')", name="realm_values"
)
class Conversation(Base):
"""对话容器:归属个人域(垂直切片 WP-03 最小集)。"""
@@ -154,6 +159,7 @@ class Conversation(Base):
ForeignKey("personal_domain.id", ondelete="cascade"), nullable=False, index=True
)
title: Mapped[str] = mapped_column(String, nullable=False, default="未命名对话")
realm: Mapped[str] = mapped_column(String, nullable=False, default="reality")
current_branch_id: Mapped[str | None] = mapped_column(
ForeignKey("branch.id", ondelete="set null", use_alter=True), nullable=True
)
@@ -164,6 +170,8 @@ class Conversation(Base):
DateTime(timezone=True), nullable=False, server_default=func.now(), onupdate=func.now()
)
__table_args__ = (CONVERSATION_REALM_CK,)
class Branch(Base):
"""对话分支:创建会话时生成默认主分支。"""
@@ -193,6 +201,12 @@ class Message(Base):
ForeignKey("branch.id", ondelete="cascade"), nullable=False, index=True
)
role: Mapped[str] = mapped_column(String, nullable=False)
realm: Mapped[str] = mapped_column(String, nullable=False, default="reality")
canonized_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
parent_message_id: Mapped[str | None] = mapped_column(
ForeignKey("message.id", ondelete="set null"), nullable=True
)
variant_kind: Mapped[str] = mapped_column(String, nullable=False, default="origin")
content: Mapped[list[dict[str, Any]]] = mapped_column(JSONB, nullable=False)
parser_version: Mapped[str | None] = mapped_column(String, nullable=True)
created_at: Mapped[datetime] = mapped_column(
@@ -201,6 +215,12 @@ class Message(Base):
__table_args__ = (
CheckConstraint("role IN ('user', 'assistant', 'system', 'tool')", name="role_values"),
CheckConstraint(
"realm IN ('reality', 'world', 'simulation')", name="realm_values"
),
CheckConstraint(
"variant_kind IN ('origin', 'revision', 'candidate')", name="variant_kind_values"
),
)