feat: the route report sends the noindex static paths (tracer)

- noindexStaticRoutes: requiresAuth, noindex/none seo.robots and static
  pages under seo.noindexRoutes, i18n copies included, never patterns or
  the layer's HTML sitemap pages (G1, gap-2 contract)
- #seo-routes exports noindexPaths; routeReportBody(paths, noindex) answers
  {routes, noindex} with the same limits and keeps the JSON body within the
  older plugin's 4,113,024 bytes, dropping noindex entries first
- smoke grammar noindex= and lacksnoindex=; README carries the contract
This commit is contained in:
Jakub Zych
2026-11-04 22:40:38 +01:00
parent b3a0078fb0
commit 7a26692001
9 changed files with 206 additions and 43 deletions

View File

@@ -81,8 +81,10 @@ noreport /stary
# The route report at server start: the static paths with the token, not
# the signed-in page, the page with a noindex seo.robots or the declared
# noindex route. The build matches the site answer: no drift warning.
routereport 1 has=/ has=/blog has=/plain has=/about lacks=/konto lacks=/szkic lacks=/prywatne lacks=/mapa-strony
# noindex route; those three go in its noindex list (G1), never an
# indexable path or the layer's HTML sitemap page. The build matches the
# site answer: no drift warning.
routereport 1 has=/ has=/blog has=/plain has=/about lacks=/konto lacks=/szkic lacks=/prywatne lacks=/mapa-strony noindex=/konto noindex=/szkic noindex=/prywatne lacksnoindex=/ lacksnoindex=/mapa-strony
log [vue-seo-layer] drift::0
# L1 breadcrumbs: a layout instance (app.vue) and a page instance render

View File

@@ -12,10 +12,12 @@
// resolves PATH N the API has seen exactly N resolve calls for PATH so far
// (PATH * counts every resolve call)
// apicalls N the API has seen exactly N requests so far
// routereport N [has=PATH]... [lacks=PATH]...
// routereport N [has=PATH]... [lacks=PATH]... [noindex=PATH]... [lacksnoindex=PATH]...
// exactly N route reports (POST /registry/routes) reached
// the API by the end of the run, each with the token;
// every has= path is in the last one, no lacks= path is
// every has= path is in the last one's routes, no lacks=
// path is; every noindex= path is in its noindex list, no
// lacksnoindex= path is
// log TEXT:N the server's output holds exactly N occurrences of TEXT
// (waits up to 3 s for them; N after the last colon)
// A value runs until the next ` contains=`, ` notcontains=`, ` count=`,
@@ -235,9 +237,9 @@ async function main() {
}
const routePosts = () => api.requests.filter((r) => r.method === 'POST' && r.url.endsWith('/registry/routes'))
for (const line of routeReports) {
const m = /^routereport\s+(\d+)((?:\s+(?:has|lacks)=\S+)*)$/.exec(line)
const m = /^routereport\s+(\d+)((?:\s+(?:has|lacks|noindex|lacksnoindex)=\S+)*)$/.exec(line)
if (!m) {
failures.push(`${line}: expected "routereport N [has=PATH]... [lacks=PATH]..."`)
failures.push(`${line}: expected "routereport N [has=PATH]... [lacks=PATH]... [noindex=PATH]... [lacksnoindex=PATH]..."`)
continue
}
const want = Number(m[1])
@@ -246,11 +248,15 @@ async function main() {
const posts = routePosts()
if (posts.length !== want) failures.push(`${line}: the API saw ${posts.length} route reports`)
if (posts.some((r) => r.authorization !== `Bearer ${FIXTURE_NOTFOUND_TOKEN}`)) failures.push(`${line}: a route report carried the wrong token`)
const last = /** @type {any} */ (posts[posts.length - 1]?.body)?.routes ?? []
const lastBody = /** @type {any} */ (posts[posts.length - 1]?.body)
const last = lastBody?.routes ?? []
const lastNoindex = lastBody?.noindex ?? []
for (const opt of (m[2] ?? '').trim().split(/\s+/).filter(Boolean)) {
const [key, path] = [opt.slice(0, opt.indexOf('=')), opt.slice(opt.indexOf('=') + 1)]
if (key === 'has' && !last.includes(path)) failures.push(`${line}: ${path} is not in the report ${JSON.stringify(last)}`)
if (key === 'lacks' && last.includes(path)) failures.push(`${line}: ${path} is in the report ${JSON.stringify(last)}`)
if (key === 'noindex' && !lastNoindex.includes(path)) failures.push(`${line}: ${path} is not in the report's noindex list ${JSON.stringify(lastNoindex)}`)
if (key === 'lacksnoindex' && lastNoindex.includes(path)) failures.push(`${line}: ${path} is in the report's noindex list ${JSON.stringify(lastNoindex)}`)
}
}
if (api.requests.some((r) => r.url.endsWith('/notfound') && r.authorization !== `Bearer ${FIXTURE_NOTFOUND_TOKEN}`)) {