What this project has
All on. Switch off what this project does not have and the rules that depend on it leave the list. Nothing is hidden until you say so.
Ticks are kept in this browser only, against the project name above. They are not shared, backed up, or visible to anyone else - copy the markdown out for anything that has to survive.
PASS means no blocker and no required item failing, with nothing left unverified. CONDITIONAL means a required item failed and was waived in writing, or something could not be checked. FAIL means a blocker is open.
An item that could not be verified is never counted as a pass. That is the difference between a gate and a formality.
No rule matches these filters. to see all 175 again.
A. Automated 69 items
Run the command, paste the number. A machine decides pass or fail.
-
No automated accessibility violations axe, zero violations at WCAG 2.1 A and AA blocker
axe reports zero violations at the WCAG 2.1 A and AA rule sets across the sampled pages, including one page with a form and one with a listing.
Without it, the cheap third of WCAG failures ships anyway, and a Lighthouse score of 98 gets read as a pass it never was.
Standard EN 301 549 - Accessibility requirements for ICT products and services 9.6, in part
Developer The build proves it Why this rule exists About A11y
a11y.axe-cleanComment on this rule -
Each language version has its own crawlable URL a distinct URL per language, 0 redirects by IP or header blocker
Only when the site serves more than one language.
Each language home page returns 200 at its own URL when requested with no cookie, no referrer and an Accept-Language naming a different language. 0 automatic redirects between languages. Every switcher control is an a element with an href.
Without it, Googlebot arrives with one country and one header, gets bounced to French every time, and the English pages never enter the index.
Vendor documentation Google Search Central documentation managing-multi-regional-sites#let-the-user-switch-the-page-language, in part
Developer The build proves it About Crawl and indexation
crawl.language-urlsComment on this rule -
Every published URL answers at its own address 0 non-200 across published URLs and nav links blocker
Every published URL and every navigation link answers 200, following at most one redirect. Anything answering 404 or 410 is given a template or unpublished before launch. Drafts and private posts are out of scope.
Without it, a menu item the client clicks on launch day lands on a 404, and no link checker reports it because the link itself is fine.
House rule Delivered reference builds, audited together a nav item published, sitemapped and 404 on a live build, 2026-08-25not public
Developer The build proves it About Crawl and indexation
crawl.published-urls-resolveComment on this rule -
Only the production host serves an indexable copy of the site every other host gated or noindex blocker
Every enumerated host except production returns 401, 403, or a noindex on both the home page and one deep page. No non-production host returns an indexable 200. The enumerated list ships with the handover, dated.
Without it, Google can pick the staging copy as the canonical one, and the production URLs quietly stop being the ones that rank.
Client document Technical SEO control grid row 6not public
Developer The build proves it Why this rule exists About Crawl and indexation
crawl.sibling-hostsComment on this rule -
Canonical, robots, sitemap and meta tell one story 0 URLs both noindex and Disallowed, 0 conflicts in 10 blocker
On ten sampled URLs, none is both noindex and Disallowed in robots.txt, no noindex URL is listed in a sitemap, and no page canonicalises to a URL that answers noindex, a redirect or a 404.
Without it, the page you meant to drop stays indexed for good: robots.txt stops the fetch, so the noindex that would have removed it is never read.
Automated check:
seo-status:robots,seo-status:home-indexClient document Website Design and Development Checklist section 7, item 13not public
Developer The build proves it About Crawl and indexation
crawl.signals-agreeComment on this rule -
No placeholder content survives to launch 0 lorem, TODO or demo-asset matches across the sitemap blocker
A grep across every URL in the sitemap returns 0 matches for lorem, ipsum, TODO, FIXME and placeholder, and 0 references to a starter-theme demo image. Drafts and private posts are out of scope.
Without it, the client finds our lorem in the hero on launch day, and Google has already indexed the page carrying it.
Client document Website Design and Development Checklist section 15, item 1, in partnot public
Developer The build proves it About Launch and handover
delivery.real-contentComment on this rule -
Doctype and a correct lang attribute on every page lang matches the visible copy, per page blocker
Every sampled page has the doctype and a lang attribute whose value matches the language of the visible copy.
Without it, the English page inherits fr-FR from the header partial, and a screen reader pronounces the whole thing in French.
Standard Web Content Accessibility Guidelines (WCAG) 2.1 3.1.1 (A), in part
Developer The build proves it About HTML
html.doctype-and-langComment on this rule -
Every inventoried URL reaches its replacement in one hop 200 or a single 301, never bulk to home blocker
Only when the project replaces an existing live site.
Every URL on the inventory returns 200, or exactly one 301 to a 200. Zero chains of two or more hops, measured with the http and www variants included. No more than 5 per cent of the inventory lands on the home page, and each one that does has a reason recorded.
Without it, every old deep link lands on the home page, Google reads the lot as soft 404s, and the rankings the old site had are gone.
Client document Website Design and Development Checklist section 8, item 24, in partnot public
Developer The build proves it About Migration
migration.redirect-mapComment on this rule -
CLS at or under 0.1 blocker
Median mobile CLS is 0.1 or less, and no visible shift occurs during a slow-network reload watched by eye.
Without it, a reader taps one link and lands on another, because a late image or web font shoved the page down under their thumb.
Vendor documentation Web Vitals cls, in part
Developer The build proves it About Perf
perf.clsComment on this rule -
LCP at or under 2.5 seconds on mobile 2.5s or less, median of 3 on mobile blocker
Median of three or more mobile runs is 2.5s or less, and the identified LCP element is stated in the report alongside the number.
Without it, a faded-in hero is dropped from the running and something slower below becomes the metric, so shaving bytes off the hero changes nothing.
Vendor documentation Web Vitals lcp, in part
Developer The build proves it Why this rule exists About Perf
perf.lcpComment on this rule -
No credential ever reaches the repository or the web root git-ignored, out of the deploy, 403 over HTTP blocker
No credential appears in git history or in the deployed web root. Requesting the environment file over HTTP returns 403 or 404.
Without it, a licence key gets fetched off the live site by anyone who guesses the filename, and rotating it is the only real fix.
House rule CONVENTIONS.md CONVENTIONS.md:76-80, in partnot public
Developer The build proves it Why this rule exists About Practices
practices.no-secretsComment on this rule -
Stored form submissions are unreachable without logging in submission URLs return 401 or 404 anonymously blocker
Only when the project has a form that collects data from a visitor.
wp post type list --public=1 lists no submission type, and requesting a stored submission by permalink and through its REST route without logging in returns 401 or 404 in both cases.
Without it, every message the contact form ever took is readable at a guessable URL, which is a personal-data breach the client has to report.
Developer The build proves it Why this rule exists About Security and hardening
security.submission-store-privateComment on this rule -
Every indexable page declares a self-referencing canonical one, absolute, on the live host blocker
Each sampled page returns one canonical, absolute, on the live host, equal to the URL that was requested once redirects have resolved.
Without it, one rename leaves 87 URLs canonicalising somewhere else, and the crawler consolidates the whole set onto the wrong address.
Automated check:
seo-status:canonicalVendor documentation Google Search Central documentation crawling-indexing/consolidate-duplicate-urls, in part
Developer The build proves it About SEO
seo.canonicalComment on this rule -
HTTPS is enforced and nothing loads over http one 301 to https, no http:// asset blocker
http:// returns a single 301 to https://, and no sampled page contains an http:// asset URL.
Without it, a migrated page pulls one script over http, the browser blocks it outright, and that block only shows up on the client's live domain.
Automated check:
seo-status:https-redirect,seo-status:mixed-contentVendor documentation web.dev developer guides articles/what-is-mixed-content, in part
Developer The build proves it About SEO
seo.https-and-mixed-contentComment on this rule -
Production is indexable and staging is not driven by environment, never a checkbox blocker
The production home page carries no noindex in the meta robots or the X-Robots-Tag header, and its robots.txt does not disallow the whole site. Staging carries noindex everywhere.
Without it, a database pull from staging carries blog_public=0 into production and the site goes dark after a deploy that reported success.
Automated check:
seo-status:home-index,seo-status:robotsVendor documentation Google Search Central documentation crawling-indexing/block-indexing, in part
Developer The build proves it Why this rule exists About SEO
seo.no-noindex-leakComment on this rule -
Errors say what is wrong and how to fix it in text, announced, focus on the first required
Submitting an invalid form produces a text message identifying the field and the fix, the message is announced, and focus lands on the first invalid control.
Without it, a red border alone says nothing to the one man in twelve who cannot see it, and the failed field sits off-screen unfound.
Standard Web Content Accessibility Guidelines (WCAG) 2.1 3.3.1; 3.3.3; 1.4.1; 4.1.3 (A, AA), in part
Developer The build proves it Why this rule exists About A11y
a11y.form-errorsComment on this rule -
Link text makes sense out of context never "here", "read more" or "click" required
No two links on a page share the same text but different destinations, and no link text is only "here", "read more" or "click".
Without it, a listing of twenty cards gives a screen reader twenty links all reading Découvrir and all going somewhere different.
Standard Web Content Accessibility Guidelines (WCAG) 2.1 2.4.4; 2.4.9 (A, AAA), in part
Developer The build proves it About A11y
a11y.link-textComment on this rule -
Tap targets are big enough and far enough apart 24x24 CSS px minimum, or 24 px of spacing required
At a 390px viewport, every button, icon control and menu item is 24 by 24 CSS pixels, or a 24 px circle centred on it clears its neighbours' circles - the spec's test, 24 px centre to centre, not 24 px of space. Links in a sentence are exempt.
Without it, ad-hoc floors on the primary buttons leave the small ones untested, and a thumb on a 390px screen hits the neighbour.
Standard Web Content Accessibility Guidelines (WCAG) 2.2 2.5.8 (AA), in part
Developer The build proves it About A11y
a11y.target-sizeComment on this rule -
A block is three files sharing one slug template, stylesheet, script, one slug required
For each block, the four names agree. No block has a stylesheet or script with no template, or a data-block value that matches no SCSS class.
Without it, dead stylesheets and scripts pile up for blocks that no longer have a template, and every one of them still builds and ships.
House rule CONVENTIONS.md CONVENTIONS.md:144-149, in partnot public
Developer The build proves it About Colibrity
colibrity.block-file-tripleComment on this rule -
JavaScript targets data attributes, never CSS classes data- for behaviour, classes for styling required
No querySelector or querySelectorAll in block or module scripts selects by a styling class. Renaming a BEM class in the stylesheet breaks nothing at runtime.
Without it, a restyle renames a BEM class and an animation silently stops working, on the client's site, weeks after anyone reviewed the code.
House rule This standard's own decision record docs/decisions.md:33-35
Developer The build proves it About Colibrity
colibrity.js-hooks-are-data-attributesComment on this rule -
Paged views are canonical to themselves page two canonicals to page two required
Only when the listing has more items than fit on one page.
The canonical on page two equals page two's own URL, and page two's title differs from page one's.
Without it, page two tells the crawler it does not exist, so it stops being followed and the items only listed there quietly leave the index.
Automated check:
seo-status:canonicalVendor documentation Google Search Central documentation pagination-and-incremental-page-loading#use-urls-correctly, in part
Developer The build proves it About Colibrity
colibrity.paged-canonicalComment on this rule -
The content that must rank is in the server HTML h1, copy and links present with JavaScript off required
curl on one URL of each template returns HTML containing the h1 text, the first paragraph of body copy and every link in the main navigation. Nothing that has to rank appears only once JavaScript has run.
Without it, the copy that has to rank waits in a render queue that may never come round, and DevTools shows it present the whole time.
Vendor documentation Google Search Central documentation javascript-seo-basics#how-googlebot-processes-javascript, in part
Developer The build proves it About Crawl and indexation
crawl.content-in-server-htmlComment on this rule -
Staging matches production where the checks depend on it same PHP, server, compression and cache headers required
PHP major and minor, server software, Content-Encoding on a built asset and Cache-Control on an HTML response are identical on both hosts, or every remaining difference is named in a dated parity note in the handover.
Without it, staging answers on a different web server with different cache headers, so a speed or caching result signed off there describes nothing live.
Vendor documentation The Twelve-Factor App X. Dev/prod parity, in part
Operations The build proves it About Environments and deployment
env.staging-parityComment on this rule -
An error appears on blur, not while someone is typing shown when the field is left, cleared once valid required
Only when the project has a form that collects data from a visitor.
Typing three characters into an empty email field shows no error. Leaving the field shows one. Typing until the value is valid clears it without leaving the field again.
Without it, half a typed email address gets marked wrong in red mid-word, and the message sits there after the visitor has finished fixing it.
Client document Website Design and Development Checklist section 4, item 5, in partnot public
Developer The build proves it About Forms
forms.error-timingComment on this rule -
Form inputs are 16 pixels so iOS does not zoom on focus 16 px computed at 390 px, and pinch-zoom still works required
Only when the project has a form that collects data from a visitor.
At a 390px viewport, every input, select and textarea computes to 16px or more, focusing one does not change the page scale, and the viewport meta sets neither user-scalable=no nor a maximum-scale.
Without it, tapping the email field on an iPhone zooms the page in and leaves the rest of the form off the right edge with no way back.
Client document Website Design and Development Checklist section 4, item 1, in partnot public
Developer The build proves it About Forms
forms.input-font-sizeComment on this rule -
Every field declares its type and its autocomplete token a token from the spec list on every identity field required
Only when the project has a form that collects data from a visitor.
Every identity field on the sampled forms carries an autocomplete token from the HTML spec list and an input type matching its data, with zero invalid-token findings. Focusing the email field on a phone brings up the email keyboard.
Without it, a phone user retypes name, email, phone and postcode by hand - a delivered contact form ships six identity fields with no autofill token.
Standard Web Content Accessibility Guidelines (WCAG) 2.1 1.3.5 (AA), in part
Developer The build proves it About Forms
forms.input-type-and-autocompleteComment on this rule -
Page regions use landmark elements exactly one main, every nav named required
Each sampled page exposes exactly one main landmark, all content sits inside a landmark, and no two navigation landmarks share a name.
Without it, jumping by region skips the mobile menu and the site header, because neither one sits inside a landmark.
Standard Web Content Accessibility Guidelines (WCAG) 2.1 1.3.1 (A), in part
Developer The build proves it About HTML
html.landmarksComment on this rule -
Ids are unique on the rendered page required
The validator reports no duplicate id on any sampled page, including pages that render the same block more than once.
Without it, clicking a label jumps focus to the first copy of a repeated block, and the visitor fills in the wrong form.
Standard HTML Living Standard 3.2.6 Global attributes, in part
Developer The build proves it About HTML
html.no-duplicate-idsComment on this rule -
No inline event handlers or javascript: URLs required
No rendered page contains an on* event attribute or an href starting with javascript:.
Without it, any Content-Security-Policy worth having has to ship with unsafe-inline, the one setting that lets the injected script run.
House rule Delivered reference builds, audited together no on* attribute in either theme, both buildsnot public
Developer The build proves it About HTML
html.no-inline-handlersComment on this rule -
One h1 per page, and no skipped heading levels required
Each sampled page has exactly one h1, no two sampled pages share an h1, and the heading outline never jumps a level going down, for example h2 straight to h4.
Without it, a screen-reader user skimming by heading level hits an h3 under an h1 and cannot tell which section it belongs to.
Standard Web Content Accessibility Guidelines (WCAG) 2.1 1.3.1 (A), in part
Developer The build proves it About HTML
html.single-h1Comment on this rule -
Every template produces valid HTML W3C validator, zero errors, every template required
The validator reports zero errors on the sampled pages. Warnings are read and either fixed or noted with a reason.
Without it, browsers each guess a different repair for broken markup, so the bug reproduces on the client's machine and not on yours.
Standard HTML Living Standard 2.1.8 Conformance classes, in part
Developer The build proves it About HTML
html.valid-markupComment on this rule -
No personal data travels in a URL 0 emails, names, phones or tokens in a query string or path required
Submit every form and follow each redirect: no resulting URL contains an email, a name, a phone number or an identifying token. A search of the analytics page-path report returns zero such URLs.
Without it, an address typed into one form turns up months later in the analytics page-path report and in a shared browser's history.
Developer The build proves it About Consent and legal
legal.no-pii-in-urlsComment on this rule -
Core CMS fields carry the content, not only the builder 0 published items with an empty title, excerpt or image required
wp post list over each public post type returns 0 published items with an empty post_title, an empty post_excerpt or no featured image, run on the content-complete site and dated. A post type that deliberately uses none of the three is listed with its reason.
Without it, site search returns blank rows and shared links show no description, while the page itself looks perfect to everyone checking it.
Client document Website Design and Development Checklist section 8, item 12not public
Developer The agency proves it About On-page signals
onpage.core-fieldsComment on this rule -
Structured data says what the page actually says type fits the page, values match the rendered copy required
On three sampled pages every emitted value matches the rendered page: headline equals the visible title, author is a name rather than a language code, dates match, and no rating, price or count is emitted that the page itself does not show.
Without it, Google is told the article is 8 words long when 659 are on screen, and the validator that would catch a typo reports it all green.
Automated check:
seo-status:org-brand,seo-status:org-sameasVendor documentation Google Search Central documentation appearance/structured-data/sd-policies, in part
Developer The build proves it About On-page signals
onpage.schema-fidelityComment on this rule -
Scheduled tasks actually fire on the production host no scheduled event overdue past its interval required
The production site's scheduled event list shows no event whose next run is in the past by more than its own interval, read after the site has been idle rather than immediately after a visit.
Without it, a scheduled post on a quiet site publishes whenever the next visitor happens to arrive, or not at all that day.
Vendor documentation WordPress Developer Resources plugins/cron/hooking-wp-cron-into-the-system-task-scheduler, in part
Operations The build proves it About Operations
ops.cron-runsComment on this rule -
A fatal error reaches a mailbox somebody actually reads admin address on the client's domain, not a dev's required
The site's stored admin email is on the client's or the agency's own domain, is not the developer of record's address, and the handover names the person who reads that mailbox and the date they took it on.
Without it, the recovery link for a white-screened site goes to an address that routes nowhere, so the client finds the outage first.
Vendor documentation WordPress Developer Resources wordpress/common-errors#critical-error-message, in part
Operations The client proves it About Operations
ops.fatal-alertsComment on this rule -
Static assets are compressed and cached far-future br or gzip, one year immutable on hashed required
Content-Encoding is br or gzip on HTML, CSS and JS, and hashed assets carry a cache lifetime of a year with immutable.
Without it, a returning visitor re-downloads a byte-identical hashed bundle on every page view, paying for files that could not have changed.
Vendor documentation Web Vitals http-cache, in part
Developer The build proves it Why this rule exists About Perf
perf.caching-and-compressionComment on this rule -
Fonts are subset woff2, self-hosted, with a swap policy woff2 only, none over 100 KB, one preload required
No font file over 100 KB, no ttf or otf served to browsers, font-display is set, and at most one font is preloaded.
Without it, half a megabyte of typefaces ships unnoticed, since nothing in the performance score is weighted against font bytes.
House rule PERFORMANCE.md PERFORMANCE.md:135-144, in partnot public
Developer The build proves it Why this rule exists About Perf
perf.fontsComment on this rule -
Images ship in a modern format at the size they display WebP or AVIF with srcset and sizes, 200 KB per image at most required
No image transfers more than twice the bytes needed at its displayed size, the image audits report no meaningful savings from format or sizing, no single image exceeds 200 KB on the wire, and no animated GIF is served.
Without it, a phone on mobile data downloads the 2000px desktop hero to paint it 390px wide, several times the bytes it needed.
Vendor documentation Web Vitals choose-the-right-image-format, in part
Developer The build proves it About Perf
perf.image-formatsComment on this rule -
TBT at or under 200ms and INP at or under 200ms required
Median mobile TBT is 200ms or less. Where field data exists, INP at the 75th percentile is 200ms or less.
Without it, a tap on the burger does nothing while the main thread finishes parsing script, so people tap twice and open then close the menu.
Vendor documentation Web Vitals inp, in part
Developer The build proves it About Perf
perf.inp-tbtComment on this rule -
Below-the-fold images lazy load, the LCP image does not lazy below the fold, fetchpriority on LCP required
Every below-the-fold image has loading lazy, the LCP image has neither lazy nor async decoding and carries fetchpriority high.
Without it, a bulk find-and-replace puts loading=lazy on the hero and delays the one request the entire metric hangs on.
Vendor documentation Web Vitals optimize-lcp, in part
Developer The build proves it Why this rule exists About Perf
perf.lazy-and-priorityComment on this rule -
Nothing render-blocking that does not have to be defer or type=module, own critical CSS only required
The render-blocking resources audit lists nothing beyond the site's own critical stylesheet.
Without it, a blank white page for as long as another company's font server takes to answer, and longer still on the day it is down.
Vendor documentation Web Vitals optimize-lcp, in part
Developer The build proves it About Perf
perf.no-render-blockingComment on this rule -
Each template has a transfer and DOM budget under 2 MB without video, 1400 elements or measured required
First-load transfer is under 2 MB per sampled template, video excluded, and anything over names its three largest resources. Element count is under 1400, or over it with a median mobile TBT at or under 200 ms recorded on the largest page that template renders.
Without it, a template renders 2774 DOM elements against a 1400 budget, and every style recalc and scroll handler pays for all of them.
Client document Technical SEO control grid rows 134, 139, in partnot public
Developer The build proves it About Perf
perf.page-weightComment on this rule -
Mobile performance score at or above 90 required
Median of three or more mobile runs is 90 or above, quoted with the spread of the runs.
Without it, the client runs PageSpeed themselves a week after launch, gets a red number, and there is no recorded median to answer it with.
Vendor documentation Lighthouse performance scoring performance/performance-scoring, in part
Developer The build proves it Why this rule exists About Perf
perf.score-floorComment on this rule -
Every deliberate split point is asserted in the build paired chunk-graph assertions, no module in two chunks required
The build fails when the negative assertion is broken and fails when the positive one is, each confirmed by breaking it on purpose. The assertion reads the build manifest, not the bundler's exit code, and no module appears in two chunks.
Without it, a mistyped dynamic import makes the build smaller and greener while the feature it was meant to load is quietly dead in production.
House rule Delivered reference builds, audited together bin/assert-chunks.mjs, one build of the twonot public
Developer The build proves it About Perf
perf.split-points-assertedComment on this rule -
Server response starts inside 800 ms TTFB 800 ms or less, median of 3, mobile required
The server response time audit reports 800 ms or less as the median of three or more mobile runs on the slowest template, with the spread of the runs quoted.
Without it, a second passes before the browser holds a single byte, and a week of image work cannot buy back what the server already spent.
Vendor documentation Web Vitals ttfb, in part
Developer The build proves it About Perf
perf.ttfbComment on this rule -
Video is deferred and never blocks the first paint poster, preload none, muted, playsinline, 2 MB per file required
Only when the project has background or hero video.
The video's own bytes are not on the critical path, LCP resolves to the poster or another element, total transfer on first load stays inside the page budget, and no video file served from the site exceeds 2 MB.
Without it, someone on mobile data pays for two megabytes of decorative clip before the page is usable, and never presses play.
House rule PERFORMANCE.md PERFORMANCE.md:465-520, in partnot public
Developer The build proves it About Perf
perf.video-weightComment on this rule -
Production loads with a clean console no error, no rejection, no failed request required
Loading each sampled page and navigating between two of them produces no console error, no unhandled rejection and no failed network request.
Without it, the asset 404 that broke the client's tracking sits unread for months underneath the debug logging.
House rule CONVENTIONS.md PERFORMANCE.md:267-276, in partnot public
Developer The build proves it About Practices
practices.console-cleanComment on this rule -
Scripts clean up after themselves on page transition listeners, tweens and observers torn down required
Only when the project uses client-side page transitions.
Navigating between two pages five times and returning leaves the same number of listeners and scroll triggers as the first load.
Without it, the fifth page a visitor opens runs five copies of the same scroll handler, and only long sessions ever show it.
House rule Delivered reference builds, audited together src/js/core/page-lifecycle.js destroyPage(), both buildsnot public
Developer The build proves it About Practices
practices.self-cleaning-modulesComment on this rule -
A Content-Security-Policy is enforced, not only reported 4 directives enforced, the rest report-only required
curl -sI returns both header names on the same response, and the enforcing one contains all four directives. Clicking through every template with the console open produces zero violations attributed to the enforcing header.
Without it, a report-only header watches an injected script send the form data elsewhere and does nothing but log it.
Standard Content Security Policy Level 3 §3.2, in part
Developer The build proves it Why this rule exists About Security and hardening
security.csp-enforced-baselineComment on this rule -
WordPress's default attack surface is closed at setup XML-RPC, author enum and file editing closed required
/xmlrpc.php returns 403 or 405, /?author=1 does not redirect to an author archive, /wp-json/wp/v2/users returns 401 to an anonymous request, and wp config get DISALLOW_FILE_EDIT returns true.
Without it, a bot reads a real login name off /wp-json/wp/v2/users and gets a second unwatched door at xmlrpc.php that nothing disables.
Vendor documentation Hardening WordPress security/hardening#disable-file-editing, in part
Operations The build proves it About Security and hardening
security.wp-attack-surfaceComment on this rule -
Multilingual sites declare reciprocal hreflang every version, plus itself, plus x-default, ISO codes only required
Only when the site serves more than one language.
Each language version lists every other version plus itself plus x-default, following any alternate lands on a page that lists the original back, and every code is an ISO 639-1 language with at most an ISO 3166-1 region, never a locale such as fr_FR.
Without it, a visitor searching in French is served the English URL, and nothing in the markup looks broken because a discarded set is silent.
Automated check:
seo-status:hreflangVendor documentation Google Search Central documentation specialty/international/localized-versions, in part
Developer The build proves it About SEO
seo.hreflangComment on this rule -
No internal link is broken no 404, no 5xx, no chain over one hop required
A crawl of the sampled pages returns no 404 and no 5xx on internal links, and no chain of more than one redirect.
Without it, a published page sits twice in the main menu and 404s from every template on the site, reaching the sitemap before anyone notices.
Automated check:
seo-status:link-ok,seo-status:linkVendor documentation Google Search Central documentation crawling/docs/troubleshooting/http-status-codes, in part
Developer The build proves it About SEO
seo.internal-links-resolveComment on this rule -
Open Graph and Twitter card tags are complete 8 tags, absolute og:image at 1200x630 required
All eight tags are present on a sampled page, og:url matches the canonical, and the og:image URL is absolute and returns an image of at least 1200 by 630.
Without it, the client shares the launch post on LinkedIn and gets a grey box with a bare URL where the brand image should be.
Standard The Open Graph protocol og:title, og:type, og:image, og:url, in part
Developer The build proves it About SEO
seo.open-graphComment on this rule -
robots.txt exists and points at the sitemap an absolute Sitemap: line, itself a 200, no asset Disallowed required
/robots.txt returns 200, contains a Sitemap: line with an absolute URL that itself returns 200, does not disallow any route that should rank, and disallows nothing a page needs to render: scripts, styles, images or fonts.
Without it, a relative Sitemap line is never resolved, and the preview routes sit crawlable - /sandbox/ answered 200 on a live site.
Automated check:
seo-status:robotsVendor documentation Google Search Central documentation crawling/docs/robots-txt/create-robots-txt, in part
Developer The build proves it About SEO
seo.robots-txtComment on this rule -
The sitemap lists every indexable URL and nothing else one generated sitemap, all 200, none noindex required
The sitemap index returns 200, every child returns 200, a sample of ten listed URLs returns 200 with no redirect, and no listed URL carries noindex. Only one sitemap source answers; the other returns 404, and robots.txt names the one that does.
Without it, seven URLs in one live sitemap answer 404, six of them category archives with no template, and the crawler is handed them on purpose.
Automated check:
seo-status:sitemap,seo-status:tax-sitemapsVendor documentation Google Search Central documentation crawling-indexing/sitemaps/build-sitemap, in part
Developer The build proves it About SEO
seo.sitemapComment on this rule -
Titles and descriptions are present, unique and the right length titles 30-60, descriptions 70-160, one of each per page required
No sampled page is missing a title or description, no two sampled pages share either, lengths sit in range, and each page carries exactly one title element, one description and one robots meta.
Without it, two templates share one title, so the results give no way to tell the pages apart and Google rewrites the title link itself.
Vendor documentation Google Search Central documentation appearance/title-link, in part
Developer The build proves it About SEO
seo.title-descriptionComment on this rule -
The current page is marked in the navigation exactly one aria-current=page per navigation required
On five pages including one section landing page, the main navigation carries exactly one aria-current="page" and it is the item for the URL loaded. No other navigation on the page carries more than one.
Without it, a screen-reader user tabbing through the menu gets nothing saying which item is the page they are already standing on.
Client document Website Design and Development Checklist section 3, item 7, in partnot public
Developer The build proves it About Interface states
states.current-pageComment on this rule -
A missing URL returns a real 404 in the right language 404 status on a missing URL, correct lang attribute required
Request a made-up path under each language root: every one answers 404, not 200 and not 302. The HTML returned carries that language's lang attribute and that language's copy.
Without it, a missing URL answers 200, so Search Console files it as a soft 404 and no monitoring tool ever flags the broken link.
Vendor documentation Google Search Central documentation http-network-errors#2xx-success, in part
Developer The build proves it About Interface states
states.error-pagesComment on this rule -
Scroll reveals fire on deep links and on back navigation 0 elements hidden past their trigger, after #anchor or back required
Only when content on the project animates in as the visitor scrolls.
Load a /page#section link deep in the page, then leave and press back. Zero elements above the scroll position are still hidden, and the same holds after a bfcache restore rather than a fresh load.
Without it, arriving on a /page#section link or pressing back lands the visitor in a stretch of page that never un-hides.
Client document Website Design and Development Checklist section 2, item 14not public
Developer The build proves it About Interface states
states.scroll-reveal-recoveryComment on this rule -
Class names follow BEM and match their block slug block__element--modifier, block name = slug recommended
Every block's root class equals its slug, and no class name outside the design system describes a colour or a size.
Without it, the next developer greps a block's slug, gets no hits in the SCSS, and ends up editing the wrong stylesheet.
House rule CONVENTIONS.md CONVENTIONS.md:144-149, in partnot public
Developer The build proves it About HTML
html.bem-namingComment on this rule -
The site ships a favicon Google can crawl square, at least 48 px, 200, not Disallowed recommended
The home page head references an icon, that URL returns 200 with a square image at least 48 pixels wide, and robots.txt disallows neither it nor its directory. The WordPress default icon appears nowhere.
Without it, the WordPress W, or a blank globe, sits next to the brand in every mobile search result and every browser tab.
Vendor documentation Google Search Central documentation favicon-in-search#guidelines, in part
Developer The build proves it About On-page signals
onpage.faviconComment on this rule -
Third-party scripts are counted and justified under 250ms combined main-thread time recommended
The third-party summary is reviewed, each origin has a stated purpose, and their combined main-thread time stays under 250ms.
Without it, a Meta pixel nobody on the team added eats most of the main-thread budget, and no one can say who owns it or whether it may go.
Vendor documentation Web Vitals third-party-javascript, in part
Developer The build proves it About Perf
perf.third-partyComment on this rule -
Filters write their state to the URL state in the URL, cleared parameters deleted blocker
Only when the page has a listing, archive or search with filters.
Changing a filter changes location.search. Reloading that URL restores the same result set and the same visible filter UI. Clearing a filter removes its parameter rather than leaving it empty. Copying the URL to another browser reproduces the view.
Without it, a visitor who opens a result and presses Back lands on the unfiltered list, and nobody can send anyone the filtered view.
Ships in
wp-starter/filter-url-state- import it rather than rebuilding it.Client document Front-end brief "each filter should update the URL parameters when changed", in partnot public
Developer The build proves it Why this rule exists About Colibrity
colibrity.filter-url-stateComment on this rule -
Pagination controls are links, not buttons a real a href, middle-clickable blocker
Only when the listing has more items than fit on one page.
Every page control in the pagination nav is an a element with an href that resolves to a 200. Middle-clicking page two opens it in a new tab.
Without it, everything past page one falls out of the link graph, so those detail pages rank only if something else happens to link them.
Ships in
wp-starter/archive-state- import it rather than rebuilding it.Client document Technical SEO control grid row 53not public
Developer The build proves it Why this rule exists About Colibrity
colibrity.pagination-crawlableComment on this rule -
Every page of a listing has its page number in the URL /page/2/, and it works with JS off blocker
Only when the listing has more items than fit on one page.
Page two is reachable at a distinct URL containing the page number, that URL loads the correct items with JavaScript disabled, and its page number is visible in the address bar after using load-more.
Without it, a crawler loads the listing, sees twelve of two hundred items and never presses the button, so the other 188 go undiscovered.
Ships in
wp-starter/archive-state- import it rather than rebuilding it.Client document Front-end brief "each pagination page should have the page number reflected in the URL", in partnot public
Developer The build proves it Why this rule exists About Colibrity
colibrity.pagination-in-urlComment on this rule -
JavaScript and CSS stay inside their budgets a gzip budget per chunk, failing the build blocker
The budget test passes, or a raised budget is accompanied by that note in the commit. Without repository access this is reported as unverified, never as a pass.
Without it, a bundle doubles across a year of small commits, each too small to notice, and no single one is blameable once the site is slow.
Ships in
wp-starter/bundle-size-test- import it rather than rebuilding it.House rule PERFORMANCE.md CONVENTIONS.md:133-134, in partnot public
Developer The build proves it About Perf
perf.bundle-budgetsComment on this rule -
Comments are closed at every layer unless the brief asks for them closed on every existing and new item, no form rendered required
On every public post type, comments read as closed on an existing item and on a new one, asked through WordPress rather than read off the stored status. No template prints a comment form and the Comments screen is gone. Where the brief wants them, the handover names a moderator.
Without it, the first spam comment lands a month after launch on a feature nobody built and nobody moderates.
Ships in
wp-starter/comments-off- import it rather than rebuilding it.House rule Delivered reference builds, audited together closed in all three builds; in code only in the third, by configuration in the othersnot public
Developer The build proves it About Security and hardening
security.comments-closedComment on this rule
B. Assisted 63 items
A tool runs, a human reads the result and judges it.
-
Text and interface contrast meets AA 4.5:1 body, 3:1 large text and UI blocker
No contrast violation is reported, and text over imagery is checked manually at its worst point rather than its best.
Without it, a body token measured at 4.37:1 sits under the AA bar and ships as real running text on every page that uses it.
Standard Web Content Accessibility Guidelines (WCAG) 2.1 1.4.3; 1.4.11 (AA), in part
Developer The build proves it About A11y
a11y.contrastComment on this rule -
Every form control has a real label a real label element, never a placeholder blocker
Every input, select and textarea has an associated label element that is visible. Placeholders, where present, are supplementary rather than the only name. Required fields are marked in the label and in the markup, and the form says which convention it uses.
Without it, someone using voice control has no visible text to say, and a half-filled form gives back no clue what each box was for.
Standard Web Content Accessibility Guidelines (WCAG) 2.1 3.3.2; 1.3.1; 1.3.5 (A, AA), in part
Developer The build proves it Why this rule exists About A11y
a11y.form-labelsComment on this rule -
Icons are hidden when decorative and named when they act decorative icons unannounced, acting icons named blocker
Zero icon-only controls in the sampled templates lack an accessible name, every decorative icon is hidden from the accessibility tree, and no icon announces a leftover title from the export tool.
Without it, a bare icon button announces as just button, and a decorative tick gets read out on every badge it appears in.
Standard Web Content Accessibility Guidelines (WCAG) 2.1 1.1.1; 4.1.2 (A), in part
Developer The build proves it About A11y
a11y.icon-semanticsComment on this rule -
Every form field lands in the right CRM field a dated signed field map, plus one test record read back blocker
Only when the project has a form that collects data from a visitor, and submissions go to a CRM or another third-party system.
Submit one test entry. Either open it in the CRM and check every field on the signed map is in its named field, or read the dated log line showing that payload leaving with the agreed field names. Keep whichever you used.
Without it, a lead arrives in the CRM with its phone number in a notes field and its consent value missing, and nobody can prove where it went.
Client document Website Design and Development Checklist section 13, item 4, in partnot public
Operations The client proves it About Email, CRM and analytics
comms.crm-field-mapComment on this rule -
Automated mail arrives with SPF, DKIM and DMARC passing all three pass on one dated test send blocker
Only when the site sends email of its own - notifications, autoresponders, transactional.
Send the live form to a Gmail account and open Show original. The Authentication-Results header reads spf=pass and dkim=pass, and dmarc=pass once the record is published. That dated header is the evidence, filed with the handover.
Without it, Gmail and Yahoo drop unauthenticated mail into spam or refuse it outright, so the enquiry is lost and nobody gets a bounce.
Vendor documentation Email sender guidelines Requirements for all senders, in part
Operations The client proves it Why this rule exists About Email, CRM and analytics
comms.email-authenticationComment on this rule -
A submission is stored before anything is emailed with mail broken on purpose, the record still lands blocker
Only when the project has a form that collects data from a visitor.
Break mail sending on purpose and submit once. The entry is in the admin list inside a minute, flagged as not notified, and it carries the consent value that goes on to the CRM. Nothing is lost when mail fails.
Without it, one SMTP failure takes the whole enquiry with it, leaving no record, no consent proof and nothing to replay once mail works again.
House rule Delivered reference builds, audited together inc/rest-contact.php stores before mailing, both buildsnot public
Developer The build proves it Why this rule exists About Email, CRM and analytics
comms.submission-deliveryComment on this rule -
Production personal data does not travel to staging or a laptop submission and consent rows dropped or synthesised blocker
Only when the project has a form that collects data from a visitor.
Row counts on staging and local for the submission, consent, order and non-staff user tables are zero against production's. The anonymisation runs inside the committed sync script, not from a runbook step.
Without it, real form submissions with names, emails and IP addresses end up in plaintext dumps on a laptop and in a backups folder nobody prunes.
Developer The build proves it Why this rule exists About Environments and deployment
env.no-production-data-off-productionComment on this rule -
File uploads declare what they accept and why they refuse sniffed-MIME allow-list, a byte cap, a named reason blocker
Only when the project has a form that collects data from a visitor, and a form on the project accepts a file upload.
A PHP file renamed to .pdf is refused. A file one byte over the documented cap is refused. Both refusals name the reason on screen. Requesting a stored file's URL returns a download or 403, never executed output.
Without it, an extension check passes a file that is not what it claims, and it lands in a folder that will happily execute PHP.
Client document Website Design and Development Checklist section 4, item 16, in partnot public
Developer The build proves it About Forms
forms.file-uploadsComment on this rule -
A link goes somewhere, a button does something never a div with a click handler blocker
No clickable element is a div or span. Every navigating control has an href that resolves. Every control is reachable and operable with Tab and Enter.
Without it, a project card that navigates from a JavaScript click has no URL to copy, open in a new tab or share, since there is no href to take one from.
Standard Web Content Accessibility Guidelines (WCAG) 2.1 4.1.2 (A), in part
Developer The build proves it About HTML
html.buttons-vs-linksComment on this rule -
The privacy policy is a real page, linked where data is taken own permalink, 200, linked from footer and every form blocker
The policy URL returns 200 on its own permalink, is linked from the footer and from every form that collects personal data, and carries no noindex. The client has confirmed in writing that the published text is the version their counsel approved.
Without it, a form collects names and emails while its policy link 404s or sits behind a noindex sweep.
Law Regulation (EU) 2016/679 (General Data Protection Regulation), consolidated text Art. 13(1), in part
Developer The client proves it About Consent and legal
legal.documents-publishedComment on this rule -
Newsletter consent is its own optional checkbox terms ticked, newsletter unticked: 0 subscriber records blocker
Only when the project has a form that collects data from a visitor, and the project captures newsletter or marketing consent.
Submit with the terms ticked and the newsletter box untouched: zero subscriber records are created and no address reaches a mailing list. The newsletter box is unticked on a fresh load and the form submits successfully without it.
Without it, somebody downloading a PDF lands on the mailing list from a box that never mentioned one, and no record says which they agreed to.
Law Regulation (EU) 2016/679 (General Data Protection Regulation), consolidated text Art. 4(11), in part
Developer The build proves it About Consent and legal
legal.newsletter-separateComment on this rule -
The terms box starts unchecked and the server enforces it unchecked after a back-nav, refused server-side, names it blocker
Only when the project has a form that collects data from a visitor.
Submit with the box unticked: the server returns an error and stores nothing. Tick it, submit, then press back - it is unticked again. The stored record names the document and the version that was shown.
Without it, Safari and Firefox re-tick the box on a back-navigation, so the record shows an acceptance the visitor never made.
Client document Website Design and Development Checklist section 5, item 3, in partnot public
Developer The build proves it About Consent and legal
legal.terms-consent-checkboxComment on this rule -
The old site's indexed URLs are counted before anything is built crawl plus Search Console, one list blocker
Only when the project replaces an existing live site.
A committed URL list with a stated total, broken down by language and template, dated, and naming which of the four sources each URL came from. Any section whose count nobody can explain is treated as unknown rather than as zero.
Without it, 2,362 old blog posts nobody counted turn up as a 404 spike a week after launch, when the old site is gone and the list cannot be rebuilt.
Vendor documentation Google Search Central documentation site-move-with-url-changes#determine-your-current-urls, in part
Developer The build proves it Why this rule exists About Migration
migration.url-inventoryComment on this rule -
All dynamic output is escaped at the point of output escape late, at output, per context blocker
No template prints an unescaped dynamic value. A field containing a script tag renders as visible text rather than executing.
Without it, an editor pastes a script tag into a title field and it runs for every visitor on that page.
House rule CONVENTIONS.md CONVENTIONS.md:37-41, in partnot public
Developer The build proves it About Practices
practices.output-escapingComment on this rule -
No REST route writes without an authorisation check or a stated bound no open write route without a stated bound blocker
Every register_rest_route in the repository either passes a capability check or appears in the handover's public-route list with its bound named. No route that returns true unconditionally writes to the database without at least one named bound.
Without it, a custom route left open takes whatever a stranger posts straight into the database, with nothing capping how much lands there.
Vendor documentation REST API Handbook rest-api/extending/adding-custom-endpoints#permissions-callback, in part
Developer The build proves it Why this rule exists About Security and hardening
security.rest-route-authorisationComment on this rule -
Uploads cannot execute, and no script-capable type is allowed no script-capable type, uploads do not execute blocker
The upload_mimes filter adds no script-capable type, or names both the sanitiser and the capability gating it. The deny-execution file for wp-content/uploads is shown to the review, read off the server rather than out of the repository.
Without it, an SVG with a script in it runs on the site's own origin, so one contributor upload becomes a shell or a stolen admin session.
Standard OWASP Application Security Verification Standard 5.0.0 5.3.1 (L1), in part
Operations The build proves it About Security and hardening
security.upload-types-and-executionComment on this rule -
Replaced URLs redirect to their new home one 301 to a 200, never bulk to the home page blocker
Only when the project replaces an existing live site.
Every URL on the old-site list returns 200 or a single 301 to a 200. No mass redirect to the home page. Spot-check the twenty highest-traffic URLs by hand.
Without it, every ranking and inbound link the old site earned dies at cutover, and by the time anyone notices the list of old URLs is gone too.
Vendor documentation Google Search Central documentation crawling-indexing/site-move-with-url-changes, in part
Developer The build proves it Why this rule exists About SEO
seo.redirects-on-launchComment on this rule -
Content is visible when JavaScript does not run JS off: 0 elements left at opacity 0 or out of viewport blocker
With JavaScript disabled, load the home page and two inner templates. Zero elements remain at opacity 0, visibility hidden or translated out of the viewport, and every section's copy is readable.
Without it, one failed script leaves dozens of sections at opacity 0, and the visitor gets a blank page while the copy sits there in the HTML.
Client document Website Design and Development Checklist section 2, item 12not public
Developer The build proves it Why this rule exists About Interface states
states.no-js-fallbackComment on this rule -
The preloader has a hard cap and a fallback page visible within 3 s of first byte whatever fails blocker
Only when the project shows a preloader before the first paint.
Throttle to Slow 3G, then repeat with the preloader's own assets blocked. The page is readable within 3 seconds of the first byte in both runs, and neither leaves the overlay on screen.
Without it, one font or third-party script that never resolves leaves the visitor staring at an opaque overlay with no way past it.
Client document Website Design and Development Checklist section 2, item 11, in partnot public
Developer The build proves it Why this rule exists About Interface states
states.preloader-budgetComment on this rule -
What the client must not do is refused, not hidden a denied capability, verified by opening the URL required
For every screen or action the client must not reach, a request made as the client's own account is refused by WordPress, checked at the URL and not in the sidebar. Where hiding is used instead, the repository says in words that it is cosmetic.
Without it, a hidden menu reads as a locked one, and the screen still answers at its own URL to anyone who types it.
House rule Delivered reference builds, audited together create_posts => do_not_allow with map_meta_cap, both buildsnot public
Developer The build proves it Why this rule exists About The admin the client receives
admin.capability-boundariesComment on this rule -
Field definitions live in the repository, and a field name is the data registered in code; no name renamed without a migration required
Every field group the site depends on is defined in a file in the repository, and a fresh database gets them from that file with nothing imported by hand. No field name in this release differs from the last one without a migration beside it.
Without it, an editor opens the page after a rename and the content is simply gone, the old values still sitting under a key nothing reads.
House rule Delivered reference builds, audited together field groups registered in PHP, both buildsnot public
Developer The build proves it About The admin the client receives
admin.fields-in-codeComment on this rule -
Every field and every fixed string says how it translates a preference per field, zero source-language theme strings required
Only when the site serves more than one language.
A scan over the field definitions finds every registered field carrying a translation preference. Each template loaded in a secondary language shows zero theme strings in the default language, and any one of them can be changed from the admin.
Without it, a translated page keeps the source language in every label and empty state, and a copied field overwrites the translation on the next save.
House rule Delivered reference builds, audited together a preference on every field, all three builds; the string table in two of threenot public
Developer The build proves it About The admin the client receives
admin.translation-declaredComment on this rule -
Filter combinations do not become a crawl trap indexable and in the sitemap, or canonicalised required
Only when the page has a listing, archive or search with filters.
A filtered URL either canonicalises to the base listing or is deliberately indexable and present in the sitemap. No filter combination generates an unbounded set of indexable URLs.
Without it, multi-select filters mint combinations faster than any crawler can exhaust them, and the budget meant for product pages goes there instead.
Vendor documentation Google Search Central documentation crawling-managing-faceted-navigation, in part
Developer The build proves it Why this rule exists About Colibrity
colibrity.filter-indexabilityComment on this rule -
Automated email carries a correct From, Reply-To and language From on the site's domain, Reply-To a real inbox required
Only when the site sends email of its own - notifications, autoresponders, transactional.
In the received notification and autoresponder, From is on the site's own domain, Reply-To resolves to an inbox someone reads, and a submission from each locale arrives written in that locale's language, subject included.
Without it, an English visitor gets a French autoresponder, and a From on a domain the site does not own fails SPF before anyone reads it.
Client document Website Design and Development Checklist section 13, item 3, in partnot public
Developer The build proves it About Email, CRM and analytics
comms.sender-identityComment on this rule -
Every page below the home page shows one breadcrumb trail one trail, root in page language, BreadcrumbList mirrors it required
Each sampled page below the home page shows exactly one trail, its root item in the page's language, its last item not a link, and its BreadcrumbList lists the same items in the same order under the same names. The Rich Results Test reports 0 BreadcrumbList errors.
Without it, the breadcrumb Google prints in the result is not the one on the page - wrong language, a level short, on every result for the site.
Vendor documentation Google Search Central documentation structured-data/breadcrumb#list-item, in part
Developer The build proves it About Crawl and indexation
crawl.breadcrumb-trailComment on this rule -
Every URL-minting template has a recorded index decision one recorded decision per template, and the sitemap agrees required
The handover carries a dated table of every URL-minting template and non-HTML route with its decision. For each marked noindex, one sampled URL answers noindex, by X-Robots-Tag where there is no HTML head, and appears in no sitemap.
Without it, author, date and attachment archives nobody thought about get indexed by default, and thin near-duplicates compete with the real pages.
Automated check:
seo-status:tax-sitemapsClient document Website Design and Development Checklist section 8, item 5, in partnot public
Developer The build proves it About Crawl and indexation
crawl.indexability-decidedComment on this rule -
Every indexable page is reachable by a static HTML link 0 orphans, 3 clicks max, crawled with JavaScript off required
The raw-HTML crawl reaches every URL in the sitemap: 0 orphans. No indexable page sits more than 3 clicks from the home page. A page found only in the sitemap counts as an orphan, not as reachable.
Without it, whole page sets stay orphaned behind a JavaScript map - live in the CMS, listed in the sitemap, reachable by no anchor a crawler can follow.
Client document Technical SEO control grid row 7not public
Developer The build proves it About Crawl and indexation
crawl.internal-reachabilityComment on this rule -
Every language publishes the same set, or says what it leaves out one parity report per language, gaps listed with a reason required
Only when the site serves more than one language.
A dated parity report per secondary language lists zero unexplained gaps in published items, menus and terms, and every translated page carries the same block count as its source or a written reason.
Without it, the French site ships with no navigation for days while every gate in the project is green.
House rule Delivered reference builds, audited together a parity checker in one older build and the third; nothing of the kind in the other older buildnot public
Developer The build proves it About Crawl and indexation
crawl.language-parityComment on this rule -
Search Console is verified and the build team has access verified property, build team's account opens Coverage required
A dated screenshot taken from the build team's own Google account with the Coverage report open on the production property. Requested at kickoff, not at launch. After go-live the same account shows the sitemap submitted, with a read date.
Without it, nobody can see what Google actually did with the site, so live sitemap 404s and dropped pages go unnoticed until someone complains.
Vendor documentation Google Search Central documentation search-console-start#get-started-with-search-console, in part
Operations The client proves it About Crawl and indexation
crawl.search-consoleComment on this rule -
A renamed slug leaves a redirect from its old URL every renamed URL: one 301 to a 200 required
Every URL in the sitemap snapshot taken before the restructure, plus every old URL rebuilt from _wp_old_slug, returns 200 or exactly one 301 to a 200. 0 of them 404, and 0 chains of two hops or more.
Without it, a renamed page 404s where a renamed post would have self-healed, and every external link and ranking pointing at the old URL dies with it.
Client document Website Design and Development Checklist section 8, item 24, in partnot public
Developer The build proves it About Crawl and indexation
crawl.slug-change-redirectComment on this rule -
Slugs are readable, hyphenated and in the page's language no ids, no dates, under 115 chars, page's language required
Every URL in the crawl is under 115 characters, separates words with hyphens rather than underscores, carries no numeric id or date segment, and is in the same language as the page it serves. 0 exceptions across the sampled templates.
Without it, an English page ends up served on a French slug, or /?cat=38 in the results, and fixing it after launch means redirects and a fresh crawl.
Client document Technical SEO control grid row 60not public
Developer The build proves it About Crawl and indexation
crawl.url-formatComment on this rule -
Contrast is proven in the mockup, not found in the browser 4.5:1 body, 3:1 large text and UI, 0 pairs unmeasured required
Only when the build works from a new design file rather than an existing template.
A dated screenshot of the contrast plugin's report on the kit: 4.5:1 for body text, 3:1 for text at 24px or 19px bold and above and for interface components, and 0 pairs left unmeasured.
Without it, a focus ring nobody measured ships at 1.48:1 on the page background, and re-colouring it after the build costs a design change and a rebuild.
Standard Web Content Accessibility Guidelines (WCAG) 2.1 1.4.3 (AA), in part
Designer The agency proves it Why this rule exists About Design and UI kit
design.contrast-in-mockupComment on this rule -
What production is running is a commit you can name the live build id resolves to a named commit required
The live site exposes an identifier that resolves to one commit on the default branch of the repository handed over. A deployment naming no commit anywhere in its response or in a stamped file does not pass.
Without it, nobody can tell whether the bug they are chasing lives in the repository or in a file somebody edited on the server months ago.
Vendor documentation The Twelve-Factor App V. Build, release, run, in part
Operations The build proves it About Environments and deployment
env.deploy-provenanceComment on this rule -
Environment switches are enforced in code, not in the database survives a database push in either direction required
Pushing a production database onto staging leaves staging's next response firing zero analytics requests with debug output off, and each host still reports its own environment from a server-side constant. Indexability is graded by seo.no-noindex-leak.
Without it, the next content push from production overwrites the one database row that was keeping staging's tracking switched off.
Vendor documentation The Twelve-Factor App III. Config, in part
Developer The build proves it About Environments and deployment
env.env-config-not-in-dbComment on this rule -
Staging never writes to a production system no beacon, no live CRM, no mail to a real address required
Only when the project has a form that collects data from a visitor.
One staging page load fires zero requests to an analytics, tag or advertising endpoint. One staging form submission arrives in a test inbox and creates no record in the production CRM.
Without it, a form test on staging lands in the client's real public inbox, and test traffic lands in the analytics property they report on.
Vendor documentation The Twelve-Factor App IV. Backing services, in part
Developer The build proves it About Environments and deployment
env.staging-sends-nothing-liveComment on this rule -
Forms carry three layers of spam defence honeypot, a scored gate, and a per-IP rate limit required
Only when the project has a form that collects data from a visitor.
The hidden field filled in stores nothing. 20 POSTs from one IP inside a minute get a 429 before the last one, and the refused POSTs write no message and no consent record. With the scored gate's verifier unreachable, a submission is refused.
Without it, the captcha verifier times out once and everything sent that minute is waved through - both delivered themes return a pass on a transport error.
Client document Website Design and Development Checklist section 4, item 11, in partnot public
Developer The build proves it Why this rule exists About Forms
forms.anti-spamComment on this rule -
A submit happens once and loses nothing 1 record on a double click, values kept on failure required
Only when the project has a form that collects data from a visitor.
The same payload submitted twice, once by double click and once by replaying the POST, leaves exactly 1 message record and 1 consent record. A failed submit returns the form with every value the visitor typed still in it.
Without it, an impatient double click writes two message records and two consent records, and the consent log is the thing a GDPR auditor counts.
Client document Website Design and Development Checklist section 4, item 12, in partnot public
Developer The build proves it About Forms
forms.submit-lifecycleComment on this rule -
Email and phone are checked without rejecting valid values email needs a dot TLD, phone stored E.164 if international required
Only when the project has a form that collects data from a visitor.
test@example is refused, test@example.com is accepted, and no address in the reviewer's list of 10 valid addresses is refused. +33 6 12 34 56 78 is accepted and stored as +33612345678.
Without it, phone numbers reach the CRM as +33 6 12 34 56 78, spaces and all, so nothing downstream can dial, dedupe or match them.
Standard HTML Living Standard 4.10.5.1.5 Email state (type=email), in part
Developer The build proves it About Forms
forms.value-formatsComment on this rule -
Lists are lists and tables are tables no layout tables, th with scope required
No layout is built from table elements, every table has header cells with scope, and repeated content is inside a list element.
Without it, a screen reader never announces the grid's item count, so nobody using one can tell how many results the filter returned.
Standard HTML Living Standard 4.9.1 The table element, in part
Developer The build proves it About HTML
html.lists-and-tablesComment on this rule -
The consent log is exportable and has a retention period a stated period, an export, and a job that runs required
Only when the project has a form that collects data from a visitor.
The period is stated in writing by the client or their DPO and appears in the privacy policy. An export of the log produces a file carrying every stored key. A record aged past the period is gone after the scheduled job has run once.
Without it, records pile up behind a policy that promises they are deleted, which is worse than promising nothing.
Operations The client proves it Why this rule exists About Consent and legal
legal.consent-retentionComment on this rule -
The site's identity is set on purpose and the share card is seen title, tagline, separator, sameAs set; card seen in 3 apps required
The home page prints a deliberate title and tagline, every page uses one separator, the Organization node lists each official account in sameAs, and a dated screenshot of the home and one article preview exists for each of the three platforms.
Without it, the client's first share reads Just another WordPress site, and the profile links Google shows beside the brand belong to nobody.
Client document Website Design and Development Checklist section 8, item 4, in partnot public
Developer The build proves it About On-page signals
onpage.site-identityComment on this rule -
No write to a live database without a fresh dump of what it replaces dump the target first, size-checked, undo printed required
Every path in the repository that writes to a remote database dumps it first, stops when that dump fails a size and gzip check, and prints the restore command. The dump from the last production write is on disk, dated.
Without it, the dump taken before a push turns out to be a zero-byte gzip, and the only thing printed afterwards is a placeholder nobody can run.
Vendor documentation Hardening WordPress security/hardening#restricting-database-user-privileges, in part
Developer The build proves it About Operations
ops.db-write-backupComment on this rule -
Animation is cheap and stops when off screen transform and opacity only required
No looping animation runs while off screen, a performance trace shows no layout thrash during scroll, and no animation drives a layout-triggering property.
Without it, an accordion animating height relays out the page on every frame, making the one interaction people actually use the jankiest thing there.
Vendor documentation web.dev developer guides articles/animations-guide, in part
Developer The build proves it About Perf
perf.animation-costComment on this rule -
Every asset loads once, has content, and only where used no asset requested twice, no 0-byte file, 4 hints max required
In each sampled template's network log: zero URLs requested more than once, no stylesheet or script under 100 bytes, no library loaded by a template that does not use it, and four or fewer resource hints in the head.
Without it, the same file is fetched twice on one page load, and each request looks reasonable on its own until somebody reads the whole log.
Client document Website Design and Development Checklist section 10, item 5, in partnot public
Developer The build proves it About Perf
perf.enqueue-hygieneComment on this rule -
Optimiser output is regenerated and state classes safelisted every JS-toggled class in prod CSS, critical CSS rebuilt required
Every class toggled from JavaScript is present in the production stylesheet: open the menu, a modal and one filter on the live URL and confirm the styling applies. The critical CSS is no older than the build it shipped with.
Without it, the menu opens perfectly on staging and unstyled on the live site, once Remove Unused CSS strips the class only JavaScript adds.
Client document Website Design and Development Checklist section 10, item 7not public
Developer The build proves it About Perf
perf.optimiser-output-freshComment on this rule -
The theme's contracts are tests, and a deploy runs them first a suite in the repo, run by the deploy, red means no upload required
The deploy script runs the build, then the suite, then the upload, and exits on a red suite. The suite reads the built output rather than skipping it, and each mechanism the handover names has a test that fails when the mechanism is removed.
Without it, a green suite that no deploy ever runs ships the broken split point it exists to catch.
House rule Delivered reference builds, audited together a suite in the third build and the starter, run by no deploy script in any build; nothing in the two older buildsnot public
Developer The build proves it About Practices
practices.tests-before-deployComment on this rule -
The administrator list is named and owned before handover admin list named, build access removed required
wp user list --role=administrator names no account called admin and no build account above editor, and a dated written confirmation from the client - an email reply or a countersigned handover line - claims every remaining administrator.
Without it, the developer's own login is still an administrator on the live site a year later, and nobody has confirmed who the rest belong to.
Vendor documentation Hardening WordPress security/brute-force#hardening, in part
Operations The client proves it About Security and hardening
security.admin-accounts-at-handoverComment on this rule -
No response leaks a PHP error, a stack trace or a server path 500 status, no path, trace or error text required
No sampled page's HTML contains Fatal error, Warning:, Notice:, Stack trace or an absolute server path, a deliberate fatal on staging returns HTTP 500 carrying none of those five strings, and wp config get WP_DEBUG_DISPLAY returns false or is unset.
Without it, the first fatal on the client's site prints a page of PHP at a visitor and a map of the install at whoever asked for it.
Standard OWASP Application Security Verification Standard 5.0.0 16.5.1 (L2), in part
Developer The build proves it About Security and hardening
security.no-error-disclosureComment on this rule -
Login and every public form endpoint are rate limited 20 rapid POSTs, refused before the 20th required
Only when the project has a form that collects data from a visitor.
20 POSTs to wp-login.php inside one minute from one IP are refused with 429 or an explicit rejection before the 20th, and one normal login still succeeds after the window. Public form endpoints are graded by forms.anti-spam, not here.
Without it, wp-login.php takes password guesses as fast as a script can send them, and only the host is counting, if it counts at all.
Standard OWASP Application Security Verification Standard 5.0.0 6.3.1 (L1), in part
Developer The build proves it About Security and hardening
security.public-post-rate-limitComment on this rule -
Core, plugins, themes and PHP are current, and updates have an owner 0 pending, PHP supported, owner named required
wp core check-update and wp plugin list --update=available --format=count both return zero on handover day, PHP is on a branch php.net still lists under security support, and the handover names the party applying updates for twelve months.
Without it, a published plugin CVE stays open for months on a site where nobody ever agreed to be the person applying updates.
Vendor documentation Hardening WordPress security/hardening#vulnerabilities-in-wordpress, in part
Operations The build proves it About Security and hardening
security.versions-currentComment on this rule -
Structured data is present, valid and singular one node per type per page, no errors required
Google's Rich Results Test reports no errors on the home page and one interior page, and exactly one Organization node exists per page with a name matching the brand.
Without it, two Organization nodes give Google two different names for the brand, and nobody decides which one it takes.
Automated check:
seo-status:org-one,seo-status:org-brand,seo-status:org-sameasVendor documentation Google Search Central documentation appearance/structured-data/intro-structured-data, in part
Developer The build proves it About SEO
seo.structured-dataComment on this rule -
Consent records carry the context of the consent source URL, purpose and method, each set by the caller recommended
Only when the project has a form that collects data from a visitor.
Two consents captured by one submit produce two records with different purposes. Each record names the URL it was given on and a collection method matching how it was actually collected, not a default string.
Without it, every record still claims a ticked checkbox the day a double opt-in ships, and two consents from one form cannot be told apart.
Law Regulation (EU) 2016/679 (General Data Protection Regulation), consolidated text Art. 7(1), in part
Developer The build proves it About Consent and legal
legal.consent-record-contextComment on this rule -
Every validation rule runs again on the server a POST that bypasses the form is rejected field by field blocker
Only when the project has a form that collects data from a visitor.
A POST to the form endpoint carrying a missing required field and a malformed email is rejected naming both fields, and that request creates no message record, no consent record and no notification email.
Without it, curl posts past every browser check and writes a message record, a consent record and a notification email out of whatever junk it sent.
Ships in
wp-starter/form-registry- import it rather than rebuilding it.Client document Website Design and Development Checklist section 4, item 10not public
Developer The build proves it Why this rule exists About Forms
forms.server-side-validationComment on this rule -
Every consent is recorded with what it takes to prove it who, when, the exact wording shown, and its version blocker
Only when the project has a form that collects data from a visitor.
Submit a form with the box ticked and open the stored record: it identifies the person, carries a timestamp, and quotes the wording verbatim with a version. Change the published wording, submit again, and the two records differ in wording and in version.
Without it, a disputed opt-in comes down to your word against theirs, and nothing stored says what wording the person actually saw.
Ships in
wp-starter/consent-log- import it rather than rebuilding it.Law Regulation (EU) 2016/679 (General Data Protection Regulation), consolidated text Art. 7(1), in part
Developer The build proves it Why this rule exists About Consent and legal
legal.consent-recordComment on this rule -
No analytics or marketing tag fires before a choice 0 third-party requests before a choice, exactly 1 container blocker
Only when the project loads analytics, advertising or marketing tags.
On a first visit with no choice made, the network log shows 0 requests to any analytics or marketing host. Accepting the analytics category makes those requests appear; refusing keeps the count at 0.
Without it, Google has already been pinged before the visitor is asked, so refusing changes nothing and the banner is decoration.
Ships in
wp-starter/analytics-registry- import it rather than rebuilding it.Regulator Recommandation cookies et autres traceurs, version consolidee 2 (chapeau), in part
Developer The build proves it Why this rule exists About Consent and legal
legal.no-tags-before-consentComment on this rule -
A working skip link is the first focusable element required
The first Tab press on a fresh page load reveals the skip link, and activating it moves focus into main so the next Tab lands on page content, not back in the header.
Without it, every keyboard visitor re-tabs the full header and nav on every single page before reaching the content they came for.
Ships in
wp-starter/skip-link- import it rather than rebuilding it.Standard Web Content Accessibility Guidelines (WCAG) 2.1 2.4.1 (A), in part
Developer The build proves it About A11y
a11y.skip-linkComment on this rule -
An editor can duplicate any content item, translations included one action, one draft per language, no linked twin required
Duplicate one item of each editable type: a draft appears with the original's fields, terms and image, and publishing it changes nothing on the original. On a multilingual site one action yields one draft per language and none of them carries a link back to the source.
Without it, the editor rebuilds a forty-field page by hand, or clones it with a plugin whose copy the original silently overwrites on the next save.
Ships in
wp-starter/duplicator- import it rather than rebuilding it.House rule Delivered reference builds, audited together inc/duplicate-core.php, the third build; a prefetch guard only in one of the twonot public
Developer The build proves it About The admin the client receives
admin.duplicate-contentComment on this rule -
Filter changes do not litter the back button one back press leaves the page required
Only when the page has a listing, archive or search with filters.
After changing filters five times, one press of the browser back button leaves the listing page entirely rather than stepping back through filter states.
Without it, ten filter clicks cost ten presses of Back to leave the page, which every visitor reads as a broken back button.
Ships in
wp-starter/filter-url-state- import it rather than rebuilding it.House rule Delivered reference builds, audited together replaceState on filter change, one build of the twonot public
Developer The build proves it Why this rule exists About Colibrity
colibrity.filter-history-noiseComment on this rule -
Design values reach the code as generated tokens, not typed numbers one token source, generated output, a drift test that fails required
Only when the build works from a new design file rather than an existing template.
The repository holds one token source and a generator, the built CSS carries every token in it, a test fails when the two disagree, and a grep of the components finds no colour literal outside the token files.
Without it, the button ships a hex nobody can find in the design file, and the next restyle hunts every literal by eye.
Ships in
wp-starter/design-tokens- import it rather than rebuilding it.House rule Delivered reference builds, audited together DESIGN.md to generated tokens with a drift test, third build and starter; typed variables in both older buildsnot public
Developer The build proves it About Colibrity
colibrity.tokens-from-the-design-fileComment on this rule -
The events that count are agreed, fired once, and observable an agreed list, each firing exactly once per action required
Only when the project loads analytics, advertising or marketing tags.
The agreed list is written down and dated by Colibrity. Doing each action once shows exactly one event of that name in GA4 DebugView, including after two in-page navigations, and the Meta copy is not counted twice.
Without it, analytics shows traffic and never a single lead, because a fetch-submitted form fires no page load for a tag to hang on.
Ships in
wp-starter/conversion-events- import it rather than rebuilding it.Client document Website Design and Development Checklist section 14, item 2, in partnot public
Developer The agency proves it About Email, CRM and analytics
comms.conversion-eventsComment on this rule -
A form still submits from a cached page fresh token at submit time, from a no-store endpoint required
Only when the project has a form that collects data from a visitor.
A form on a page served with a cache HIT older than the token lifetime submits successfully as an anonymous visitor, and the token request answers with Cache-Control: no-store.
Without it, every anonymous submit fails with a 403 while the developer's logged-in test passes, and the enquiries are lost in silence.
Ships in
wp-starter/form-registry- import it rather than rebuilding it.House rule Delivered reference builds, audited together a fresh-nonce route in the third build; the two others print the nonce into the pagenot public
Developer The build proves it About Forms
forms.cache-safe-submitComment on this rule -
Every HTML response carries the baseline security headers 5 response headers, HSTS max-age 1 year required
curl -sI on the home page and two inner pages returns all five headers with those values. Strict-Transport-Security carries max-age=31536000 and appears over https only, never on http or local. Where a page cache is in use, a response marked HIT carries them too.
Without it, the site can be framed on someone else's page, referrers leak full URLs to third parties, and browsers keep retrying over http.
Ships in
wp-starter/security-headers- import it rather than rebuilding it.Automated check:
seo-status:hdr-strict-transport-security,seo-status:hdr-x-frame-options,seo-status:hdr-x-content-type-options,seo-status:hdr-referrer-policy,seo-status:hdr-permissions-policyStandard OWASP Secure Headers Project Best Practices - Configuration proposal, in part
Developer The build proves it About Security and hardening
security.response-headersComment on this rule
C. Eyes only 43 items
No tool can answer these. They are read, clicked and listened to.
-
Images carry alt text that earns its place empty alt on decorative, never "image of" blocker
Every image has an alt attribute, decorative ones are empty, and reading the alt text of a page aloud conveys the same information as seeing it.
Without it, a screen reader reads out the filename instead, and a client-filled media library passes the scanner with alt text nobody wrote.
Standard Web Content Accessibility Guidelines (WCAG) 2.1 1.1.1 (A), in part
Developer The build proves it Why this rule exists About A11y
a11y.alt-textComment on this rule -
Everything works with a keyboard alone Tab, Shift-Tab, Enter, Space, Escape blocker
Every interactive control can be reached and operated by keyboard, focus never enters a hidden element, and no component traps focus except a modal, which releases it on Escape.
Without it, a mobile menu built from an href-less anchor never opens for someone on a keyboard - one delivered build shipped exactly that.
Standard Web Content Accessibility Guidelines (WCAG) 2.1 2.1.1; 2.1.2 (A), in part
Developer The build proves it Why this rule exists About A11y
a11y.keyboard-operableComment on this rule -
No information is carried by colour alone greyscale filter loses nothing, 0 colour-only distinctions blocker
View the key frames with a greyscale filter on: links, required markers, statuses, chart series, map keys and the active tab are all still tellable apart, with 0 distinctions left to hue alone. Keep the dated greyscale export as the evidence.
Without it, a link inside a rich-text field looks the same as the words around it - both delivered themes strip underlines and never put them back.
Standard Web Content Accessibility Guidelines (WCAG) 2.1 1.4.1 (A), in part
Designer The agency proves it Why this rule exists About Design and UI kit
design.not-colour-aloneComment on this rule -
Refusing cookies is as easy as accepting them refuse in one click, at the same visual weight as accept blocker
Only when the project loads analytics, advertising or marketing tags.
Both choices are reachable in one click from the banner's first screen, at the same size, weight and contrast. Refusing takes no more clicks than accepting, and neither is styled as the quieter of the two.
Without it, refusing takes more clicks than accepting, so CNIL does not count what the banner collected as consent at all.
Regulator Recommandation cookies et autres traceurs, version consolidee 2.3 (modalites du refus), in part
Designer The build proves it Why this rule exists About Consent and legal
legal.cookie-bannerComment on this rule -
Video and audio carry captions and controls captions on speech; audio over 3s, motion over 5s required
Only when the project has video or audio, or content that starts moving on its own.
Every video with speech has captions that match the audio, and every auto-playing item can be paused with a keyboard.
Without it, a deaf visitor gets nothing from a video testimonial, and the one delivered build with speech video shipped zero track elements.
Standard Web Content Accessibility Guidelines (WCAG) 2.1 1.4.2; 1.2.2; 2.2.2 (A), in part
Developer The build proves it About A11y
a11y.media-alternativesComment on this rule -
One page and one form are driven with a screen reader VoiceOver or NVDA, one content page plus one form required
The report names the screen reader and browser used, lists the headings and landmarks in the order they were announced, and confirms the invalid submit was announced. Zero unlabelled controls were met on the two pages.
Without it, nobody has driven the site by ear even once, so an announcement order that makes no sense ships with every automated check green.
Client document Website Design and Development Checklist section 12, item 9, in partnot public
Developer The build proves it About A11y
a11y.screen-reader-passComment on this rule -
The page survives 200 percent zoom and a 320px viewport no loss at 200%, no h-scroll at 320px, body text 16 px+ required
At 200 percent zoom no content is lost or overlapping, at 320px wide the page scrolls vertically only, and body text computes to at least 16 px at every sampled width.
Without it, body overflow-x hidden suppresses the measurable instead of passing it, and the clipped content is unreachable, not just off-screen.
Standard Web Content Accessibility Guidelines (WCAG) 2.1 1.4.10; 1.4.4 (AA), in part
Developer The build proves it About A11y
a11y.zoom-and-reflowComment on this rule -
The client's admin is trimmed, and the trim can always be undone declared in code, reversible, reaches the real accounts required
What is hidden is a list in the repository. An account the client actually uses sees the trimmed admin and can still reach the control that undoes it. No account can be locked out of its own reversal.
Without it, the client's own people are administrators, and a trim that exempts administrators leaves the only accounts it exists to help untouched.
House rule Delivered reference builds, audited together inc/admin-cleanup.php, both buildsnot public
Developer The build proves it Why this rule exists About The admin the client receives
admin.client-modeComment on this rule -
One control writes one setting no two boxes claiming the same value required
For each setting the client can change, exactly one control in the admin writes it. Where a plugin supersedes a theme feature, the theme's control is not rendered while that plugin is active, checked with the plugin on and off.
Without it, the client sets the value in the plugin, the theme's box overwrites it on the next save, and nothing says which one won.
House rule Delivered reference builds, audited together theme SEO panel hidden while Yoast is active, both buildsnot public
Developer The build proves it About The admin the client receives
admin.one-control-per-settingComment on this rule -
A broken form or CRM connection raises an alert a failed send alerts a named human inside one day required
Only when the site sends email of its own - notifications, autoresponders, transactional.
Break the CRM credential on purpose and submit once. An alert naming the site and the failure reaches the named recipient within 24 hours, and the handover names that recipient and the date they took it on.
Without it, a broken credential eats enquiries into a log file nobody reads, and the first to notice is the client asking why nobody called back.
Client document Website Design and Development Checklist section 13, item 5, in partnot public
Operations The agency proves it About Email, CRM and analytics
comms.delivery-alertingComment on this rule -
Transactional emails render in the clients people use Gmail, Outlook and iPhone Mail, plus a text part required
Only when the site sends email of its own - notifications, autoresponders, transactional.
The same message is opened in Gmail, Outlook and iPhone Mail, with a dated screenshot of each: no broken layout, no clipping notice, every link working. The raw source carries a text/plain part.
Without it, an Outlook reader gets a broken stack of tables and a Gmail reader gets the end of the message hidden behind a clipping link.
Client document Website Design and Development Checklist section 13, item 2, in partnot public
Developer The build proves it About Email, CRM and analytics
comms.email-renderingComment on this rule -
Every template is opened in all three browser engines Blink, Gecko and desktop WebKit - three passes required
Every template on the template list has been opened in Chrome, Firefox and desktop Safari - three engines, none checked in fewer - and each difference found is either fixed or written down.
Without it, a Firefox-only break ships because every check ran in Chromium, and the client's own team is the one that finds it.
Client document Website Design and Development Checklist section 15, item 4, in partnot public
Developer The build proves it About Launch and handover
delivery.browser-matrixComment on this rule -
The client leaves handover able to run the site a dated recording, plus a credential inventory by holder required
The client has a dated recording of the session covering editing content, adding a page and what must not be touched, naming at least 2 attendees. The wider account table is not graded anywhere since ops.account-inventory was withdrawn - raise it, do not check it.
Without it, the client cannot add a page without ringing us, and nobody can say who holds the DNS zone or the mail relay when it breaks.
Client document Website Design and Development Checklist section 15, item 7, in partnot public
Developer The agency proves it About Launch and handover
delivery.client-handoverComment on this rule -
Uptime monitoring and a restorable backup are live at launch checks at 5 min or better, one dated restore performed required
The monitor's public status URL shows checks on the home page at five minutes or better, and the handover names the person it alerts and the date they took it on. If nobody will own it, the handover records that and it is not ticked.
Without it, the site is down all weekend before anyone notices, because the client is the only monitor and nobody was named to be told.
Client document Website Design and Development Checklist section 15, item 6, in partnot public
Operations The client proves it About Launch and handover
delivery.monitoring-and-backupsComment on this rule -
Every unique section and page has its own mockup one named frame per section and per page required
Only when the build works from a new design file rather than an existing template.
On the handoff date, the frame count in the file matches the sections and page types in the agreed sitemap: 0 sections and 0 page types without a named frame. Record both counts and that date in the handoff message.
Without it, a page type nobody drew - the archive, the 404, the mobile variant - gets guessed at during the build and was never in the estimate.
Client document Website Design and Development Checklist section 1, item 2not public
Designer The agency proves it About Design and UI kit
design.mockup-coverageComment on this rule -
Every animated surface has a defined motion spec 8 surfaces, each with trigger, duration and easing required
Only when the build works from a new design file rather than an existing template.
The handoff file carries a motion sheet naming all eight surfaces - text reveal, button hover, image reveal, card hover, preloader, page transition, the menu on desktop and mobile, and the footer - each with a trigger, a duration in ms and a named easing, or not applicable.
Without it, the developer picks every duration himself, which is what both delivered themes did, and the client first sees the timing in a browser.
Client document Website Design and Development Checklist section 2, items 1-8, in partnot public
Designer The agency proves it About Design and UI kit
design.motion-specComment on this rule -
Layer and component names are agreed with the developer the Figma name is the name in code, 0 renames after handoff required
Only when the build works from a new design file rather than an existing template.
The kickoff note lists the agreed name of every component and section frame and is countersigned by the developer. At handoff the names in the file are that same list: 0 renames between the agreed list and the delivered file.
Without it, a name agreed in the mockup is renamed after handoff, and one word changed in Figma becomes four file renames and a re-review.
Client document Website Design and Development Checklist section 1, item 7, in partnot public
Designer The agency proves it About Design and UI kit
design.naming-conventionComment on this rule -
The design specifies every state of every interactive element hover, focus, active, disabled, loading, current - all six required
Only when the build works from a new design file rather than an existing template.
Every interactive component in the kit has all six states present as variants, with 0 components missing one. The focus variant is identical across components and matches the kit's single focus style.
Without it, the submit button looks identical while it is sending - one delivered theme sets a loading class in JS that no stylesheet ever consumes.
Client document Website Design and Development Checklist section 3, items 2-7not public
Designer The agency proves it About Design and UI kit
design.state-setComment on this rule -
Text over imagery carries a scrim the design specifies 4.5:1 at the image's darkest and lightest region required
Only when the build works from a new design file rather than an existing template.
The mockup names the overlay colour and opacity, or the gradient stops, for every text-over-media block. A dated export shows each block over the lightest and darkest plausible photo, body copy at 4.5:1 and display text at 3:1 in both.
Without it, an editor uploads a lighter photo than the mockup's and the heading over it falls under 3:1 - a delivered hero already sits at 2.85:1.
Standard Web Content Accessibility Guidelines (WCAG) 2.1 1.4.3 (AA), in part
Designer The agency proves it About Design and UI kit
design.text-over-mediaComment on this rule -
The UI kit is built and published before the build starts components, variants, variables, styles, 0 detached required
Only when the build works from a new design file rather than an existing template.
Colibrity shares a published library URL at kickoff. Opening it, every colour and text value used in the mockups resolves to a published variable or style, and the file holds 0 detached instances of a kit component.
Without it, raw hex spreads through the stylesheets, 171 of them across 47 files in one delivered theme, and a brand tweak becomes a search and replace.
Client document Website Design and Development Checklist section 1, item 1, in partnot public
Designer The agency proves it About Design and UI kit
design.ui-kitComment on this rule -
A successful submit produces a confirmation nobody can miss focus lands on it, announced, still there at 30 s required
Only when the project has a form that collects data from a visitor.
After a successful submit, focus is on the confirmation, a screen reader announces it, and it is still on screen 30 seconds later. Where it is a thank-you page, the handover names its URL.
Without it, the confirmation is gone in three seconds, as it is in both delivered themes, and the visitor sends the form again to check it worked.
Client document Website Design and Development Checklist section 4, item 15, in partnot public
Developer The build proves it About Forms
forms.confirmationComment on this rule -
Backups cover the database and the uploads, on a stated schedule daily database, weekly files, one copy off-account required
A dated screenshot of the backup listing shows a database backup under 24 hours old and a file backup under 7 days old. The handover states retention in days and names the copy held outside the hosting account.
Without it, the newest restorable copy on the box turns out to be a month old, and the uploads have no copy at all.
Vendor documentation Hardening WordPress security/hardening#data-backups, in part
Operations The agency proves it Why this rule exists About Operations
ops.backup-coverageComment on this rule -
A destructive deploy refuses to run against the wrong target the resolved target is checked, not just typed required
Pointed at the wrong target on purpose, the production deploy refuses and exits non-zero before transferring anything. A prompt that accepts a typed word and proceeds does not satisfy this.
Without it, an rsync --delete aimed at the wrong alias empties a live site's files, and the typed confirmation was answered correctly.
House rule Delivered reference builds, audited together PROD_EXPECTED_URL_HOST, one build of the twonot public
Operations The build proves it About Operations
ops.deploy-target-pinnedComment on this rule -
The site has been restored and rolled back, once, on purpose restore and rollback both run, dated, output kept required
The handover carries dated terminal output from two runs: a restore of a backup no more than 7 days old into a non-production target, ending with that target's home page returning 200, and a rollback to the previous release. A tick with no output does not settle it.
Without it, the first restore anybody attempts is during a real outage, and that is when the rollback turns out not to exist.
Vendor documentation Hardening WordPress security/brute-force#hardening, in part
Operations The build proves it Why this rule exists About Operations
ops.recovery-drillComment on this rule -
Every dynamic component handles empty, long and broken zero items, one, many, long title, no image required
Emptying a listing shows a deliberate empty state rather than a blank region. A title of double the expected length does not break its layout.
Without it, a filter that matches nothing leaves a blank strip on the page and the visitor decides the site is broken.
House rule Delivered reference builds, audited together a rendered empty state per listing, both buildsnot public
Developer The build proves it About Practices
practices.empty-statesComment on this rule -
The project ships with the notes needed to run it one page in the repo, not a chat thread required
Someone who has never seen the project can build, run and deploy it from that page alone.
Without it, somebody deactivates a plugin the theme quietly depends on, because no page anywhere says which ones are load-bearing.
House rule Delivered reference builds, audited together README.md plus a .claude/ doc set, both buildsnot public
Developer The build proves it About Practices
practices.handover-notesComment on this rule -
The layout survives the phone's real viewport nothing clipped by the toolbar or notch, landscape usable required
On a real phone at 390x844: no section clipped by the browser toolbar in either orientation, no text or control under the notch or home indicator, and a sticky header at 15 percent of viewport height or less in landscape.
Without it, the phone's home indicator sits on top of the fixed CTA bar, and the visitor cannot tap the one button that matters.
Client document Website Design and Development Checklist section 11, item 5, in partnot public
Developer The build proves it About Practices
practices.mobile-viewport-chromeComment on this rule -
Editable content is editable, not baked into templates copy, images, links and order, from fields required
A content editor can change the text and images of every public page, and reorder the sections of a flexible page, without a developer.
Without it, the client emails you to change a phone number, and a one-word fix costs a developer, a deploy and an invoice.
House rule Delivered reference builds, audited together page.php loops have_rows(page_blocks), both buildsnot public
Developer The build proves it About Practices
practices.no-hardcoded-contentComment on this rule -
Anything animated or video-driven is checked on a real device a real iPhone and a real mid-range Android required
Every page with entrance animation or video is opened on a real phone in a fresh private tab, and scrolling stays smooth with video playing.
Without it, the hero video plays in every simulator and stays black on the client's iPhone, where iOS refuses play() outside a real gesture.
House rule Delivered reference builds, audited together a real-device debugging procedure in .claude/, both buildsnot public
Developer The build proves it About Practices
practices.real-device-checkComment on this rule -
The layout holds at every width, not just the design widths 320 to 2560, no h-scroll, no overlap required
No horizontal scrollbar at any width from 320 up, no clipped or overlapping content, and no layout that only works at the exact design breakpoints.
Without it, a 900px laptop sits between two drawn widths, and nobody opens one before launch, so that is where the heading lands on the image.
House rule Delivered reference builds, audited together one breakpoint map plus body overflow-x hidden, both buildsnot public
Developer The build proves it About Practices
practices.responsive-breakpointsComment on this rule -
The 404 and 500 pages are designed, not server defaults site chrome, a route back, no raw server 500 required
The 404 opens with the site header, footer and type styles and at least one working link back into the site. Forcing a 500 on staging returns a page in the same chrome, not the raw server or PHP default.
Without it, a PHP fatal drops the visitor onto WordPress core's unstyled critical-error screen, with no header and no way back.
Client document Website Design and Development Checklist section 3, item 11, in partnot public
Developer The build proves it About Interface states
states.error-page-designComment on this rule -
Every interactive element ships all of its states hover, active, disabled and open, script-inserted included required
Sample one control of each kind on three templates: hover, active, disabled and open each render a visible change. An element inserted by a filter or a load-more shows the same four states as one present at first load. Nothing a hover reveals is the only route to it on touch.
Without it, a card arriving from a filter fetch is dead to the touch while an identical one above it lights up on hover.
Client document Website Design and Development Checklist per-page item 13, in partnot public
Developer The build proves it About Interface states
states.interactive-setComment on this rule -
Anything that takes time says so visible feedback within 500 ms, cleared on failure too required
Throttle to Slow 3G, then submit a form and change a filter. Each shows a busy state within 500 ms. Force one to fail and the busy state clears rather than leaving a spinner running forever.
Without it, people hit submit a second time because nothing moved, and a failed request leaves the spinner turning forever.
Client document Website Design and Development Checklist section 4, item 14, in partnot public
Developer The build proves it About Interface states
states.loading-feedbackComment on this rule -
Sticky header and menu scroll behaviour is decided up front 0 shift on stick, anchor clears the header, scroll locked required
Scrolling past the stick point shifts the page by 0 pixels. A link to #section leaves its heading fully below the header. With the menu open the page behind it does not scroll, and closing it returns to the same position.
Without it, the page behind an open off-canvas menu scrolls away under the visitor's finger, and every anchor lands its heading under the header.
Client document Website Design and Development Checklist section 11, item 6, in partnot public
Developer The build proves it About Interface states
states.sticky-chromeComment on this rule -
The site publishes an accessibility statement target, known gaps, a contact route recommended
A linked, reachable page names the standard targeted, lists known exceptions, and gives a working contact address.
Without it, nobody can say what the site targets or where to report a problem, and the client has nothing to produce when a complaint arrives.
Developer The build proves it About A11y
a11y.statementComment on this rule -
The admin reads in the language the editor set labels follow wp-admin's language, keys never do recommended
Only when the site serves more than one language.
Switching the wp-admin display language switches the labels of the site's own post types, columns and meta boxes. No slug, meta key or field name changes with it.
Without it, labels follow the content-language switcher instead of the editor's own, so half the meta boxes stay in a language they cannot read.
House rule Delivered reference builds, audited together bilingual label helper, one build of the twonot public
Developer The build proves it About The admin the client receives
admin.editor-languageComment on this rule -
Performance and behaviour changes ship one at a time recommended
Each performance claim in the handover names the single change it came from and the before and after measurement.
Without it, eight changes ship in one commit, the score drops, and there is no way to tell which one did it.
House rule PERFORMANCE.md PERFORMANCE.md:89-92, in partnot public
Developer The build proves it About Practices
practices.one-change-per-deployComment on this rule -
The heading outline reads as an outline recommended
Reading only the headings of a page conveys what the page is about, in order, without needing the body copy.
Without it, a screen-reader user skimming the headings hears the brand name and a sentence fragment ending on a preposition, and learns nothing.
Standard Web Content Accessibility Guidelines (WCAG) 2.1 2.4.6 (AA), in part
Developer The build proves it About SEO
seo.headings-describe-contentComment on this rule -
A visible focus indicator on every focusable element one global style, 3:1 against its background blocker
Tabbing through a page shows an obvious indicator on every stop, with at least a 3:1 contrast against its background, including over images and gradients.
Without it, a global focus ring hidden behind @media (hover: hover) paints nothing on a touch laptop, so the keyboard user tabs blind.
Ships in
wp-starter/focus-tokens- import it rather than rebuilding it.Standard Web Content Accessibility Guidelines (WCAG) 2.1 2.4.7; 1.4.11 (AA), in part
Developer The build proves it Why this rule exists About A11y
a11y.focus-visibleComment on this rule -
prefers-reduced-motion is honoured everywhere final state, not a faster animation blocker
With reduced motion enabled at OS level, no element animates on scroll or entrance, all content is visible and in its final position, and nothing auto-plays.
Without it, footer parallax keeps running for a visitor with a vestibular disorder who already asked their OS to stop it, and nausea lasts hours.
Ships in
wp-starter/motion-guard- import it rather than rebuilding it.Standard Web Content Accessibility Guidelines (WCAG) 2.1 2.2.2; 2.3.3 (A, AAA), in part
Developer The build proves it Why this rule exists About A11y
a11y.reduced-motionComment on this rule -
Modals trap focus, return it, and close on Escape required
Only when the project has a modal, drawer, cookie banner, lightbox or off-canvas menu.
Opening a modal moves focus inside, Tab cycles only within it, Escape closes it, and focus returns to the trigger.
Without it, tabbing out of an open drawer lands on links behind it, and closing sends focus back to the top of the document, not the trigger.
Ships in
wp-starter/dialog-a11y- import it rather than rebuilding it.Standard Web Content Accessibility Guidelines (WCAG) 2.1 2.1.2; 2.4.3; 4.1.2 (A), in part
Developer The build proves it About A11y
a11y.dialog-behaviourComment on this rule -
Adding a block shows a picture first and never lands empty a rendered thumbnail per layout, real default copy recommended
Every layout in the picker shows a thumbnail rendered from the block itself, and the thumbnails are regenerated by one command. Adding any block to an empty page renders visible, sensible content before the editor types a word.
Without it, the editor adds four blocks by name to see what they look like and deletes three, every time.
Ships in
wp-starter/block-defaults- import it rather than rebuilding it.House rule Delivered reference builds, audited together inc/admin-blocks.php and inc/block-defaults.php, the third build onlynot public
Developer The build proves it About Colibrity
colibrity.adding-a-blockComment on this rule -
The admin has been tested by someone who did not build it a dated sheet, a tester off the build recommended
The handover carries a dated observation sheet naming the tester, the tasks attempted and each point of friction with what was done about it. The tester is not a developer on the build.
Without it, the client is the first person to discover the block picker is a mystery, on a call, after the invoice.
Ships in
wp-starter/editor-test-kit- import it rather than rebuilding it.House rule Delivered reference builds, audited together docs/editor-test in the third build; nothing of the kind in the two othersnot public
Developer The build proves it About Launch and handover
delivery.editor-testComment on this rule