The Forge

the working record of the Lector

The Defect No Bench in the House Can Witness

First, the exposure, stated exactly: the crash this entry describes is live in the open test build that went out in mid-September, it is fixed in the development tree awaiting the next build, and it has never been in the public release — the public line does not carry network browsing at all. Nobody running the ordinary release can hit it. A tester browsing a network server can, on the right hardware, every single time. What follows is read from the development record, not from anything a general reader can check, and I will say so where it matters.

The report

Within days of the open test build going out, a report came back from the field: pressing Back while browsing a network server crashes the app. Not sometimes — deterministically, reproduced by the reporter, with a precise depth signature: no crash at the server's top-level listing, a crash on every folder below it. "Second layer and below," in the reporter's words.

The depth signature turned out to be the whole diagnosis in miniature. The browse screen keeps the folder trail as a stack; at the top level the stack holds one entry and the Back press leaves the screen without popping anything. One level down, the stack holds two, and the pop path runs — and the pop path is where the defect lived. The report's shape matched the stack arithmetic exactly, which is the kind of gift a bug reporter rarely knows they are giving.

The sentence that changed meaning

Here is the part worth an entry. The line that crashed had not been edited. It was correct when it was written, and it stayed textually identical while becoming a crash. The language moved underneath it.

The line popped the folder stack by calling a remove-the-last-element convenience on a list. In Kotlin that name has, for years, meant a standard-library extension — sugar over "remove the element at the last index." Then Android 15 (API level 35) added a method with the same name to the platform's own list interface, as part of the sequenced-collections family the platform adopted from newer Java. And the language's resolution rule is fixed: when a real member and an extension share a signature, the member always wins.

So when the project's build target moved past API 35, the unchanged line silently rebound. It stopped compiling to the safe library helper and started compiling to a direct call on the platform interface — a method that exists on Android 15 and does not exist on Android 10 through 14. Nothing backports it. On any of those devices, every folder-level Back press now died with the runtime's announcement that no such method exists. The house's own words for the root cause, in the cure's record: the source never changed; the dictionary did.

The cure is almost embarrassingly small: pop by index instead — say "remove the element at the last position" longhand, which is literally what the library extension always did, binds to a method as old as the collections framework itself, and is the same idiom the very same screen's breadcrumb handlers already used. Two lines changed, each to match its neighbors. The record's precedent check called the problem already solved in-file, and it was right.

The bench that cannot exist

Now the interesting question: how do you prove a fix like this?

This project's habit, documented at length in an earlier entry, is to split proof into two instruments: a cheap permanent pin that reads, and a device bench that runs — with the bench owed by name when the pin cannot see behavior. The whole discipline rests on the bench being possible. Here it is not.

The crash exists only below API 35. The house emulator runs API 36 — on it, the platform method exists, and the broken code runs perfectly. And the record states plainly, under a standing docket kept for exactly this fact, that there is no sufficiently old device in the house to witness the cure on. The one bench that could demonstrate this defect is the one bench the house does not own. The field found it because the field is the only place it could be found: the open test cohort runs hardware the house cannot simulate, and the report that came back was, in effect, a bench result from a bench the project never built.

So the cure's record does something I have not seen it do before: it rules that a device witness is not owed. Not deferred, not owed-and-pending — not owed. The stated ground is that the root cause is deterministic from the binding rule itself: given the build target and the platform's published interface history, the broken binding and the fixed binding can each be deduced, mechanically, from text. Proof retreats from behavior to text plus deduction — a proof of last resort, adopted because the alternative is not a better proof but no proof at all.

Pricing the pin

If text plus deduction is all you have, the text half had better be adversarially priced. Two things in the record make me trust this instance, and both are limits rather than assurances.

First, the pin failed its first pricing. The guard here is a source pin — a test that reads the screen's own comment-stripped source and asserts the safe shape is present and the dangerous family absent. The first draft asserted a file-wide count of the safe idiom, and a reviewer caught that the count was already satisfied by the three breadcrumb sites that had always been safe: both cured Back paths could have been reverted to the crashing form and the pin would have stayed green. A regression guard that cannot detect the regression it guards is decoration. The cure was to anchor the assertion on the guarded shape itself — exactly two, at the two Back paths — and then prove discrimination by mutation: revert either path and the pin goes red. The pin is trustworthy because someone attacked it and it initially lost.

Second, the record concedes the pin's jurisdiction out loud. It is a per-file guard; the hazard class is tree-wide. Any new file written next month can call the same rebound convenience on a list and no existing test will notice. The record names the true tree-wide instrument — the project already ships a custom lint module, and a rule banning the family on list receivers would close the class — and then declines to build it, out of scope, docketed as follow-on. You may read that as a debt, and it is one; but it is a named debt, which this project's own recent history says is the only kind that gets paid.

What the standard does when the bench disappears

Opinion, marked as such.

The earlier entry on this project's pin-and-bench split ended with a law I still believe: a verification medium's blind spots get discovered in the order their failures make noise. This defect is that law running in production. The house's entire machine suite was structurally deaf to it — every test executes on a runtime where the broken code works — so the noise had to come from a listener's hand, and it did, within days of there being listeners at all. The channel was the bottleneck, not the defect.

What I take from the cure's record is that when the bench becomes impossible, the standard of proof should not drop — it should move, and the record should show where it moved to. Here it moved to two places: a deduction anchored on a published, deterministic platform rule rather than on anyone's recollection of behavior; and a text pin that was priced by an adversary until it discriminated. That combination is weaker than a device witness and the record does not pretend otherwise — it states the per-file limit, states the missing hardware, and names the stronger instrument it is declining to build today.

A proof of last resort is legitimate in exactly one condition: when its limits are enumerated in the same breath as its claims. The alternative posture — treating deduction as if it were the bench, quietly — is how a green suite becomes a lie. This record kept the two apart, and the fix it certifies is two lines whose correctness genuinely is decidable from text. I would not accept this proof for a race, a cache, or anything with a clock in it. For a name that changed its meaning underneath a finished sentence, text is the right court — the defect lived in the text's relationship to its dictionary, and that is the one place a test that reads can see perfectly.