377 lines
13 KiB
Python
377 lines
13 KiB
Python
"""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"]
|
|
PMFlowExecutionRuntimeTarget = Literal["local_bridge", "codex", "github_agent", "manual"]
|
|
PMFlowExecutionProgressSource = Literal["local_bridge", "codex", "github_agent", "manual"]
|
|
PMFlowExecutionProgressEventType = Literal[
|
|
"branch_created",
|
|
"commit",
|
|
"pr_opened",
|
|
"pr_synced",
|
|
"test_passed",
|
|
"test_failed",
|
|
"checks_passed",
|
|
"failed",
|
|
"blocked",
|
|
"merged",
|
|
"accepted",
|
|
"manual_progress",
|
|
]
|
|
PMFlowReleaseGateStatus = Literal["ready", "blocked", "needs_confirmation", "empty"]
|
|
PMFlowReleaseValidationDecision = Literal["enter_release_candidate", "keep_blocked"]
|
|
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"]
|
|
PMFlowReviewerRoutingStatus = Literal["empty", "ready", "warning"]
|
|
PMFlowReviewerRoutingSourceType = Literal["manual", "ai_extraction", "iteration_recommendation", "unknown"]
|
|
PMFlowReviewerRoutingPriority = Literal["normal", "elevated", "urgent"]
|
|
PMFlowReviewerConfidence = Literal["low", "medium", "high"]
|
|
PMFlowFallbackReviewerRole = Literal["OWNER", "REVIEWER", "MEMBER"]
|
|
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 PMFlowExecutionHandoffRequest(BaseModel):
|
|
task_id: str = Field(min_length=1)
|
|
repo_binding_id: Optional[str] = None
|
|
runtime_target: PMFlowExecutionRuntimeTarget = "local_bridge"
|
|
note: Optional[str] = Field(default=None, max_length=4000)
|
|
|
|
|
|
class PMFlowExecutionHandoffConsumeRequest(BaseModel):
|
|
runtime_target: Optional[PMFlowExecutionRuntimeTarget] = None
|
|
consumer_label: Optional[str] = Field(default=None, max_length=120)
|
|
note: Optional[str] = Field(default=None, max_length=4000)
|
|
|
|
|
|
class PMFlowExecutionProgressEventRequest(BaseModel):
|
|
task_id: str = Field(min_length=1)
|
|
event_type: PMFlowExecutionProgressEventType
|
|
source: PMFlowExecutionProgressSource = "manual"
|
|
repo_binding_id: Optional[str] = None
|
|
branch_name: Optional[str] = Field(default=None, max_length=255)
|
|
commit_sha: Optional[str] = Field(default=None, max_length=255)
|
|
pr_number: Optional[int] = Field(default=None, ge=1)
|
|
test_summary: Optional[str] = Field(default=None, max_length=4000)
|
|
workflow_state: Optional[str] = Field(default=None, max_length=120)
|
|
summary: Optional[str] = Field(default=None, max_length=4000)
|
|
event_source_id: Optional[str] = Field(default=None, max_length=255)
|
|
occurred_at: Optional[str] = None
|
|
|
|
|
|
class PMFlowReleaseValidationRunCreateRequest(BaseModel):
|
|
decision: PMFlowReleaseValidationDecision
|
|
note: Optional[str] = Field(default=None, max_length=4000)
|
|
|
|
|
|
class PMFlowReleaseFeedbackIngestRequest(BaseModel):
|
|
source_type: str = Field(default="manual", min_length=1, max_length=32)
|
|
title: Optional[str] = Field(default=None, max_length=255)
|
|
content: str = Field(min_length=1, max_length=12000)
|
|
charter_id: Optional[str] = None
|
|
metrics: dict[str, Any] = Field(default_factory=dict)
|
|
samples: list[dict[str, Any]] = Field(default_factory=list)
|
|
|
|
|
|
class PMFlowIterationRecommendationChangeSetDraftRequest(BaseModel):
|
|
note: Optional[str] = Field(default=None, max_length=4000)
|
|
|
|
|
|
class PMFlowIterationRecommendationGroupChangeSetDraftRequest(BaseModel):
|
|
recommendation_ids: list[str] = Field(default_factory=list)
|
|
note: Optional[str] = Field(default=None, max_length=4000)
|
|
|
|
|
|
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 PMFlowReviewerSuggestion(BaseModel):
|
|
userId: Optional[str] = None
|
|
displayName: Optional[str] = None
|
|
role: Optional[str] = None
|
|
reason: str
|
|
confidence: PMFlowReviewerConfidence = "low"
|
|
|
|
|
|
class PMFlowReviewerRoutingItem(BaseModel):
|
|
projectId: str
|
|
changeSetId: str
|
|
changeSetTitle: str
|
|
changeSetStatus: str
|
|
sourceType: PMFlowReviewerRoutingSourceType = "unknown"
|
|
reviewReason: str
|
|
riskLevel: PMFlowRiskLevel = "low"
|
|
priority: PMFlowReviewerRoutingPriority = "normal"
|
|
changeTypes: list[str] = Field(default_factory=list)
|
|
itemCount: int = 0
|
|
pendingItemCount: int = 0
|
|
evidenceCount: int = 0
|
|
suggestedReviewer: Optional[PMFlowReviewerSuggestion] = None
|
|
fallbackReviewerRole: Optional[PMFlowFallbackReviewerRole] = None
|
|
targetUrl: str
|
|
createdAt: Optional[str] = None
|
|
updatedAt: Optional[str] = None
|
|
|
|
|
|
class PMFlowReviewerRoutingSummary(BaseModel):
|
|
totalPendingReview: int = 0
|
|
highRiskCount: int = 0
|
|
missingReviewerCount: int = 0
|
|
iterationDraftCount: int = 0
|
|
|
|
|
|
class PMFlowReviewerRoutingProjection(BaseModel):
|
|
status: PMFlowReviewerRoutingStatus = "empty"
|
|
warningCode: Optional[str] = None
|
|
items: list[PMFlowReviewerRoutingItem] = Field(default_factory=list)
|
|
summary: PMFlowReviewerRoutingSummary = Field(default_factory=PMFlowReviewerRoutingSummary)
|
|
|
|
|
|
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)
|
|
reviewerRouting: PMFlowReviewerRoutingProjection = Field(default_factory=PMFlowReviewerRoutingProjection)
|
|
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
|
|
releaseGate: dict[str, Any] = Field(default_factory=dict)
|
|
releaseSignals: dict[str, Any] = Field(default_factory=dict)
|
|
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)
|