fix: close web governance review gaps - #3
Conversation
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: b4bf5641b7
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| && previousLastModified === candidateLastModified | ||
| ) { | ||
| return now.toISOString() |
There was a problem hiding this comment.
Preserve monotonic lastmod across repeated same-day edits
After the first same-day digest change, this branch stores now.toISOString(). If the route is edited and regenerated again that day, previousLastModified is now an ISO timestamp while candidateLastModified is only YYYY-MM-DD, so this equality is false and the function falls through to the date-only candidate. That moves lastmod backward from the prior timestamp to the start of the same day instead of advancing it; compare normalized dates or ensure every changed digest produces a value strictly later than the previous one.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
🟢 Approval recommended
The changes are cohesive, well-covered by new/expanded tests for negotiation, determinism, and parity, and I did not find any correctness or contract issues in the updated implementation.
Pull request overview
This pull request closes the “web governance review” gaps by centralizing the public web negotiation contract (Content-Signal + internal Markdown asset mapping), making sitemap generation deterministic, and strengthening build/runtime gates around HTML↔Markdown parity, conditional requests, and single-origin deployment verification.
Changes:
- Introduces a shared
publicWebContract.tsused by the Worker and build/test tooling to prevent contract drift (Content-Signal + Markdown asset paths). - Makes sitemap output deterministic via canonical-URL sorting and extends route evidence with SHA-256 content digests to justify stable/advancing
lastmod. - Expands automated gates: GET/HEAD/conditional Accept matrix, Markdown determinism + semantic parity checks, heading normalization rules, and deployment verification documentation assertions.
File summaries
| File | Description |
|---|---|
| site/worker.js | Uses shared public-web contract for Content-Signal and Markdown asset mapping; ensures HEAD responses omit bodies. |
| site/src/lib/publicWebContract.ts | New single source of truth for Content-Signal header formatting and Markdown representation path mapping. |
| site/src/lib/discovery.ts | Deterministic sitemap ordering; reuses Content-Signal header string in generated public docs. |
| site/src/data/routeLastModified.ts | Adds generated per-route SHA-256 digests alongside lastmod timestamps. |
| site/scripts/worker-routing.test.mjs | Extends Accept-matrix tests to cover missing Accept, invalid ranges, HEAD parity, and conditional (ETag/304) behavior. |
| site/scripts/seo-contract.test.mjs | Sorts expected sitemap locs; validates new content-evidence plumbing and single-origin verification doc contract. |
| site/scripts/public-web-contract.test.mjs | New test enforcing a single shared contract for Content-Signal and Markdown asset paths. |
| site/scripts/markdown-representation.mjs | Normalizes skipped heading levels during HTML→Markdown projection; reuses shared Markdown path mapping. |
| site/scripts/markdown-representation.test.mjs | Adds coverage for heading-level normalization behavior. |
| site/scripts/last-modified.mjs | Adds content digest computation + evidence-based lastmod resolution while keeping reruns deterministic. |
| site/scripts/last-modified.test.mjs | New unit tests for digest-driven lastmod advancement/stability rules. |
| site/scripts/check-html.mjs | Strengthens Markdown gates: heading hierarchy, deterministic regeneration, semantic parity vs HTML, and same-origin link resolution. |
| site/scripts/build-representations.test.mjs | Updates/extends build-gate tests to validate semantic drift detection, heading/link gates, and determinism. |
| site/public/sitemap.xml | Updates checked-in sitemap baseline ordering to the new deterministic canonical sort. |
| docs/operations/verification.md | Updates deployment verification checklist to the single-origin + negotiation/ETag/Vary/Content-Signal contract. |
| docs/engineering/architecture.md | Documents the new shared public-web contract module and digest-backed lastmod behavior. |
Review details
- Files reviewed: 17/17 changed files
- Comments generated: 0
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: a7da4353f7
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| if ( | ||
| statement.type !== 'ImportDeclaration' | ||
| && statement.type !== 'ExportNamedDeclaration' | ||
| && statement.type !== 'ExportAllDeclaration' | ||
| ) return [] |
There was a problem hiding this comment.
Include lazy family games in route content evidence
When a family game such as PackMasterGame.tsx or one of its dependencies changes without touching catalog.ts, the family route digest remains unchanged: this walker only collects import/export declarations, while the game is reachable through a literal import() in catalog.ts, and routeModuleIds() seeds only the family page and art module. Consequently resolveContentLastModified() preserves the old timestamp and publishes stale sitemap/discovery metadata for a changed interactive page; seed each catalog-selected game as a semantic root while keeping its runtime loading lazy.
AGENTS.md reference: AGENTS.md:L13-L16
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 0aa6a9daf5
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| const pending = [ | ||
| resolve(projectRoot, 'site/src/components/layout/Shell.tsx'), | ||
| resolve(projectRoot, 'site/src/lib/pageMeta.ts'), | ||
| resolve(projectRoot, 'site/src/lib/seoHead.ts'), | ||
| ...routeModules.map((moduleId) => resolve(projectRoot, 'site', moduleId)), | ||
| ] |
There was a problem hiding this comment.
Include the prerender wrappers in each route digest
Seed the actual prerender path through entry-server.tsx, StaticApp.tsx, and AppContent.tsx, or explicitly include those modules in the evidence graph. A change to AppContent's RouteView or common route wrappers can alter every route's prerendered HTML and Markdown, but the graph currently starts at Shell and the leaf page, and static-import traversal cannot move upstream to those renderer modules; the digest therefore remains unchanged and preserves stale lastmod metadata.
Useful? React with 👍 / 👎.
| if (previousDigest && previousDigest !== currentDigest && previousLastModified) { | ||
| if (evidenceSchemaChanged) return previousLastModified | ||
| const previousTime = Date.parse(previousLastModified) |
There was a problem hiding this comment.
Do not suppress content edits during schema upgrades
When the digest schema version changes in the same task as a real route-content edit, this unconditional return preserves the old timestamp solely because evidenceSchemaChanged is true, even though the current and previous digests differ. The newly edited page is then published with stale discovery metadata; schema migrations need to distinguish schema-only digest churn from simultaneous semantic changes, or reject combined migrations rather than masking them.
Useful? React with 👍 / 👎.
Signed-off-by: Shanire <shanire@skylinejoy.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 9d41da1a7e
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| const source = readFileSync(new URL(`../../${file}`, import.meta.url), 'utf8') | ||
| digest.update(normalizeContentForDigest(semanticSourceForDigest(file, source))) |
There was a problem hiding this comment.
Hash binary route assets as bytes
When the semantic graph reaches an imported binary asset such as the route-owned .avif files, reading it as UTF-8 and applying text newline normalization makes the digest lossy: distinct byte sequences can decode identically (and 0x0d/0x0a differences are explicitly normalized). An image-only content change can therefore retain the previous digest and stale lastmod; only decode and normalize parsed text modules, while feeding binary assets directly to the hash as buffers.
Useful? React with 👍 / 👎.
Signed-off-by: Shanire <shanire@skylinejoy.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 079f801666
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| const rootName = SEMANTIC_ELEMENT_ROOTS.get(path) | ||
| if (!rootName) return source |
There was a problem hiding this comment.
Scope catalog changes to affected routes
Because every route seeds pageMeta.ts and seoHead.ts, both of which import the combined catalog.ts, this fallback hashes the entire catalog for all 47 routes. Editing one lesson's catalog entry therefore changes every route digest and advances unrelated sitemap/structured-data lastmod values, defeating the route-specific evidence this graph is intended to provide; project catalog evidence to the entries relevant to each pathname rather than treating the whole registry as route content.
AGENTS.md reference: AGENTS.md:L13-L18
Useful? React with 👍 / 👎.
Signed-off-by: Shanire <shanire@skylinejoy.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: defcb64944
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| } catch { | ||
| // The URL parsed, but an invalid percent escape still makes the target unusable. | ||
| } | ||
| if (!assetPath || !existsSync(assetPath)) { |
There was a problem hiding this comment.
Reject links to built internal specimens
When public JSX links to an internal prerendered specimen such as /lab/body-demo-standard, this fallback accepts it because the build creates that directory under dist, so existsSync(assetPath) succeeds even though the pathname is absent from PUBLIC_PATHS. The resulting public Markdown therefore exposes an internal specimen while the gate reports success; explicitly reject internal paths or validate non-route assets against an allowlist rather than accepting every existing build path.
AGENTS.md reference: AGENTS.md:L18-L18
Useful? React with 👍 / 👎.
Signed-off-by: Shanire <shanire@skylinejoy.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 921f10c5a7
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| const pending = [ | ||
| resolve(projectRoot, 'site/src/entry-server.tsx'), | ||
| resolve(projectRoot, 'site/src/lib/pageMeta.ts'), | ||
| resolve(projectRoot, 'site/src/lib/seoHead.ts'), | ||
| ...routeModules.map((moduleId) => resolve(projectRoot, 'site', moduleId)), |
There was a problem hiding this comment.
Include Markdown projection logic in route evidence
When scripts/markdown-representation.mjs changes how semantic HTML is projected—such as the heading normalization added in this commit—the published text/markdown body changes, but none of the evidence roots here can reach that build-only renderer, so every route can retain its previous digest and stale lastmod. This commit demonstrates the mismatch: the renderer changes while the checked-in route timestamps remain from August 22; include the projection logic in each route's evidence or hash the rendered Markdown output.
AGENTS.md reference: AGENTS.md:L62-L62
Useful? React with 👍 / 👎.
Signed-off-by: Shanire <shanire@skylinejoy.com>
Signed-off-by: Shanire <shanire@skylinejoy.com>
Signed-off-by: Shanire <shanire@skylinejoy.com>
Signed-off-by: Shanire <shanire@skylinejoy.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 6c98fcc460
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| const pending = [ | ||
| resolve(projectRoot, 'site/src/entry-server.tsx'), | ||
| resolve(projectRoot, 'site/src/lib/pageMeta.ts'), | ||
| resolve(projectRoot, 'site/src/lib/seoHead.ts'), | ||
| ...routeModules.map((moduleId) => resolve(projectRoot, 'site', moduleId)), |
There was a problem hiding this comment.
Track literal public hero assets in home evidence
When any site/public/og/dpmaster-social* image is replaced without editing Home.tsx, the published home hero changes but its digest does not: these roots only traverse source-module imports, while HeroImage references the AVIF/WebP/JPEG files through literal /og/... URLs. Include those public assets as home-route evidence so image-only updates advance the home lastmod.
Useful? React with 👍 / 👎.
Signed-off-by: Shanire <shanire@skylinejoy.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: f4e474dfdf
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| } | ||
|
|
||
| function resolveStaticImport(importer, specifier) { | ||
| if (!specifier.startsWith('.')) return null |
There was a problem hiding this comment.
Include SSR dependency versions in route evidence
When an SSR-affecting dependency is upgraded, this drops every bare import, so neither site/package.json nor the exact pnpm-lock.yaml resolution contributes to any route digest. For example, a KaTeX upgrade can change renderToString output—and therefore the published lesson HTML and Markdown—while the unchanged import katex from 'katex' leaves the digest and lastmod stale; seed the relevant dependency-resolution evidence or hash the rendered representations.
AGENTS.md reference: AGENTS.md:L63-L63
Useful? React with 👍 / 👎.
Signed-off-by: Shanire <shanire@skylinejoy.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: e0b015b4de
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| const resolved = candidates.find((candidate) => ( | ||
| existsSync(candidate) && statSync(candidate).isFile() | ||
| )) | ||
| if (!resolved || extname(resolved) === '.css') return null |
There was a problem hiding this comment.
Include route CSS in content evidence
When a route stylesheet such as pages/home.css changes without its importing TSX changing, this branch explicitly drops the CSS dependency, so the route digest and lastmod remain unchanged. However, the prerender flow in scripts/prerender.mjs injects the manifest's content-hashed stylesheet URL into each route's HTML, meaning the published representation and visible page have changed; hash route-owned CSS as text evidence rather than discarding it.
Useful? React with 👍 / 👎.
Signed-off-by: Shanire <shanire@skylinejoy.com>
Signed-off-by: Shanire <shanire@skylinejoy.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 6c7bb5523e
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| const pending = [ | ||
| resolve(projectRoot, 'site/src/entry-server.tsx'), | ||
| resolve(projectRoot, 'site/src/lib/pageMeta.ts'), | ||
| resolve(projectRoot, 'site/src/lib/seoHead.ts'), | ||
| ...routeModules.map((moduleId) => resolve(projectRoot, 'site', moduleId)), |
There was a problem hiding this comment.
Include prerender assembly inputs in route evidence
When scripts/prerender.mjs changes settleSuspenseMarkup() or documentForRoute()—or when the index.html template it assembles changes—the published HTML, and potentially the Markdown projected from it, changes for every route, but these roots only traverse the SSR source graph and cannot reach either build-time input. The stored digest therefore remains unchanged and preserves stale lastmod values; include the prerender assembler/template in each route's evidence or hash the completed representations.
AGENTS.md reference: AGENTS.md:L62-L62
Useful? React with 👍 / 👎.
Signed-off-by: Shanire <shanire@skylinejoy.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 8bca2b1e9d
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| resolve(projectRoot, 'site/package.json'), | ||
| resolve(projectRoot, 'site/pnpm-lock.yaml'), |
There was a problem hiding this comment.
Scope runtime dependency evidence to routes that use it
When a client-only dependency such as GSAP is upgraded, these unconditional roots change every route digest even though GSAP is imported only by HomeMotionController.tsx, which this graph explicitly excludes as non-semantic. pnpm seo:generate will therefore advance lastmod for all 47 routes despite no published HTML or Markdown changing; derive package evidence from each route's retained imports rather than seeding the entire runtime allowlist globally.
Useful? React with 👍 / 👎.
Signed-off-by: Shanire <shanire@skylinejoy.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: c72f4b36f2
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| for (const parameter of parameters) { | ||
| if (!parameter) return null | ||
| const separator = parameter.indexOf('=') | ||
| if (separator < 1) return null |
There was a problem hiding this comment.
Accept bare extension parameters after q
When a client sends a valid Accept extension without a value, such as Accept: text/html;q=1;foo, accept-ext permits the bare token, but this check rejects the entire media range because it has no =. If no other range is present, a supported public HTML request incorrectly receives 406; treat parameters after q as accept extensions and allow their optional values.
AGENTS.md reference: AGENTS.md:L62-L62
Useful? React with 👍 / 👎.
Signed-off-by: Shanire <shanire@skylinejoy.com>
Signed-off-by: Shanire <shanire@skylinejoy.com>
Signed-off-by: Shanire <shanire@skylinejoy.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 693475959c
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| for (const name of selected) { | ||
| if (!Object.hasOwn(dependencies, name)) { | ||
| throw new Error(`Missing runtime dependency ${name}`) |
There was a problem hiding this comment.
Treat newly added packages as historical changes
When a route begins using a newly added runtime dependency, semanticChangeEvidence() projects the old package.json and lockfile using the route’s current package set. Because that historical manifest legitimately lacks the new package, this branch throws Missing runtime dependency instead of recognizing an added dependency and deriving its commit timestamp, so pnpm seo:generate and every build are blocked after such an addition. Permit a selected package to be absent on the historical side while retaining the strict check for the current manifest and lockfile.
AGENTS.md reference: AGENTS.md:L63-L63
Useful? React with 👍 / 👎.
Signed-off-by: Shanire <shanire@skylinejoy.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 4cb7113f51
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| `pnpm check:seo` verifies the 47-path catalog, route metadata, checked-in single-origin sitemap/robots baseline, `llms.txt`, 47-entry route summaries, and source-backed `lastmod` data. Version 18 follows each route's real SSR injection chain with a line-ending-neutral runtime-AST digest: type-only syntax is erased without dropping runtime-bearing TypeScript parameter properties or optional-chain behavior; intrinsic event/ref/key props and statically proven spreads erase only deferred callback values while retaining synchronous factories; public `config/site.ts` evidence follows immutable field dependencies and validates global provenance; and mixed shell modules contribute route-rendering JSX plus the lexical closure of all runtime module-evaluation edges, root/program synchronous calls, proven synchronous callbacks and selected React `lazy` loaders, constructors, tagged templates, aliases, and render-phase mutations. Known asynchronous callbacks, including stable aliases and locally private callback-factory results, are erased even when nested inside an otherwise selected synchronous slice, while callback acquisition remains synchronous evidence and exported callbacks remain conservative. Regression probes additionally cover all-candidate mixed call targets, object and class getter-derived targets, conditional/nested/factory/getter and built-in-mutator global containers, nested/shadowed/reassigned/member-held literal dynamic-import callbacks reached through module evaluation, awaited continuation callbacks without treating callback acquisition as execution, statically false literal branches and loops, unmatched literal `switch` cases, selected relative `lazy` children, semantic CSS query imports, and byte-distinct binary assets. Runtime packages are trusted only through the audited dependency set used by this product; each route projects only its semantically reachable trusted roots from `package.json`, rejects reachable packages outside that allowlist, and requires every selected root and transitive registry node to have its exact importer, snapshot, package record, and canonical SHA-256/384/512 `resolution.integrity` value with a 32/48/64-byte digest in `pnpm-lock.yaml`. Unsupported mutable, escaped, aliased, globally patched, unresolved, or dynamic config, unproved callback timing, dynamic targets or intrinsic spreads, imported member receivers, arbitrary external mutations, ambiguous nested writes, and incomplete lock evidence outside proven client callbacks fail closed. | ||
|
|
||
| The browser gate runs Chromium against built `dist/` through a strict, non-reused custom preview server. Route tests directly open `/`, `/part/a`, `/part/a/01`, `/method`, and `/part/g/plug`, then exercise live client navigation and keyboard focus. They check HTTP status, prerendered HTML, absence of pending streamed-Suspense placeholders, route CSS at first paint, hydration without errors, CLS below `0.05`, title/description/abstract/canonical/zero-hreflang/Open Graph/JSON-LD metadata, one visible `h1`, route announcements, current-page semantics, initial-load focus, changed-route focus, and skip-link focus. Navigation-positioning tests click a representative lesson outline in each of the seven families, restore a direct lesson fragment, verify the mobile outline and an ordinary family-page fragment, and require a changed route to reset old-page scroll immediately. An unknown path must return 404 with `noindex,nofollow`, no canonical, and the themed not-found heading. Worker-level Node tests separately cover the Accept matrix, 406 behavior, HEAD parity, representation-specific ETags, hidden internal assets, and unaffected API/static/unknown paths. | ||
| Client endpoints and sidebar-only copy are structurally isolated from the public representation configuration and are unreachable from all 47 semantic graphs. An unchanged digest preserves its prior time; changed content uses the exact Git commit or working-tree timestamp of a semantically changed projection and must advance. A schema migration reapplies the current projector to source history at the previous `lastmod`, so clean committed semantic edits advance while dirty changes confined to pruned client branches do not. Version 15 made the runtime dependency graph visible and advanced all 47 routes to the dependency-maintenance commit at `2026-08-23T21:18:04+08:00`; Version 16 made that evidence route-specific and fail-closed; Version 17 closes the initial callback, package-root, integrity, global-container, and getter provenance gaps; Version 18 closes the exact-SHA review gaps in lexical module evaluation, selected relative lazy children, built-in mutators, literal switches, and SRI byte lengths without inventing a later content time, so the 47 timestamps remain there. This keeps same-day edits precise while unchanged or cross-platform regeneration remains deterministic. The gate also checks the source contracts for the one Cloudflare output, Worker-first static-asset routing, React prerender/hydration, route CSS injection, canonical metadata, and real 404 behavior. `pnpm check:html` then requires the sitemap/public-route/Markdown sets to agree; rejects missing or extra Markdown assets, browser-only markup, internal-path leakage, illegal heading hierarchies, and unresolved same-origin links; regenerates every Markdown document twice from its matching semantic HTML to prove exact same-source parity and determinism; and requires each representation to remain less than half the size of its HTML. When routes, lesson readiness, or route-owned source files change, run `pnpm seo:generate` and review the generated files before committing them. |
There was a problem hiding this comment.
Document the active digest schema version
The new verification contract describes Version 18 as the current route-evidence schema and ends its migration history there, but scripts/last-modified.mjs and the checked-in generated module both set ROUTE_CONTENT_DIGEST_VERSION to 19. This leaves the durable operational documentation unable to explain which projector governs regeneration or what Version 19 changed; update this section alongside the schema bump.
AGENTS.md reference: AGENTS.md:L74-L74
Useful? React with 👍 / 👎.
Closes the DpMaster Web-governance review findings: deterministic sitemap ordering and content-digest lastmod evidence; complete GET, HEAD, conditional Accept matrix; exact HTML-to-Markdown parity, heading and link gates; shared public Web contract; and current single-origin deployment verification. Verified locally with pnpm verify (56 browser tests) and Wrangler 4.125 deploy --dry-run. Dependency drift remains a separate maintenance task.