"A question without its image is a different question. If they can be saved separately, they can be corrupted separately."
The Half-Saved Question
Imagine capturing the question and the image as two independent writes. The text saves; then the app is killed before the image blob is written. Now the outbox holds "Which of these is sharper?" with no image attached. When it finally syncs, Pippa gets a question that is literally unanswerable — the referent is gone. The user's intent has been silently corrupted, not by losing everything, but by losing part of one indivisible thing.
Capture-first fixes this by treating the question and all its attachments as a single aggregate: one unit that is written completely or not at all. There is no valid intermediate state where the text exists but an image doesn't. Either the whole turn is durable, or the submit hasn't happened yet.
Aggregate Means One Consistency Boundary
The word comes from domain modeling: an aggregate is a cluster of data that must stay internally consistent and is only ever modified as a whole. For a Pippa Go turn, the consistency rule is simple and strict — a question and its referenced images are meaningless apart. So they share one boundary:
- One commit writes the question text and every image blob and the attachment references, together.
- If that commit can't complete, it rolls back to nothing — no orphan text, no orphan blobs.
- Downstream, delivery and retry always move the whole aggregate, never a fragment.
Why Atomicity Beats 'Just Re-attach'
A tempting shortcut is to let the pieces save separately and "reconcile later" — re-attach the image if it's missing. But reconciliation is where bugs breed: which image? attached to which question? what if two turns are in flight? The atomic aggregate deletes the entire problem class. There's no reconciliation because there was never a moment of inconsistency to reconcile. One write, one boundary, one intent — kept whole from the instant the user hit submit.