- 规则 GET 不存在 project → 404(原返误导性空 200,掩盖坏 id):list_rules 加 项目存在校验(仿 C1/H2)。 - 规则 content 纯空白 → 422(原 strip 前校验 min_length,空白行入库成垃圾): 改 StringConstraints(strip_whitespace=True, min_length=1)。 - 档位路由 tier 限定 writer/analyst/light(Tier Literal)→ 未知档位 422 (原接受任意字符串)。 回归测试:test_generation(GET rules 404)/ test_rules(空白 content 422)/ test_settings_providers(未知 tier 422)。门禁绿:ruff/format/mypy(210)/pytest。
32 lines
1.2 KiB
Python
32 lines
1.2 KiB
Python
"""规则端点的请求/响应 schema(C3 扩 / PRODUCT_SPEC §7 POST /rules)。
|
||
|
||
snake_case;前端经 OpenAPI 生成 TS 类型消费。改字段 → 前端必须 `pnpm gen:api`。
|
||
`level` ∈ global/genre/style/project(四级合并优先级,见 memory `merge_rules`)。
|
||
加规则是作者显式动作——审稿发现的问题/亮点随手沉淀为规则(非 AI 静默写库,不变量 #3)。
|
||
"""
|
||
|
||
from __future__ import annotations
|
||
|
||
from typing import Annotated, Literal
|
||
|
||
from pydantic import BaseModel, Field, StringConstraints
|
||
|
||
RuleLevel = Literal["global", "genre", "style", "project"]
|
||
|
||
# 先 strip 再校验长度:纯空白内容(" ")strip 后为空 → 422(QA MEDIUM:此前被接受入库)。
|
||
RuleContent = Annotated[str, StringConstraints(strip_whitespace=True, min_length=1)]
|
||
|
||
|
||
class RuleCreateRequest(BaseModel):
|
||
"""POST /projects/:id/rules:新增一条规则。"""
|
||
|
||
level: RuleLevel = Field(description="规则级别(global/genre/style/project,越具体越优先)")
|
||
content: RuleContent = Field(description="规则正文(首尾空白会被裁剪,不可全空白)")
|
||
|
||
|
||
class RuleView(BaseModel):
|
||
"""规则视图(创建后回显;snake_case)。"""
|
||
|
||
level: str
|
||
content: str
|