Skip to main content

Week 4 Studio: No idea how long

Three honest ways to say "still going" when there is no denominator at all, and the rule that none of them may imply a fraction.

18 March 2027

Last week’s flag has gone false.

The simulator can now hand you a transfer where lengthComputable is false: a stream of unknown length, the shape you get when a server is generating a file as it sends it. There is no total. There will not be one. The upload might take four seconds or four minutes, and nothing on your machine knows which.

The interface still has to show something. The temptation is to show a bar anyway — a bar that creeps to 90% and waits, a spinner that speeds up near the end. Both of those invent a denominator. This week is about the three things you can say instead, all of which are true.

By the end of this week

You can:

The idea

Tuesday’s lecture, Saying Nothing, Precisely, is the teaching. The three registers, restated so you have them at the machine:

RegisterAssertsRequiresSays nothing about
Livenesssomething is still happeninga heartbeat eventposition, duration, or whether it will succeed
Elapsedyou have been waiting this longa clockthe process at all — it is a fact about the user
Named stagethis thing is happening nowthe week 2 state modelhow many stages remain

Elapsed is the one people skip, and it is the strongest of the three, because it is the only one that cannot be wrong. It is also the one that makes a stall visible without your having to detect a stall — a counter that reaches 0:45 on a process that usually takes 0:06 has communicated a problem with no error handling whatsoever.

The fractional-reading trap. An indeterminate display must not admit a fractional reading, and the test is what a reader can take from it, not what the code intends:

If a user can form a ratio from it, you have made a determinate claim with indeterminate data. That is the one hard constraint on today’s work.

View this week’s slides — Tuesday’s lecture deck. Worth a pass before the studio, and the reference while you build. On a phone they are small — the deck is built for a projector, and this page carries the same material as prose.

In the room

Thursday 18 March, 14:00–17:00. Tuesday’s lecture is the teaching; today is the build.

TimeWhat happens
14:00Fraction hunt (20 min). Six indeterminate treatments on the projector, none containing a number. Vote on which ones admit a fractional reading. The room usually disagrees, which is the lesson.
14:20Build. Three treatments.
16:15Rule-writing (20 min). In pairs, draft the permission rule. Swap and try to find a case your partner’s rule handles wrongly.
16:45Read two rules aloud.

What you start with

What you build

  1. Three treatments against the unknown-length stream: liveness, elapsed, and named stage. Each independently selectable so they can be compared.
  2. A fraction audit of your own three — including the document title and the favicon, which are where fractions survive a cleanup.
  3. A permission rule, one paragraph, saying which treatment is allowed when. “Named stage when the state model can name the current stage; elapsed always; liveness only when neither of the others is available” is the shape. Yours should differ and should be defensible.

A worked example

The same moment in the unknown-length stream, in each of the three registers:

liveness      ◆ ◆ ◆ ◆         "Still uploading"
elapsed       0:12            "Uploading — 12 seconds so far"
named stage   ▣ read ▣ hash ▶ transfer     "Transferring"

All three are true at t = 12 s, and none implies a fraction. The fourth thing most people build — a bar creeping to 90% and waiting — implies one, and has no event behind it.

The stream’s length is withheld by the simulator; nothing is transferred.

Done when

The mistake to expect

Reaching for value="0" when there is no value.

<div role="progressbar" aria-valuenow="0">              <!-- "nothing has happened" -->
<div role="progressbar" aria-valuetext="Transferring, total unknown">

Omitting aria-valuenow is how the platform spells indeterminate. Setting it to zero is a different claim, and on a stream four stages in it is a false one. This exact line is audited in week 7.

Before next week

About two to three hours.

  1. Apply your own rule to your week 3 determinate prototype. It should tell you which treatment appears when the denominator runs out near the end — the 99%-forever case from week 1. Make that transition work.
  2. Week 5 uses a supplied transfer trace. Pull it (git pull on upload-ui) and check the plotting harness runs before Thursday.

If you are joining late

git checkout stage-04 gives you a prototype with the state model, a byte-counted bar, and the unknown-length stream wired into the simulator but unhandled — it currently renders a bar stuck at zero. It is a floor, not an answer: the three treatments and the rule are yours.

What this week cannot tell you

Whether users prefer any of these, or understand any of them.

You have built three truthful displays. Truthful is not the same as comprehensible, and nothing today tested comprehension. Two later weeks get at it from different directions: week 6 compares how they feel, with results weaker than you will want them to be, and week 11 puts them in front of someone who has never seen them.

There is also a real cost you cannot measure today. Elapsed time is the most honest register and it is the one that makes a wait feel longest. That trade is the course’s subject and this week does not resolve it.

Reading

The spec

What you bring to the session. Written so a reader can tell whether it has been met without asking you.

Teaching team