feat: M3 — 伏笔账本 + 节奏引擎 + 大纲(含并发记账 bugfix)
- 伏笔账本:纯函数状态机(OPEN/PARTIAL/CLOSED/OVERDUE) + ForeshadowLedger repo;验收后到期扫描(BackgroundTask 自建 session 置 OVERDUE);登记/状态变更端点 - 节奏 + 三审齐:foreshadow-analyst + pace-checker 并入 LangGraph 并行审(REVIEW_SPECS),collect 分列落 chapter_reviews(conflicts/foreshadow_sug/pace),review SSE 加 foreshadow/pace 事件 - 大纲:outliner Agent 产 OutlineResult(含 foreshadow_windows),POST /outline 逐章 upsert outline 表;GET /foreshadow?status= 看板 - 前端:伏笔四泳道看板(OVERDUE 琥珀) + 大纲编辑器(窗口徽标) + 节奏节拍图(▁▃▅) + 审稿页消费 foreshadow/pace SSE - bugfix(T3.8):并行三审共用请求 session 记账触发 'Session is already flushing' → foreshadow/pace 静默丢失;SqlAlchemyLedgerSink.record 改 add-only(靠端点/事务 commit),加并发回归测试 - M3 E2E:真实 DB + mock 网关零 token 走通 埋设→进展→验收后扫描 OVERDUE→看板 + 大纲含窗口 + 三审齐 SSE/留痕;E2E 暴露并钉住上述 bug - 门禁绿:mypy 111 / pytest 228(0 xfailed) / alembic 无漂移;前端 gen:api/lint/tsc/vitest 69/build
This commit is contained in:
66
apps/api/ww_api/schemas/foreshadow.py
Normal file
66
apps/api/ww_api/schemas/foreshadow.py
Normal file
@@ -0,0 +1,66 @@
|
||||
"""伏笔登记 / 状态变更端点的请求/响应 schema(C3 扩 / ARCH §6.2, §7.2)。
|
||||
|
||||
snake_case;前端经 OpenAPI 生成 TS 类型消费。改字段 → 前端必须 `pnpm gen:api`。
|
||||
登记是**作者显式动作**(不变量 #3:伏笔入库不经 AI 静默写库),到期扫描是验收后的
|
||||
确定性纯函数置位(M3-d),二者都不在审稿/写章流水线里。
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
|
||||
class ForeshadowRegisterRequest(BaseModel):
|
||||
"""POST /projects/:id/foreshadow:作者显式登记一条伏笔(status 落 OPEN)。"""
|
||||
|
||||
code: str = Field(min_length=1, description="伏笔代号,`(project_id, code)` 唯一")
|
||||
title: str = Field(min_length=1, description="伏笔标题/一句话描述")
|
||||
planted_at: int | None = Field(default=None, description="埋设章号")
|
||||
content: str | None = Field(default=None, description="伏笔正文/线索")
|
||||
expected_close_from: int | None = Field(default=None, description="预期回收窗口起始章")
|
||||
expected_close_to: int | None = Field(
|
||||
default=None, description="预期回收窗口结束章(到期判据用)"
|
||||
)
|
||||
importance: str | None = Field(default=None, description="重要度(自由文本,看板用)")
|
||||
|
||||
|
||||
class ForeshadowTransitionRequest(BaseModel):
|
||||
"""PATCH /projects/:id/foreshadow/:code:状态机转移 和/或 追加一条进展。
|
||||
|
||||
两字段皆可选:`to_status` 走状态机(非法 → VALIDATION 信封);`progress_entry`
|
||||
append-only 追加到 progress JSONB。二者可同时给(先转移、后追加进展)。
|
||||
"""
|
||||
|
||||
to_status: str | None = Field(
|
||||
default=None, description="目标状态(OPEN/PARTIAL/CLOSED/OVERDUE)"
|
||||
)
|
||||
progress_entry: dict[str, Any] | None = Field(
|
||||
default=None, description="追加一条进展记录(append-only,不覆盖历史)"
|
||||
)
|
||||
|
||||
|
||||
class ForeshadowView(BaseModel):
|
||||
"""伏笔账本视图(登记/状态变更/看板共用;snake_case)。形对齐 `ForeshadowLedgerView`。"""
|
||||
|
||||
code: str
|
||||
title: str
|
||||
status: str
|
||||
planted_at: int | None = None
|
||||
content: str | None = None
|
||||
expected_close_from: int | None = None
|
||||
expected_close_to: int | None = None
|
||||
importance: str | None = None
|
||||
links: list[dict[str, Any]] = Field(default_factory=list)
|
||||
progress: list[dict[str, Any]] = Field(default_factory=list)
|
||||
|
||||
|
||||
class ForeshadowBoardResponse(BaseModel):
|
||||
"""GET /projects/:id/foreshadow?status=:伏笔看板(四泳道 + OVERDUE 字段齐)。
|
||||
|
||||
`status` 缺省返回全部;按 `code` 升序(repo `list_by_status` 已排序)。前端按
|
||||
`status` 分四泳道(OPEN/PARTIAL/CLOSED/OVERDUE),用 `expected_close_to` 标逾期。
|
||||
"""
|
||||
|
||||
foreshadow: list[ForeshadowView] = Field(default_factory=list)
|
||||
Reference in New Issue
Block a user