feat(poll): extend response editing contract

This commit is contained in:
2026-07-20 18:08:58 +02:00
parent 9b5418db78
commit 2f559e3f0b
2 changed files with 75 additions and 0 deletions

View File

@@ -58,6 +58,21 @@ class PollUpdateCommand:
closes_at: datetime | None
@dataclass(frozen=True, slots=True)
class PollOptionUpdateCommand:
"""Complete mutable option snapshot supplied by an owning module.
Providers must treat an exact repeat as a no-op. When the snapshot
changes, answers for this option are invalidated while answers for other
options are retained.
"""
label: str
description: str | None = None
value: Mapping[str, object] | None = None
metadata: Mapping[str, object] = field(default_factory=dict)
@dataclass(frozen=True, slots=True)
class PollInvitationCommand:
respondent_id: str | None = None
@@ -102,6 +117,14 @@ class PollInvitationRef:
token: str
@dataclass(frozen=True, slots=True)
class PollAnswerRef:
option_id: str | None = None
option_key: str | None = None
value: object = None
rank: int | None = None
@dataclass(frozen=True, slots=True)
class PollResponseRef:
invitation_id: str | None
@@ -110,6 +133,9 @@ class PollResponseRef:
# consumer can use it to reconcile an authenticated response without
# trusting client-supplied invitation metadata.
respondent_id: str | None = None
# Optional for backwards compatibility. Providers that support response
# editing expose the authoritative, still-valid answers here.
answers: tuple[PollAnswerRef, ...] = ()
@runtime_checkable
@@ -144,6 +170,19 @@ class PollSchedulingProvider(Protocol):
) -> PollRef:
...
def update_option(
self,
session: object,
*,
tenant_id: str,
poll_id: str,
option_id: str,
command: PollOptionUpdateCommand,
) -> PollOptionRef:
"""Update one option and invalidate only answers for that option."""
...
def open_poll(self, session: object, *, tenant_id: str, poll_id: str) -> PollRef:
...