"""PMFlow OS read-side projection schemas.""" from __future__ import annotations from typing import Any, Literal, Optional from pydantic import BaseModel, Field PMFlowStage = Literal["idea", "validation", "planning", "development", "testing", "release", "growth"] PMFlowObjectStatus = Literal["draft", "confirmed", "in_progress", "blocked", "done", "released"] PMFlowRiskLevel = Literal["low", "medium", "high"] PMFlowExecutionStatus = Literal["queued", "pushed", "coding", "pr_open", "testing", "synced", "failed"] PMFlowReleaseStatus = Literal["check_pending", "ready", "shipping", "live", "watch"] ProjectLoopStage = Literal["command_idle", "ai_extracting", "extraction_ready", "review_open", "writeback_success"] PMFlowChangeGroup = Literal["new_object", "field_update", "risk", "decision"] PMFlowChangeStatus = Literal["pending_review", "accepted", "edited", "deferred", "committed", "skipped"] PMFlowObjectType = Literal[ "Requirement", "Decision", "Task", "Risk", "ModelDecision", "TestRun", "Release", "MetricSignal", ] class PMFlowThreadMessageCreateRequest(BaseModel): content: str = Field(min_length=1, max_length=12000) source: str = "web" attachments: list[dict[str, Any]] = Field(default_factory=list) class PMFlowThreadMessageResponse(BaseModel): id: str threadId: str projectId: str role: str author: str content: str createdAt: str status: str = "sent" source: str = "web" metadata: dict[str, Any] = Field(default_factory=dict) class PMFlowProposedChangeItem(BaseModel): group: PMFlowChangeGroup object_type: PMFlowObjectType object_id: Optional[str] = None title: str = Field(min_length=1, max_length=255) summary: str = Field(min_length=1) diff: str = Field(default="") payload: dict[str, Any] = Field(default_factory=dict) confidence: float = Field(default=0.0, ge=0.0, le=1.0) risk_level: PMFlowRiskLevel = "medium" class PMFlowExtractionCreateRequest(BaseModel): thread_id: str message_id: str scope: str = "latest_message" summary: Optional[str] = None headline: Optional[str] = None routing_meta: dict[str, Any] = Field(default_factory=dict) llm_call_id: Optional[str] = None proposed_items: list[PMFlowProposedChangeItem] = Field(min_length=1) class PMFlowChangeItemEditRequest(BaseModel): summary: Optional[str] = None diff: Optional[str] = None payload_patch: dict[str, Any] = Field(default_factory=dict) reason: Optional[str] = None class PMFlowChangeItemDeferRequest(BaseModel): reason: Optional[str] = None class PMFlowChangeSetCommitRequest(BaseModel): item_ids: list[str] = Field(default_factory=list) mode: Literal["atomic"] = "atomic" note: Optional[str] = None class PMFlowChangeSetDetailResponse(BaseModel): changeSet: dict[str, Any] items: list[dict[str, Any]] = Field(default_factory=list) evidence: list[dict[str, Any]] = Field(default_factory=list) approvals: list[dict[str, Any]] = Field(default_factory=list) class PMFlowThread(BaseModel): id: str title: str projectId: str objective: str extractionStatus: Literal["idle", "loading", "ready"] = "idle" messageIds: list[str] = Field(default_factory=list) class PMFlowProjectSummary(BaseModel): id: str name: str goal: str stage: PMFlowStage threadId: str class PMFlowRequirement(BaseModel): id: str title: str summary: str stage: PMFlowStage = "planning" status: PMFlowObjectStatus linkedTaskIds: list[str] = Field(default_factory=list) class PMFlowDecision(BaseModel): id: str title: str summary: str stage: PMFlowStage = "planning" status: PMFlowObjectStatus owner: str = "未分配" class PMFlowTask(BaseModel): id: str title: str summary: str stage: PMFlowStage = "development" status: PMFlowObjectStatus assignee: str = "未分配" acceptanceCriteria: list[str] = Field(default_factory=list) requirementId: Optional[str] = None class PMFlowRisk(BaseModel): id: str title: str summary: str stage: PMFlowStage = "planning" status: PMFlowObjectStatus level: PMFlowRiskLevel = "medium" mitigation: str = "待补充缓解策略" class PMFlowModelDecision(BaseModel): id: str title: str summary: str stage: PMFlowStage = "planning" status: PMFlowObjectStatus rationale: str = "" class PMFlowTestRun(BaseModel): id: str title: str summary: str stage: PMFlowStage = "testing" status: PMFlowObjectStatus result: Literal["passed", "failed"] linkedTaskId: Optional[str] = None class PMFlowRelease(BaseModel): id: str title: str summary: str status: PMFlowReleaseStatus stage: PMFlowStage = "release" gateItems: list[dict[str, Any]] = Field(default_factory=list) class PMFlowMetricSignal(BaseModel): id: str title: str summary: str stage: PMFlowStage = "growth" status: PMFlowObjectStatus = "confirmed" value: str direction: Literal["up", "down", "flat"] = "flat" class PMFlowFeedEvent(BaseModel): id: str kind: Literal["extraction", "review", "execution", "test", "release", "growth", "agent"] title: str summary: str timestamp: str class PMFlowExecutionContext(BaseModel): taskId: Optional[str] = None status: PMFlowExecutionStatus = "queued" prompt: str = "" commitLog: list[str] = Field(default_factory=list) prStatus: str = "pending" testSummary: str = "pending" writebackStatus: str = "pending" class PMFlowTeamInbox(BaseModel): product: list[str] = Field(default_factory=list) engineering: list[str] = Field(default_factory=list) qa: list[str] = Field(default_factory=list) growth: list[str] = Field(default_factory=list) class PMFlowProjectMemory(BaseModel): truthNodeFacts: list[dict[str, Any]] = Field(default_factory=list) semanticFacts: list[dict[str, Any]] = Field(default_factory=list) sourceSummary: dict[str, int] = Field(default_factory=dict) class ProjectTruthStateProjection(BaseModel): loopStage: ProjectLoopStage = "command_idle" lastWritebackAt: Optional[str] = None project: PMFlowProjectSummary thread: PMFlowThread messages: list[dict[str, Any]] = Field(default_factory=list) changeSets: list[dict[str, Any]] = Field(default_factory=list) changeItems: list[dict[str, Any]] = Field(default_factory=list) evidence: list[dict[str, Any]] = Field(default_factory=list) requirements: list[PMFlowRequirement] = Field(default_factory=list) decisions: list[PMFlowDecision] = Field(default_factory=list) tasks: list[PMFlowTask] = Field(default_factory=list) risks: list[PMFlowRisk] = Field(default_factory=list) modelDecisions: list[PMFlowModelDecision] = Field(default_factory=list) testRuns: list[PMFlowTestRun] = Field(default_factory=list) releases: list[PMFlowRelease] = Field(default_factory=list) metricSignals: list[PMFlowMetricSignal] = Field(default_factory=list) approvals: list[dict[str, Any]] = Field(default_factory=list) feed: list[PMFlowFeedEvent] = Field(default_factory=list) teamInbox: PMFlowTeamInbox = Field(default_factory=PMFlowTeamInbox) activeChangeSetId: Optional[str] = None selectedTaskId: Optional[str] = None execution: PMFlowExecutionContext = Field(default_factory=PMFlowExecutionContext) projectMemory: PMFlowProjectMemory = Field(default_factory=PMFlowProjectMemory) projectionWarnings: list[str] = Field(default_factory=list) class ExecutionSummaryProjection(BaseModel): projectId: str execution: PMFlowExecutionContext devSync: dict[str, Any] = Field(default_factory=dict) promptPackage: Optional[dict[str, Any]] = None repoBindings: list[dict[str, Any]] = Field(default_factory=list) activeDevTasks: list[dict[str, Any]] = Field(default_factory=list) recentProgressEvents: list[dict[str, Any]] = Field(default_factory=list) recentDeliveries: list[dict[str, Any]] = Field(default_factory=list) warnings: list[str] = Field(default_factory=list)