Add durable reconciliation decisions

This commit is contained in:
2026-08-06 12:42:20 +02:00
parent 3dae80b6b8
commit b14c693bde
14 changed files with 2037 additions and 19 deletions
+62
View File
@@ -145,6 +145,68 @@ class PipelineListResponse(BaseModel):
pipelines: list[PipelineResponse]
class ReconciliationDecisionSetCreateRequest(BaseModel):
name: str = Field(min_length=1, max_length=300)
node_id: str | None = Field(
default=None,
min_length=1,
max_length=100,
pattern=r"^[A-Za-z0-9_.:-]+$",
)
class ReconciliationDecisionWriteRequest(BaseModel):
base_revision: int = Field(ge=1)
key_hash: str = Field(pattern=r"^[0-9a-f]{64}$")
input_hash: str = Field(pattern=r"^[0-9a-f]{64}$")
action: Literal["accept", "reject", "correct", "defer"]
reason: str = Field(min_length=3, max_length=4_000)
correction: dict[str, Any] | None = None
@model_validator(mode="after")
def validate_correction(self) -> "ReconciliationDecisionWriteRequest":
if self.action == "correct" and not self.correction:
raise ValueError("Correct decisions require corrected field values.")
if self.action != "correct" and self.correction:
raise ValueError("Only correct decisions may include corrected field values.")
return self
class ReconciliationDecisionResponse(BaseModel):
ref: str
id: str
revision: int
key_hash: str
input_hash: str
action: Literal["accept", "reject", "correct", "defer"]
reason: str
correction: dict[str, Any] | None
actor_ref: str
decided_at: datetime
class ReconciliationDecisionSetResponse(BaseModel):
ref: str
id: str
pipeline_id: str
name: str
node_id: str | None
resource_revision: int = Field(ge=1)
etag: str
fingerprint: str
decisions_included: bool
current_decisions: list[ReconciliationDecisionResponse]
history: list[ReconciliationDecisionResponse]
created_by: str | None
updated_by: str | None
created_at: datetime
updated_at: datetime
class ReconciliationDecisionSetListResponse(BaseModel):
decision_sets: list[ReconciliationDecisionSetResponse]
class PipelineCreateRequest(BaseModel):
name: str = Field(min_length=1, max_length=300)
description: str | None = Field(default=None, max_length=4000)