The pattern
This project has shipped the same failure four times in different clothes:
| What the app knew |
What it showed |
| the session was refused as busy |
"Disconnected. Reconnecting…" (#70) |
| the display was placed to the left |
nothing at all (#71) |
| capture was idle, not dead |
restarted capture every six seconds (#63) |
| the receiver was caught up, not congested |
cut the bitrate to the floor (#60) |
Each time, the specific fact existed somewhere in the process and the interface displayed a generic one. Each time, a user reasonably concluded the app was broken — because from outside there is no difference between occupied and broken, or between on the other side and not working.
Two of those cost a real session to diagnose this week.
What to do
Go looking for the rest, deliberately, before someone finds them the expensive way.
Places worth reading with this specifically in mind:
- Every
catch that produces a message. Does it say what failed, or that something failed?
- Every retry loop. Does it distinguish refused from dropped from timed out? Those have different remedies and are routinely collapsed into one.
- Every state derived from silence. Nothing arriving is not the same as something being wrong — that assumption produced two of the four above.
humanise() in windows/src/errors.ts, which does this well for transport errors. The question is what reaches it and what bypasses it.
- The Mac's
state = .failed(...) paths. How much of the underlying error survives to the popover?
What a good fix looks like
Not a message per symptom. That is how the first attempt at #70 went wrong: a boolean guarding one message, which fixed the instance somebody noticed and left every other reason exposed. busy was the next one.
The version that held was a single function deciding the question for all reasons, so a new one cannot be added without deciding what the user sees. refusalExplanation and disconnectStatus in errors.ts are the shape to follow.
Why it is a good first issue
It needs no new subsystem knowledge — it needs someone reading the code while asking one question. The fix for any individual finding is usually small. Finding them is the work, and a list is a useful contribution even without the fixes.
The pattern
This project has shipped the same failure four times in different clothes:
Each time, the specific fact existed somewhere in the process and the interface displayed a generic one. Each time, a user reasonably concluded the app was broken — because from outside there is no difference between occupied and broken, or between on the other side and not working.
Two of those cost a real session to diagnose this week.
What to do
Go looking for the rest, deliberately, before someone finds them the expensive way.
Places worth reading with this specifically in mind:
catchthat produces a message. Does it say what failed, or that something failed?humanise()inwindows/src/errors.ts, which does this well for transport errors. The question is what reaches it and what bypasses it.state = .failed(...)paths. How much of the underlying error survives to the popover?What a good fix looks like
Not a message per symptom. That is how the first attempt at #70 went wrong: a boolean guarding one message, which fixed the instance somebody noticed and left every other reason exposed.
busywas the next one.The version that held was a single function deciding the question for all reasons, so a new one cannot be added without deciding what the user sees.
refusalExplanationanddisconnectStatusinerrors.tsare the shape to follow.Why it is a good first issue
It needs no new subsystem knowledge — it needs someone reading the code while asking one question. The fix for any individual finding is usually small. Finding them is the work, and a list is a useful contribution even without the fixes.