Skip to main content
blink

If a recording is interrupted, nothing is lost

What happens when a recording is cut off

While you record a Blink, the audio is saved to the server as you go. So if the recording stops before you finish — you lock the phone, close the tab, take a call, lose signal — the part you had already spoken is safe.

The next time you open OrbitingFox, that recording appears as a draft Blink with a title that says what it is:

Draft — interrupted recording #3, Sep 4 8:25 AM

The number counts your interruptions in order, and the date and time tell you which one it was — useful when two get cut off on the same afternoon.

Where to find them

Drafts show up in two places, and they are the same items either way:

  • Your ordinary Blink list, mixed in with everything else, each marked with a small Draft label so you can spot it at a glance.
  • The interrupted-recordings page, which shows only the drafts, with an explanation at the top and the choices next to each one.

Your three choices

  • Keep — it becomes an ordinary Blink. The recording is attached to it, and you can rename it whenever you like; the draft title is just a starting point.
  • Edit — open it first and change the title or text, then save it as usual.
  • Delete — you did not want it. It goes to your Recycle Bin like anything else you delete, so a mis-tap is recoverable.

There is no deadline. A draft waits until you decide.

OrbitPilot and your drafts

OrbitPilot does not read a draft's contents. An interrupted recording is half a thought — you may not have finished the sentence, or you may delete it entirely — so the AI is not given it to learn from.

The moment you keep a draft it becomes an ordinary Blink, and from then on OrbitPilot treats it like any other: it can read it, unless you have marked that Blink private.

What changed, and why

Before this, an interrupted recording announced itself with a warning banner inside whatever Blink form you opened next — one banner per interrupted recording, stacked on top of each other, and the recording would be attached to whatever you happened to be writing at the time.

That was confusing in two ways: several alarms for one problem, and a recording ending up inside an unrelated Blink. Now each interrupted recording is its own item, with its own name, and you decide what happens to it.

The Blink form no longer announces them (BL-451, 2026-09-10)

Until now the Blink form carried a one-line notice — "N earlier recordings were interrupted and saved as drafts — Review them" — inside the voice-note block, between the Start recording button and its help text. The owner designed this feature as no banners at all: the drafts are visible in your Blink list (badged as drafts), on the Interrupted recordings page, and behind the small hourglass pill under the home-page capture box. The home page already hid the form's notice; the form itself kept it, and it interrupted exactly the moment it should not — while you are catching something else.

What changed. The notice is gone from the form. Nothing about the rescue changed: when you open a Blink form, the page still asks the server to check for interrupted recordings, and each one still becomes a draft Blink with an honest title. You find them where the design put them — the Blink list, the drafts page, the home-page pill — and OrbitPilot can point you at them. If you are editing an ordinary Blink while drafts are waiting, the form no longer mentions them either; the drafts page does.

For developers. The container #voice_draft_recovery_banner is removed from templates/blink/_wink_voice.html; checkDrafts() in _wink_voice_js.html keeps its voice_draft_check fetch — the GET's side effect is the materialisation, so the fetch is the rescue — and drops the banner-writing branch; the now-dead hide rule is removed from templates/home.html. The BL-396 count contract is untouched (its nine scenarios read the endpoint, not the page). Guard: blink/test_draft_form_notice_retired.py. This is Phase 0 of the home-page microphone front (GRP-104 / WO-33; repo copy docs/blink/HOME-PAGE-MIC-DESIGN.md).

Telling your drafts apart without opening them (BL-464, 2026-09-11)

What changed. Every row on the interrupted-recordings page used to show a title and the time it was recorded, and nothing else. The titles are generated, so eight drafts looked like eight copies of the same thing — and the only way to decide whether to Keep or Delete one was to open it, look, and come back.

The owner's words: "then user is going to have a general idea what's inside of each of them before clicking edit or clicking on keep or clicking on delete. So that page should be more informative about the draft items."

Each row now carries

  • The start of what was said. One short line of the transcript — deliberately short, and kept to a single line however long the recording was. A list of three-line blocks would be the same problem in a different shape.
  • A play control, on any draft that still has its recording. Press it and the recording plays without leaving the page; press it again to stop.

Only one plays at a time. Pressing play on a second draft stops the first. Without that, skimming eight drafts to work out which is which leaves four recordings talking over each other and no obvious way to stop them.

The control says Play or Stop in words, not just as a shape, and the word changes with what pressing it will do. Nothing here needs hovering — there is no hover on a phone, and that lesson has its own row.

The length is not shown yet

The owner also asked for the total length of each recording. It is not here, and that is deliberate rather than forgotten: nothing stores it today, and the obvious way to add it turned out not to work for this page. It is a separate piece of work with its own row.

For developers

⚠ A draft Blink has no BlinkAudio. This is the thing to know before touching this page. materialise_voice_draft() creates the Blink and leaves the recording on BlinkVoiceDraft; a BlinkAudio is created only when the person presses Keep (promote_voice_draft → commit_voice_drafts). So the play control and the snippet both read blink.voice_draft, and prefetch_related("audios") would be N queries returning nothing. The view already select_related("voice_draft"), so the row costs no extra query — pinned by a test that counts queries for one draft against four.

The snippet reads voice_draft.transcript and not blink.description: the description is seeded from the transcript at materialise time and can then be edited, so the two drift. The transcript is what was actually said, which is what somebody scanning the list is trying to recognise.

The control is a small button plus a hidden <audio>, not a native <audio controls>: a native player is roughly 300px wide and these rows already carry Edit, Keep and Delete, so one would wrap every row at 375px. preload="none" keeps a ten-row list from fetching ten audio files on load. The shared handler lives in static/js/of-draft-play.js; a rejected play() puts the button back and says so rather than leaving it reading "Stop" over silence.

The glyphs come from the icon registry — play, pause and microphone were registered by adminapp/0080, because none of them existed. Rendering {% of_icon "play" %} against a key the registry does not hold returns the empty string outside DEBUG, which would have shipped a button with nothing in it. The same migration replaces the raw 🎙 emoji the pending-voice chip used as its affordance.

🪐 OrbitPilot

Create a free account and I'll remember your conversations — sign up

🧠 Memory status