lighthouse fixes
This commit is contained in:
50
openspec/specs/lighthouse-quality-gate/spec.md
Normal file
50
openspec/specs/lighthouse-quality-gate/spec.md
Normal file
@@ -0,0 +1,50 @@
|
||||
## Purpose
|
||||
|
||||
Define a deterministic Lighthouse quality gate that produces repeatable scores and blocks regressions across required categories.
|
||||
|
||||
## Requirements
|
||||
|
||||
### Requirement: Deterministic Lighthouse configuration
|
||||
The project MUST define a deterministic Lighthouse run configuration that specifies:
|
||||
|
||||
- a fixed list of URLs to audit
|
||||
- mobile and desktop runs
|
||||
- theme variants: `light`, `dark`, and `high-contrast`
|
||||
- a clean run environment (no browser extensions)
|
||||
- throttling / device emulation settings
|
||||
|
||||
The configuration MUST be checked into the repository.
|
||||
|
||||
#### Scenario: Lighthouse config is version-controlled
|
||||
- **WHEN** a developer checks the repository
|
||||
- **THEN** a Lighthouse configuration file/script exists and is referenced by a documented command
|
||||
|
||||
### Requirement: Lighthouse gate enforces perfect scores
|
||||
The project MUST provide a command that runs Lighthouse for the configured URLs and variants and fails if any category score is below 100:
|
||||
|
||||
- Performance
|
||||
- Accessibility
|
||||
- Best Practices
|
||||
- SEO
|
||||
|
||||
The command MUST output the reports as build artifacts (HTML and/or JSON) to a deterministic output directory.
|
||||
|
||||
#### Scenario: Gate fails on a regression
|
||||
- **WHEN** Lighthouse runs and any audited variant scores 99 in any category
|
||||
- **THEN** the command exits non-zero and reports which URL/variant failed
|
||||
|
||||
#### Scenario: Gate produces artifacts
|
||||
- **WHEN** Lighthouse runs successfully
|
||||
- **THEN** the reports are written to the configured output directory for later inspection
|
||||
|
||||
### Requirement: Repeatable scoring rule
|
||||
The Lighthouse gate MUST define a repeatable scoring rule to reduce run-to-run noise.
|
||||
|
||||
At minimum, it MUST document one of the following:
|
||||
|
||||
- single-run with fixed throttling and clean environment, or
|
||||
- multiple runs per variant with a deterministic selection rule (e.g., median)
|
||||
|
||||
#### Scenario: Run-to-run method is documented
|
||||
- **WHEN** a developer runs the gate locally or in CI
|
||||
- **THEN** the method for selecting/reporting scores is explicitly documented
|
||||
@@ -14,6 +14,12 @@ The modal MUST render the following elements in order:
|
||||
- The publish date and view count (when available)
|
||||
- A "Subscribe on YouTube" / "Follow on Spotify" CTA and a "View on YouTube" / "Listen on Spotify" CTA
|
||||
|
||||
All modal CTAs that represent navigation MUST be implemented as crawlable anchors:
|
||||
|
||||
- Each CTA MUST be an `<a>` element with a non-empty `href` attribute.
|
||||
- The UI MUST NOT render placeholder `<a>` elements without `href` in the initial HTML.
|
||||
- If CTA destinations are not known until a user selects an item, the CTA UI MUST be rendered as non-anchor elements until the destinations are known.
|
||||
|
||||
#### Scenario: User clicks a YouTube video card
|
||||
- **WHEN** a user clicks a video content card on any listing surface
|
||||
- **THEN** a modal dialog opens displaying a YouTube iframe embed, the video title, full description, date, view count (if available), and CTAs for "Subscribe on YouTube" and "View on YouTube"
|
||||
@@ -32,6 +38,17 @@ The modal MUST render the following elements in order:
|
||||
- **WHEN** a content item has no view count or no summary
|
||||
- **THEN** the modal MUST still render cleanly with those fields omitted
|
||||
|
||||
#### Scenario: Modal CTAs are crawlable anchors
|
||||
- **WHEN** the modal is present in the DOM (before any user interaction)
|
||||
- **THEN** the document contains no `<a>` elements in the modal that are missing `href`
|
||||
|
||||
### Requirement: Embed fallback is a link only when a destination is available
|
||||
If an embed fallback is presented as a link to an external page, it MUST be an anchor with a valid `href`. If no destination is available, the fallback MUST be hidden or rendered as non-link text.
|
||||
|
||||
#### Scenario: Embed fallback does not render a non-crawlable anchor
|
||||
- **WHEN** the modal is rendered before any item selection
|
||||
- **THEN** the embed fallback is not rendered as an anchor without `href`
|
||||
|
||||
### Requirement: Playback stops on modal close
|
||||
The modal MUST stop all media playback when it is dismissed, regardless of the dismissal method.
|
||||
|
||||
|
||||
33
openspec/specs/responsive-image-delivery/spec.md
Normal file
33
openspec/specs/responsive-image-delivery/spec.md
Normal file
@@ -0,0 +1,33 @@
|
||||
## Purpose
|
||||
|
||||
Define responsive image delivery requirements that reduce layout shift and improve deterministic performance outcomes for Lighthouse.
|
||||
|
||||
## Requirements
|
||||
|
||||
### Requirement: Card thumbnails have explicit dimensions
|
||||
All card thumbnail images MUST include explicit `width` and `height` attributes matching the rendered aspect ratio.
|
||||
|
||||
#### Scenario: Thumbnail dimensions are present
|
||||
- **WHEN** a crawler or browser loads a listing surface with content cards
|
||||
- **THEN** each card thumbnail `<img>` includes `width` and `height` attributes
|
||||
|
||||
### Requirement: Above-the-fold imagery is optimized
|
||||
The site MUST ensure above-the-fold images are optimized for performance:
|
||||
|
||||
- avoid unnecessarily large image payloads for the requested viewport
|
||||
- prefer modern image formats when first-party controlled
|
||||
- avoid layout shift caused by late image dimension discovery
|
||||
|
||||
#### Scenario: Above-the-fold images do not cause layout shift
|
||||
- **WHEN** a user loads the home page on a mobile viewport
|
||||
- **THEN** the hero/top content area does not shift vertically due to image loading
|
||||
|
||||
### Requirement: Third-party image variability is controlled for the Lighthouse gate
|
||||
If a gated page depends on third-party images (e.g., external thumbnails), the gate MUST either:
|
||||
|
||||
- ensure those images do not block reaching 100s by design (e.g., not above-the-fold, lazy-loaded), or
|
||||
- provide a first-party controlled alternative for gated pages.
|
||||
|
||||
#### Scenario: Gated pages avoid third-party image volatility
|
||||
- **WHEN** Lighthouse runs against the gated URL set
|
||||
- **THEN** third-party image delivery does not prevent meeting the required scores
|
||||
@@ -42,7 +42,7 @@ The site MUST provide Open Graph and Twitter card metadata for indexable pages s
|
||||
|
||||
### Requirement: Sitemap and robots
|
||||
The site MUST provide:
|
||||
- `sitemap.xml` enumerating indexable pages
|
||||
- `sitemap-index.xml` enumerating indexable pages (and/or referencing sitemap shards)
|
||||
- `robots.txt` that allows indexing of indexable pages
|
||||
|
||||
The sitemap MUST include the blog surface routes:
|
||||
@@ -51,17 +51,32 @@ The sitemap MUST include the blog surface routes:
|
||||
- blog page detail routes
|
||||
- blog category listing routes
|
||||
|
||||
#### Scenario: Sitemap is available
|
||||
- **WHEN** a crawler requests `/sitemap.xml`
|
||||
- **THEN** the server returns an XML sitemap listing `/`, `/videos`, `/podcast`, `/about`, and `/blog`
|
||||
`robots.txt` MUST reference the sitemap using an absolute URL for the production domain.
|
||||
|
||||
#### Scenario: Sitemap index is available
|
||||
- **WHEN** a crawler requests `/sitemap-index.xml`
|
||||
- **THEN** the server returns an XML sitemap index (or sitemap) listing `/`, `/videos`, `/podcast`, `/about`, and `/blog`
|
||||
|
||||
#### Scenario: Blog URLs appear in sitemap
|
||||
- **WHEN** WordPress content is available in the cache at build time
|
||||
- **THEN** the generated sitemap includes the blog detail URLs for those items
|
||||
|
||||
#### Scenario: Robots references sitemap with absolute URL
|
||||
- **WHEN** a crawler requests `/robots.txt`
|
||||
- **THEN** the response contains a `Sitemap:` line with an absolute URL to `/sitemap-index.xml`
|
||||
|
||||
### Requirement: Structured data
|
||||
The site MUST support structured data (JSON-LD) for Video and Podcast content when detail pages exist, and MUST ensure the JSON-LD is valid JSON.
|
||||
|
||||
#### Scenario: Video structured data present
|
||||
- **WHEN** a video detail page exists and is requested
|
||||
- **THEN** the HTML includes JSON-LD describing the video using a recognized schema type
|
||||
|
||||
### Requirement: Organization and website structured data
|
||||
The home page SHOULD include JSON-LD structured data for the site and its owner/organization.
|
||||
|
||||
If present, the JSON-LD MUST be valid JSON and MUST use a recognized schema type.
|
||||
|
||||
#### Scenario: Home page includes valid JSON-LD
|
||||
- **WHEN** a crawler requests `/`
|
||||
- **THEN** the HTML contains a JSON-LD script tag that parses as valid JSON
|
||||
|
||||
@@ -46,3 +46,19 @@ The Service Worker SHALL use versioned caches and remove old caches during activ
|
||||
#### Scenario: Activate new version and clean old caches
|
||||
- **WHEN** a new service worker version activates
|
||||
- **THEN** it deletes caches from older versions and begins using the current versioned caches
|
||||
|
||||
### Requirement: Critical assets do not remain stale after deploy
|
||||
The service worker and server caching strategy MUST ensure critical shell assets (including the global stylesheet and service worker script) do not remain stale across deploys.
|
||||
|
||||
The implementation MUST include at least one cache-busting mechanism for critical assets, such as:
|
||||
|
||||
- content-hashed asset filenames, or
|
||||
- an asset version query suffix that changes per deploy
|
||||
|
||||
#### Scenario: New deploy updates critical CSS
|
||||
- **WHEN** a new deploy is released and a returning user loads the site
|
||||
- **THEN** the user receives the updated global stylesheet without requiring a manual hard refresh
|
||||
|
||||
#### Scenario: Service worker updates predictably
|
||||
- **WHEN** a new deploy is released
|
||||
- **THEN** the browser can retrieve the updated service worker script and activate it without being pinned by long-lived caches
|
||||
|
||||
@@ -24,6 +24,23 @@ Themes MUST be applied by setting a `data-theme` attribute on the root document
|
||||
- **WHEN** `data-theme="high-contrast"` is set on `<html>`
|
||||
- **THEN** the site uses a high-contrast palette with a clearly visible focus ring and high-contrast borders
|
||||
|
||||
### Requirement: Theme tokens meet contrast intent
|
||||
For each supported theme (`dark`, `light`, `high-contrast`), the theme token pairs used for primary text and primary surfaces MUST meet WCAG 2.2 AA contrast intent.
|
||||
|
||||
At minimum:
|
||||
|
||||
- primary body text on the primary background MUST be high-contrast
|
||||
- link text on the primary background MUST be distinguishable and meet contrast intent
|
||||
- secondary labels on the primary background MUST remain readable
|
||||
|
||||
#### Scenario: Dark theme text is readable
|
||||
- **WHEN** `data-theme="dark"` is active
|
||||
- **THEN** primary text remains readable against primary surfaces without low-contrast combinations
|
||||
|
||||
#### Scenario: Dark theme links are readable
|
||||
- **WHEN** `data-theme="dark"` is active
|
||||
- **THEN** links in common surfaces are readable against their background
|
||||
|
||||
### Requirement: Theme persistence
|
||||
The site MUST persist the user's theme selection so it is retained across page loads and navigations.
|
||||
|
||||
|
||||
@@ -97,3 +97,23 @@ The theme MUST keep text readable and interactive affordances obvious, including
|
||||
#### Scenario: High contrast theme improves readability
|
||||
- **WHEN** the user enables `high-contrast` theme
|
||||
- **THEN** primary text and secondary UI labels remain clearly readable and interactive elements are visually distinct
|
||||
|
||||
### Requirement: Interactive elements use correct semantics
|
||||
Interactive elements MUST use correct semantic elements:
|
||||
|
||||
- Navigation MUST use anchors (`<a>`) with valid `href`.
|
||||
- Actions that do not navigate MUST use `<button>`.
|
||||
|
||||
The site MUST NOT render anchor elements that lack an `href` attribute.
|
||||
|
||||
#### Scenario: Modal triggers are buttons
|
||||
- **WHEN** a content card opens the media modal
|
||||
- **THEN** the card is a `<button>` element and is keyboard operable
|
||||
|
||||
#### Scenario: Navigation CTAs are anchors
|
||||
- **WHEN** a user sees a CTA that navigates to another page
|
||||
- **THEN** the CTA is an `<a>` element with a valid `href`
|
||||
|
||||
#### Scenario: No non-crawlable anchors exist
|
||||
- **WHEN** a crawler inspects the rendered HTML
|
||||
- **THEN** there are no `<a>` elements without `href`
|
||||
|
||||
Reference in New Issue
Block a user