Follow-ups from the #34 and #37 reviews - #39
Conversation
2da474a to
4409abb
Compare
…two tests that prove something Four follow-ups the reviews of #34 and #37 left open. The gate that decides whether this pass owns a path and the parser that reads the code out of it both asked whether a suffix names a file, with two different sets: the gate carried jpg|jpeg|webp|ico|txt|xml that the parser lacked, the parser carried html that the gate lacked. So /invite/AB.HTML passed the gate and then lost its code, while /invite/AB.JSON never reached the gate at all. Both read one constant now, and a case asks the two as a single question across every suffix — the sweep includes html, a suffix that names no file type, and a mixed-case spelling — so a set that grows on one side and not the other fails there rather than in production. The two still ask it of different things, deliberately: the gate of the whole path, because /invite/AB12CD/logo.png is an asset request whoever owns the first segment, and the parser of the code segment alone. A case pins that difference as well as the agreement. html is not in the list for one reason: a code that happens to end in .HTML stays a code. The shell needs no help from the list — the parser names index.html outright — and the 308 that canonicalises it comes from the platform and is handed on either way. public/_headers had a rule for /invite/ and another for /invite/*, and the first matches the second. Every answer that matched both carried the value twice: measured on the deploy, /invite/ answered cache-control: public, max-age=60, public, max-age=60 Pages concatenates what every matching rule says rather than letting one win, and a parser takes the first. The rules the wildcards already cover are gone, the bare paths keep theirs, and /invite/invite.js keeps its own rule above the wildcard — the restatement below it, added when the match order was thought to be uncertain, only appended a third value nobody reads. check-site.mjs now requires the wildcard, rejects a rule the wildcard covers, and rejects the same exact path declared twice, which its own header parser had been merging out of sight. Two tests could not tell a working build from a broken one. The clipboard stub resolved and discarded what it was handed, so the case named after copying the canonical invite URL passed on any string, or on none; it records now, and the case requires exactly one write, equal to the href the canonical link names. And the fifteen-second lookup budget was asserted against its own constant and nowhere else: a request that never answers now has to leave the loading state by itself, and the case measures how long that took against the budget the page itself reports.
4409abb to
6cb08cd
Compare
The comment said the budget is read from the page rather than restated here, and the line under it restates it. Both belong there — the size is pinned outright, because bounds computed from the page's own number would follow it anywhere, and the elapsed time is measured against that number so another timer cannot pass for this one. The comment now says that instead of denying half of it.
The sweep's comment implied it catches any divergence between the two sides, where it walks a list of its own and catches a divergence on what it enumerates. The .PDF case called it a dot that names no file type, where PDF is a file type this rule simply does not call an asset. And the timeout case said the budget was asserted against itself, where the unit suite pinned it against a literal and went no further.
…it does The covered-path check listed the four rules that happened to be there, so a rule added later would have slipped past it. It now rejects any exact path a landing wildcard covers, with the script's own rule kept on purpose: it wants a longer cache than the shells, and a parser takes the first of the two values. Proven by adding a rule for /invite/foo and watching it fail. The budget case took its timestamp before the navigation, so a slow page load counted against the budget and could push the upper bound over on a busy machine. It starts when the page says it is checking, which is when the timer the case is about was armed.
|
EN. Ready. Four lanes across two vendors report nothing that changes what a visitor gets; what they did find was a run of my own sentences claiming more than the code beside them held, and those are corrected. Every behavioural claim here is measured: the cache values on a preview deployment, both new tests by mutation, and the new site check by adding the rule it is meant to reject. DE. Freigegeben. Die Prüfungen melden nichts, was für Besucher einen Unterschied macht. Gefunden wurden vor allem eigene Formulierungen von mir, die mehr behaupteten als der Code daneben hält; die sind korrigiert. What was measuredOn a preview deployment of this branch:
Before it, Each new guard was made to fail on purpose:
What the review foundNo lane found anything behavioural, on any round. What they did find, and what is corrected here:
|
EN. The four items the reviews of #34 and #37 left open, none of which changes what a visitor sees today: one list where there were two disagreeing ones, one cache rule where two matched the same request, and two tests that could not tell a working build from a broken one.
DE. Die vier Punkte, die aus den Reviews von #34 und #37 offen geblieben sind. Für Besucher ändert sich nichts: eine Liste statt zweier widersprüchlicher, eine Cache-Regel statt zweier für dieselbe Anfrage, und zwei Tests, die vorher nichts bewiesen haben.
Two lists that disagreed
The gate that decides whether the Function owns a path and the parser that reads the code out of it both ask whether a segment names a file, and they asked it with different lists — one carried
htmland not the image types, the other the reverse. So/invite/AB.HTMLpassed the gate and then lost its code, while/invite/AB.JSONnever reached the gate at all.The real difference was narrower than it first looked: the gate carried
jpg|jpeg|webp|ico|txt|xmlthat the parser lacked, the parser carriedhtmlthat the gate lacked.Both read one constant now, and a case asks the two as a single question across every suffix — the sweep includes
html, a suffix that names no file type, and a mixed-case spelling — so a set that grows on one side and not the other fails there rather than in production.They still ask it of different things, deliberately: the gate of the whole path, because
/invite/AB12CD/logo.pngis an asset request whoever owns the first segment, and the parser of the code segment alone. A case pins that difference as well as the agreement.htmlis not in the list for one reason: a code that happens to end in.HTMLstays a code. The shell needs no help from the list — the parser namesindex.htmloutright — and the308that canonicalises it comes from the platform and is handed on either way.One cache rule instead of two
public/_headerscarried a rule for/invite/and another for/invite/*, and the first matches the second. Every answer that matched both carried the value twice — measured on the deploy:The rules the wildcards already cover are gone; the bare
/inviteand/promokeep theirs, because a wildcard does not match them.scripts/check-site.mjsnow requires the wildcard and fails if a covered rule comes back. Measured on a preview deployment of this branch, the landing paths each carry the value once.Pages concatenates what every matching rule says rather than letting one win, and a parser takes the first.
/invite/invite.jstherefore keeps its own rule above the wildcard, and the restatement below it is gone: it was added when the match order was thought to be uncertain and only appended a third value nobody reads. On production the zone's Browser Cache TTL replaces the lot withmax-age=14400anyway.The checker also rejects the same exact path declared twice, which its own header parser had been merging out of sight — proven by adding a duplicate block and watching it fail.
Two tests that proved nothing
The clipboard stub discarded what it was handed.
writeText: () => Promise.resolve()— so the case named after copying the canonical invite URL passed on any string, or on none; what it actually checked was the label beside the button, which is written from the DOM. The stub records now, and the case requires exactly one write, carrying the code, equal to the canonical link. Verified by mutation: makingcopyLinkHref()return the bare code turns it red.The fifteen-second lookup budget was asserted against its own constant.
expect(LOOKUP_TIMEOUT_MS).toBe(15000)and nothing else — no case established that a request which never answers ever leaves the loading state. One does now: the endpoint is routed and never fulfilled, the page still says it is checking ten seconds in, and the unavailable state has to appear before the twenty-second mark. Verified by mutation: raising the budget turns it red.The fake clock does not work here — the budget's timer is armed while the page loads — so the case runs in real time and carries its own longer timeout.