feat: implement definition-aware forms runtime

This commit is contained in:
2026-08-01 17:48:35 +02:00
parent 396d6b0c90
commit 9dc49fe27b
25 changed files with 4180 additions and 79 deletions
@@ -0,0 +1,142 @@
from __future__ import annotations
from dataclasses import dataclass, field, replace
from datetime import datetime
from typing import Mapping
from govoplan_core.core.institutional import (
EvidenceReference,
InstitutionalContextError,
InstitutionalReference,
ServiceBinding,
)
FORM_INSTANCE_STATUSES = frozenset(
{
"started",
"draft",
"submitted",
"validated",
"needs_review",
"accepted",
"rejected",
"handed_off",
"archived",
}
)
@dataclass(frozen=True, slots=True)
class FormInstance:
tenant_id: str
instance_id: str
revision: int
status: str
definition_ref: InstitutionalReference
values: Mapping[str, object]
validation_results: tuple[Mapping[str, object], ...]
recorded_at: datetime
change_reason: str
created_by: str
changed_by: str
attachment_refs: tuple[EvidenceReference, ...] = ()
signature_refs: tuple[EvidenceReference, ...] = ()
handoff_refs: tuple[InstitutionalReference, ...] = ()
service_ref: InstitutionalReference | None = None
service_binding: ServiceBinding | None = None
receipt_id: str | None = None
replayed: bool = False
metadata: Mapping[str, object] = field(default_factory=dict)
def __post_init__(self) -> None:
if not self.tenant_id or not self.instance_id:
raise InstitutionalContextError(
"A Form instance requires tenant and instance identities."
)
if self.revision < 1:
raise InstitutionalContextError(
"A Form instance revision must be positive."
)
if self.status not in FORM_INSTANCE_STATUSES:
raise InstitutionalContextError(
f"Unsupported Form instance status: {self.status!r}."
)
if (
self.definition_ref.kind != "form"
or self.definition_ref.owner_module != "forms"
or self.definition_ref.tenant_id != self.tenant_id
or not self.definition_ref.version
):
raise InstitutionalContextError(
"A Form instance requires an exact same-tenant Forms definition."
)
if self.service_ref is not None and (
self.service_ref.kind != "service"
or self.service_ref.tenant_id != self.tenant_id
or not self.service_ref.version
):
raise InstitutionalContextError(
"Form instance Service provenance must be exact and same-tenant."
)
for item in (*self.attachment_refs, *self.signature_refs):
if item.tenant_id != self.tenant_id:
raise InstitutionalContextError(
"Form instance evidence cannot cross tenants."
)
for item in self.handoff_refs:
if item.tenant_id != self.tenant_id:
raise InstitutionalContextError(
"Form instance handoff references cannot cross tenants."
)
@property
def reference(self) -> InstitutionalReference:
return InstitutionalReference(
kind="form_submission",
owner_module="forms_runtime",
object_id=self.instance_id,
tenant_id=self.tenant_id,
version=str(self.revision),
valid_at=self.recorded_at,
)
def with_replay(self) -> "FormInstance":
return replace(self, replayed=True)
def to_dict(self, *, include_values: bool = True) -> dict[str, object]:
return {
"reference": self.reference.to_dict(),
"tenant_id": self.tenant_id,
"instance_id": self.instance_id,
"revision": self.revision,
"status": self.status,
"definition_ref": self.definition_ref.to_dict(disclose_label=True),
"values": dict(self.values) if include_values else {},
"validation_results": [dict(item) for item in self.validation_results],
"attachment_refs": [
item.to_dict(include_inspection=False) for item in self.attachment_refs
],
"signature_refs": [
item.to_dict(include_inspection=False) for item in self.signature_refs
],
"handoff_refs": [item.to_dict() for item in self.handoff_refs],
"service_ref": (
self.service_ref.to_dict() if self.service_ref is not None else None
),
"service_binding": (
self.service_binding.to_dict()
if self.service_binding is not None
else None
),
"receipt_id": self.receipt_id,
"recorded_at": self.recorded_at.isoformat(),
"change_reason": self.change_reason,
"created_by": self.created_by,
"changed_by": self.changed_by,
"replayed": self.replayed,
"metadata": dict(self.metadata),
}
__all__ = ["FORM_INSTANCE_STATUSES", "FormInstance"]