Defects that are invisible in the source and obvious in a browser
Some interface defects are not in the code. They are in what two correct components do when composed, in state a browser remembered from an earlier visit, or in the absence of anything calling a function that works perfectly. Three of those are recorded here, each with a check that takes about thirty seconds and finds it every time.
Why reading the source cannot find them#
A review reads files. These three defects are properties of a *running* page, and each has a different reason for being invisible on the page it would have to be spotted on.
- Composition
- Two components that are each correct produce a wrong result together. Neither file contains the defect; the overlap does, and the overlap only exists at run time.
- Remembered state
- The input is in the visitor's browser rather than in the repository. The code is the same for everyone and the outcome is not.
- Absence
- The capability exists and works. What is missing is anything that calls it, and nothing in the module that owns it looks wrong.
A fourth reason belongs in the same family and has its own note: a style rule that is present, valid and beaten at run time by a same-named token loaded later — see focus rings that computed to none.
Three defects, and the check for each#
| Defect | In the source | In the browser | The check |
|---|---|---|---|
| A stack of notifications covering the launcher | Both components correct in isolation; neither knows about the other | The control could not be reached while notifications were on screen | Raise the notifications the way ordinary use raises them, then try to reach the control |
| A remembered panel size hiding the launcher | No defect at all — the size is read from stored preferences | Correct for a first-time visitor, broken for a returning one | Look once with a fresh profile and once with a returning one; they are different products |
| A capability with nothing calling it | Present, working and reachable by identifier | No route on any screen reached it, so for that audience the feature did not exist | Search for the *call sites*, not the definition, and then try to reach it as a user |
Two of the three were found in about half a minute of looking at a changed screen as each audience, having been invisible to code review. The third is the operator's missing account-connection flow described in one implementation, two audiences.
The check, as a procedure#
Bring up the application against a test database and open the changed screen with a real session for each audience. Sign-in is Google OAuth only — there is no password login — so a local check uses a minted session rather than a form.
Result Both audiences are in front of you at once, which is what turns "works for me" into a claim about the product rather than about one session.
Use the screen the way the defect would be met: raise the notifications, resize the panel, reload with what the browser remembers.
Result Composition and remembered state only produce their defects under those conditions, and a fresh profile hides both.
Reach every control with the keyboard as well as the pointer.
Result A click and a Tab do not produce the same focus state, and a control that is reachable one way and not the other is the ordinary case rather than the exotic one.
Read the events the page emits rather than the configuration it loaded — a registration, a request, a state change.
Result Every state the dialer shows comes from a real event rather than from a click, which is the property that makes the silent-failure case visible at all.
What this check does not replace, and what it costs#
- It is not enumeration. A browser pass on one screen says nothing about the other forty; the parity comparison over the running route table is what covers those.
- It is not a performance measurement. Query cost is counted in statements against a fixture, not felt on a warm local machine.
- It is one pass per audience, once, after the change is final. Re-running a check that passed because unrelated code moved is repetition, not rigour.
- It proves this build. A defect from remembered state can return the moment a stored preference changes shape, which is an argument for treating stored state as an input with its own cases rather than as background.
- UNKNOWN: no figure is published for the share of interface defects this finds. What is recorded is that two of three defects in one release were invisible in code and obvious in the browser.
Questions#
Can a linter or a type checker catch these?
Not this class. A linter reads a file; two of the three defects here exist only when independently correct pieces are composed at run time, and the third is an absence — nothing calls a function that is itself faultless.
Why look as both audiences rather than once?
Because the paths differ. A customer session reaches a rewritten path and an operator session does not, so a screen can be complete for one and missing a control for the other with no difference in the shared code beneath them.
Is a screenshot enough?
Rarely. A screenshot captures one state, and these defects live in transitions and remembered preferences — notifications raised, a panel resized, a return visit. What settles them is interacting with the page in the state the defect needs.