draftDraft
The host owns purpose, category intent, reporter consent, location context, and retention policy before opening provider UI.
Open one feedback UI generation, normalize a bounded report candidate, commit an application submission, reconcile provider acknowledgement separately, review evidence, and close only with an attributable resolution.
A state is not a UI label. It determines which actor may act, what evidence exists, what may be retried, and how recovery proceeds.
draftThe host owns purpose, category intent, reporter consent, location context, and retention policy before opening provider UI.
capturingOne presented feedback generation owns UI, focus, permission prompts, callbacks, cancellation, and cleanup.
candidateThe adapter copied allow-listed category, bounded description, normalized location identity, and attachment references into application state.
submittedThe contributor deliberately committed one immutable application report with idempotency, expected version, audit, and outbox evidence.
provider_pendingA separately selected adapter has an acknowledged or unknown provider submission outcome that requires reconciliation.
review_pendingSubmission evidence and any provider acknowledgement await an attributable quality, privacy, duplication, or policy decision.
resolvedterminalAn authorized reviewer recorded the disposition and exact supporting evidence, with provider resolution only when independently proven.
rejectedterminalReview found the report invalid, duplicate, out of scope, or unsupported and preserved the reason plus evidence lineage.
cancelledterminalThe contributor ended the active attempt before application submission and every UI resource was disposed.
Commands express intent. The aggregate validates current state and invariants, commits one new version, and emits a fact in the same transaction.
create_reportHost applicationfeedback_report.createdOne external case and purpose maps to one draft aggregate across retries.
open_feedback_uiContributordraftfeedback_report.ui_openedOne command creates one active presentation generation and ownership record.
receive_candidateMappls Feedback Kitcapturingfeedback_report.candidate_receivedAccept one terminal allow-listed result for the active generation and normalized content hash.
commit_submissionContributorcandidatefeedback_report.submittedCommit report, processed command, audit event, and outbox atomically under expected version.
request_provider_submissionProvider adaptersubmittedfeedback_report.provider_requestedPersist application command and provider request identities before attempting the separately approved contract.
queue_reviewHost applicationsubmittedprovider_pendingfeedback_report.review_queuedOne immutable submission revision creates at most one active review case.
resolve_reportOperations reviewerreview_pendingfeedback_report.resolvedBind actor, disposition, exact evidence revision, audit, and notification outbox in one commit.
reject_reportOperations reviewerreview_pendingfeedback_report.rejectedOne reviewer decision applies once to one immutable report revision.
cancel_reportContributordraftcapturingcandidatefeedback_report.cancelledRepeated cancellation returns the terminal result while cleanup remains exactly-once-in-effect.
Keep provider responses, business identity, state, events, and side-effect delivery distinct so each can be reconciled safely.
Host-owned intent, lifecycle state, current immutable submission, and optimistic version.
reportIdexternalIdpurposestatesubmissionRevisionversionAllow-listed category, description, normalized location, consent, attachment references, and content identity.
submissionIdreportIdcontentHashlocationIdentityconsentVersionsubmittedAtSeparately selected contract request, acknowledgement, unknown outcome, and reconciliation evidence.
attemptIdsubmissionIdproviderRequestIdstatusreceiptReferencelastCheckedAtAttributable disposition against one exact submission and provider-evidence revision.
reviewIdsubmissionIdreviewerdecisionreasondecidedAtA UI callback creates only a candidate; it cannot prove application submission, provider receipt, publication, or resolution.
One presentation generation produces at most one accepted terminal result and all late callbacks are ignored.
Every submission revision is immutable and content-hashed; rework creates a new linked attempt.
Provider acknowledgement and reviewer disposition are separate attributable records.
Credentials, view controllers, delegates, attachment bodies, and opaque provider payloads never enter durable state.
Idempotency, optimistic concurrency, audit, outbox, privacy purpose, retention, and redaction apply to every committed transition.
Recovery changes durable truth only through the same rules as normal operation. A timeout is an unknown outcome, not evidence that nothing happened.
The active generation ends without a valid allow-listed candidate.
Dispose, restore focus, retain the draft, record a safe reason, and offer a purpose-appropriate manual fallback.
Its presentation generation differs from the report's active generation.
Ignore it, release its resources, and keep current report state unchanged.
The application has a durable request identity but no authoritative acknowledgement.
Remain provider pending and reconcile under the same identity before any retry.
Policy, privacy, duplication, location, or content validation fails for the immutable revision.
Preserve the decision and original revision; create a new linked attempt rather than editing history.
Measure state age, event health, retries, reconciliation, and sensitive-data access alongside latency and error rate.
Only explicitly indexed evidence is linked. Empty sections are not backfilled with invented endpoints or package names.
8 labs · 5 hostile scenariosmappls-feedback-kit-ios-distributionmappls-feedback-kit-ios-distribution-basemappls-feedback-uikit-ios-distributionmappls-feedback-uikit-ios-distribution-base8 verified tests