lighthouse fixes
This commit is contained in:
@@ -0,0 +1,46 @@
|
||||
## ADDED 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
|
||||
@@ -0,0 +1,49 @@
|
||||
## MODIFIED Requirements
|
||||
|
||||
### Requirement: Media modal dialog
|
||||
The site MUST provide a modal dialog that displays embedded media (YouTube video or podcast episode) when a user clicks a video or podcast content card on a listing surface (homepage, `/videos`, `/podcast`).
|
||||
|
||||
The modal MUST render the following elements in order:
|
||||
|
||||
- A header row with the content title on the left and a close button on the right
|
||||
- An embedded media player (YouTube iframe for videos; Spotify embed for podcast episodes when the URL is a Spotify URL; otherwise an in-modal audio player when an `audioUrl` is available)
|
||||
- The full description/summary text (not truncated)
|
||||
- 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"
|
||||
|
||||
#### Scenario: User clicks a podcast episode card with a Spotify URL
|
||||
- **WHEN** a user clicks a podcast content card whose URL is a Spotify URL
|
||||
- **THEN** a modal dialog opens displaying a Spotify episode embed, the episode title, full description, date, and CTAs for "Follow on Spotify" and "Listen on Spotify"
|
||||
|
||||
#### Scenario: User clicks a podcast episode card with a non-Spotify URL
|
||||
- **WHEN** a user clicks a podcast content card whose URL is not a Spotify URL
|
||||
- **THEN** the modal dialog opens displaying the episode metadata (title, description, date) and either:
|
||||
- an in-modal audio player when an `audioUrl` is available
|
||||
- otherwise, a "Listen on Spotify" outbound link
|
||||
|
||||
#### Scenario: Modal renders with missing optional fields
|
||||
- **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`
|
||||
|
||||
## ADDED Requirements
|
||||
|
||||
### 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`
|
||||
@@ -0,0 +1,29 @@
|
||||
## ADDED 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
|
||||
@@ -0,0 +1,39 @@
|
||||
## MODIFIED Requirements
|
||||
|
||||
### Requirement: Sitemap and robots
|
||||
The site MUST provide:
|
||||
|
||||
- `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:
|
||||
|
||||
- `/blog`
|
||||
- blog post detail routes
|
||||
- blog page detail routes
|
||||
- blog category listing routes
|
||||
|
||||
`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`
|
||||
|
||||
## ADDED Requirements
|
||||
|
||||
### 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
|
||||
@@ -0,0 +1,17 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### 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
|
||||
@@ -0,0 +1,41 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### 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
|
||||
|
||||
## MODIFIED Requirements
|
||||
|
||||
### Requirement: Site themes
|
||||
The site MUST support three themes:
|
||||
|
||||
- `dark`
|
||||
- `light`
|
||||
- `high-contrast`
|
||||
|
||||
Themes MUST be applied by setting a `data-theme` attribute on the root document element (`<html>`).
|
||||
|
||||
#### Scenario: Dark theme active
|
||||
- **WHEN** `data-theme="dark"` is set on `<html>`
|
||||
- **THEN** the site's background, text, and component styling reflect the dark palette
|
||||
|
||||
#### Scenario: Light theme active
|
||||
- **WHEN** `data-theme="light"` is set on `<html>`
|
||||
- **THEN** the site's background, text, and component styling reflect the light palette
|
||||
|
||||
#### Scenario: High contrast theme active
|
||||
- **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
|
||||
@@ -0,0 +1,21 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### 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