Fix a speculation rule that excluded every URL

The query-string exclusion was written as the pattern string "/*\?*",
meaning "any path, then a literal ?, then anything". It never meant that.
A URL pattern string is split into components before escapes are resolved,
so the ? still ends the pathname: the pattern parses as pathname `/*` with
search `*`, and search `*` matches the empty query too. Sitting inside a
`not`, it excluded every same-origin URL, so both rules reduced to
`(matches) AND NOT (everything)` and no link was ever speculated.

Filter on the query with the component form instead, whose parts are
separate by construction. Name `pathname` alongside `search`: an object
that omits it inherits `/` from the document URL and matches nothing —
the same silent failure wearing different clothes.

Also prerender /issues, which `/issues/*` does not cover.

The MDN example this was modelled on, "/*\?*(^|&)add-to-cart=*", does
work, because what follows the ? lands in the search component and says
something there. Only the bare * collapsed.

Verified by evaluating the shipped JSON through URLPattern: /, /issues,
/issues/<date> and its chapters prerender; ?page=2, /logout, /rate and
/static/* do not; /dashboard* prefetches. Covered by a test that rejects
a ? in any href_matches string and a `search` component without its
`pathname`; it fails on the old rules.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0164rQrMUZkf7uV1VGYuCFy4
This commit is contained in:
2026-09-05 04:42:25 +00:00
co-authored by Claude Opus 5
parent 6c2d74c734
commit a72f036bd1
2 changed files with 95 additions and 3 deletions
+21 -3
View File
@@ -4,8 +4,17 @@
"source": "document",
"where": {
"and": [
{ "href_matches": ["/", "/issues/*"] },
{ "not": { "href_matches": ["/logout", "/rate", "/static/*", "/*\\?*"] } }
{ "href_matches": ["/", "/issues", "/issues/*"] },
{
"not": {
"href_matches": [
"/logout",
"/rate",
"/static/*",
{ "pathname": "/*", "search": "(.+)" }
]
}
}
]
},
"eagerness": "moderate"
@@ -17,7 +26,16 @@
"where": {
"and": [
{ "href_matches": ["/dashboard", "/dashboard/*"] },
{ "not": { "href_matches": ["/logout", "/rate", "/static/*", "/*\\?*"] } }
{
"not": {
"href_matches": [
"/logout",
"/rate",
"/static/*",
{ "pathname": "/*", "search": "(.+)" }
]
}
}
]
},
"eagerness": "moderate"