C.W.K.
Stream
Lesson 03 of 04 · published

All-or-Error: Never Silent Text-Only

~11 min · failure-handling, all-or-error, no-silent-downgrade, honesty

Level 0Dead Zone
0 XP0/32 lessons0/12 achievements
0/100 XP to next level100 XP to go0% complete
"If you can't send the image, don't quietly send the question without it. A question that lost its picture is a different, wrong question."

The Silent Downgrade Trap

Image handling has more failure points than text: staging can fail, resolution can fail, encoding can fail, the upload can fail. When one of these breaks, there's a tempting "graceful" fallback: send the question as text-only so something goes through. It feels robust — the user gets an answer instead of an error. But it's the honesty failure from Track 3 wearing a new outfit. The user asked about an image; you delivered a question with the image silently missing; Pippa answered a question that was never actually asked. A confident answer to the wrong question is worse than an honest failure on the right one.

All-or-Error

The rule is all-or-error: for a turn that includes images, either the whole aggregate is delivered — question and images, intact — or the client surfaces a failure and preserves the whole input for retry. There is no middle path where the text goes and the image is dropped. This mirrors the atomic aggregate from Track 2: the question and its images were captured as one indivisible unit, so they must be delivered as one too. Partial delivery is exactly as corrupting as partial capture.

  • Success: question + all images reach Pippa. The turn is answered honestly.
  • Error: something in the image path failed. Surface it, keep the full input durable, offer retry. Nothing is silently dropped.
  • Forbidden: text delivered, image quietly gone, user unaware. This path must not exist.

Why the Error Is the Kind Choice

Surfacing an image-attachment error feels less smooth than "just send the text," but it's the choice that respects the user. An explicit "couldn't attach your image — retry?" keeps them in control and keeps their question intact. A silent text-only downgrade takes the decision away and corrupts their intent behind their back. As with honest offline, the client that intends to be trusted prefers a visible, recoverable failure over an invisible, plausible wrong. Make the forbidden path unrepresentable — no code branch that sends text after the image path has failed — and the guarantee holds structurally.

Code

All-or-error: no branch that drops the image and sends text·typescript
async function deliverTurn(turn: PippaGoTurn) {
  let images: ResolvedImage[];
  try {
    images = await resolveAll(turn.attachmentIds); // stage/resolve/encode
  } catch (err) {
    // Surface + preserve. Do NOT fall through to a text-only send.
    await setStatus(turn.deviceTurnId, "failed");
    throw new AttachmentError("Couldn't attach image — input preserved, retry available");
  }
  return callCanonical({ ...turn, images }); // question AND images, together
}

// There is deliberately no `catch { sendTextOnly(turn) }`.
// The image-failed-so-send-text path simply does not exist.

External links

Exercise

Audit an upload-with-text feature for silent downgrades: what happens if the file fails to attach but the text is valid? Does it send the text anyway? Trace whether the user is told the attachment was dropped. Then redesign it as all-or-error: where do you surface the failure, how do you preserve the whole input, and what code branch do you delete to make the silent path impossible?
Hint
The silent path is usually a try/catch around the attachment that falls through to the text send. Deleting that fall-through — replacing it with surface-and-preserve — is the whole fix. If there's no code that sends text after an image failure, the downgrade can't happen.

Progress

Progress is local-only — sign in to sync across devices.
Spotted a bug or have feedback on this page?Report an Issue

Comments 0

🔔 Reply notifications (sign in)
Sign inPlease sign in to comment.

No comments yet — be the first.