"""admin 域请求/响应模型(FR-ADM-01~05)。 实体与素材的载荷复用 ``packages/kb/schemas.py``(服务层契约同源);本模块只 放后台特有的形状:状态机流转请求、规则对外视图、缺口看板行。雪花 ID 一律 以字符串出现在载荷里(与 kb 契约一致:JS Number 只有 2^53 精度)。 """ from __future__ import annotations from datetime import datetime from typing import Any, Literal from pydantic import BaseModel, Field from packages.kb.schemas import EntityStatus from packages.rules.dsl import Rule as RuleUpsert __all__ = [ "GapOut", "RuleOut", "RuleTransitionRequest", "RuleUpsert", "TransitionRequest", ] class TransitionRequest(BaseModel): """``POST /kb/items/{id}/transition`` 载荷。 ``target`` 收全量四态而不是只收三个「前进方向」:published→draft 这类非法 跃迁应该是**状态机语义冲突(40900)**,而不是 schema 层的 422——顾问在 界面上看到的错误要能告诉他「为什么不行」(矩阵见 ``packages.kb.service``), 而不是「这个值不合法」。draft 作为目标在矩阵里永远非法,自然会被拦下。 """ target: EntityStatus class RuleTransitionRequest(BaseModel): """``POST /rules/{rule_key}/transition`` 载荷。 规则状态机里 draft 永远不是合法目标(发布与下线是仅有的两个前进动作, 与实体不同,规则没有 reviewing 中间态),直接在 schema 层收窄。 """ target: Literal["published", "archived"] class RuleOut(BaseModel): """规则对外视图。conditions/effects 保持入库的 DSL 原样(决策表是数据, 后台表单按 DSL 渲染,不做二次加工)。""" rule_id: str rule_key: str category: str version: int = Field(description="内容版本号,每次修改 +1") status: str priority: int conditions: dict[str, Any] effects: dict[str, Any] is_hard: bool confidence: float evidence: str | None author: str | None reviewer: str | None published_at: datetime | None created_at: datetime class GapOut(BaseModel): """缺口看板一行(kb_gap,T-P2-06)。hit_count 是排序依据也是优先级信号。""" gap_id: str query_text: str = Field(description="用户真实查询原文——内容生产的起点") filter_ctx: dict[str, Any] = Field(description="缺口出现时的过滤条件快照") hit_count: int = Field(description="同一缺口累计出现次数") first_seen_at: datetime last_seen_at: datetime