Skip to content
C.W.K.
Stream
Lesson 05 of 06 · published

Doors In — the Share Sheet, the Microphone, and the Partial Share

~13 min · share-extension, stt, honest-failure, app-group

Level 0Curious
0 XP0/80 lessons0/18 achievements
0/100 XP to next level100 XP to go0% complete

The app is not the only way in

A desktop client has one door: the window. A phone has several, and two of them matter here — the system share sheet, which lets any other app hand something to Pippa, and the microphone, which lets Dad speak instead of typing.

Both doors turned out to teach the same lesson, from opposite directions: the honest report of a partial result beats a clean-looking total one.

What a share sheet actually hands you

The first defect is subtler than it looks. When another app shares something, the system describes each attachment by the types it conforms to — and a shared file also conforms to url, because it has a location on disk. So a naive chain that asks "is this a link?" first, and a photo second, takes every photo as a link and drops the image.

That is a real bug a sibling app shipped first. The fix is to ask what each provider is — ranking the registered types, with link considered last — before loading anything. The shared kit now owns that ranking, so the whole household gets the answer once.

The extension cannot open its host

An iOS share extension is a separate process with a real constraint: it cannot launch the app it belongs to. So the honest promise it can make is not "posted" — it is "saved to Pippa".

The mechanism is a drop box in a shared container: one directory per share, media written first, the manifest written last through a single atomic write. Manifest-last means a half-written share is invisible rather than corrupt — there is no moment where a readable manifest names bytes that are not there yet. On the next foreground, the app lists what is pending and offers Post as is, Edit or Discard.

The partial share, and where the words live

Here is the part worth the lesson. Loading an attachment can time out. In the first version, one attachment past its deadline threw out of the collection step — and the extension wrote nothing at all. Eight photos shared, one slow, zero saved.

The policy now: save what arrived, and record every attachment that did not, with why. Timeouts, unreadable items, items over the limit, and the app's own staging drops — an undecodable photo, a ninth photo when eight is the limit, a second clip. The banner shows that line above the three buttons.

Principle: The words about what was lost live in the saved record, not in an alert inside the extension. The record is where Dad acts on it, and the record outlives the sheet. A message that appears where the decision is not being made has been delivered to nobody.

The same instinct governs the reading side. When the app lists pending shares it returns the readable ones and the manifests that would not parse, each with its reason — and the Stream tab shows a line saying so. Nothing is deleted. A queue that is quietly wrong is worse than one that says it is wrong; that sentence has now earned its place twice in this track, once in the outbox and once here.

One more small piece of durability: a share record decodes with defaults for every field except the three that identify it. So a manifest written by an older version of the extension still reads after the app gains a field. The extension and the app update on the user's schedule, not yours.

The microphone, and where the audio goes

Voice input is the second door. The button records, the file goes to cwkPippa's own transcription route, and the transcript lands in the composer for Dad to read before sending.

The interesting decision is where the audio travels. It does not go from the phone to a speech vendor. It goes to the household engine, which hands it to the voice sibling that already holds the family's credentials for exactly this. One place in the house knows that key; the phone knows the house.

And the language is the composer's pick, forwarded explicitly — never auto-detected. Auto-detection on a bilingual household is a coin flip that fails silently on short utterances, and a wrong-language transcript looks like a bad microphone rather than a wrong setting. Two microphone buttons, Korean and English, and the ambiguity never exists.

A phantom worth naming: dictated text arrived carrying an invisible object-replacement character — the placeholder iOS leaves where an attachment would sit. It looked like a mysterious empty attachment, and a sister brain spent real time hunting an attachment that did not exist. The fix is one strip before the text leaves the phone. Name the ghost in the commit, or the next reader re-hunts it.

Code

Deciding what a shared item IS·text
Every shared FILE also conforms to `url` (it has a disk location).

  WRONG   if isLink      -> take as link      <- every photo lands here
          else if isImage-> take as image

  RIGHT   rank the registered types, link considered LAST,
          and decide BEFORE loading any bytes

The sibling app that shipped the wrong order silently
dropped every shared photo as if it were a link.
Saving a partial share honestly·text
share of 8 photos + 1 clip, one attachment times out

  BEFORE  one timeout throws out of collect()
          -> extension writes NOTHING
          -> 8 good attachments lost, no trace

  AFTER   staged + saved, every loss recorded in `missed`:
            deadline exceeded · unreadable · over the limit
            undecodable photo · 9th photo · 2nd clip
          -> banner shows the missed line above
             [Post as is] [Edit] [Discard]

write order: media first, manifest LAST, one atomic write
  -> a half-written share is invisible, never corrupt

Exercise

Find an ingest path in your own system that processes a batch — an upload, an import, a webhook with several items. Check what happens when item four of nine fails. If the answer is that the whole batch is rejected, decide whether that is a real requirement or just the shape the first version took.
Hint
Then ask the second question: where does the user find out WHICH item failed, and is that the same place they will act on it?

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.