Read backwards, on purpose. Every other page here starts from a rule and names its source; this one starts from the source and names the rule, which is the only direction an item nobody acted on can show up in.
Neither document is named to a client here or on the site. The grid is an outside agency's audit of one delivered site, and a defect list for somebody else's project is not ours to publish. What is published is the control point and what this standard did with it, which is nameless and is the only half a reader has any use for.
The design and build checklist
- 181 became a rule
- 7 declined in public
- 4 half and half
1. Design & UI Kit 7
| Item | What they asked for | Outcome | What we did with it |
|---|---|---|---|
| 1.1 | UI Kit built: components, variants, auto-layout, variables, published styles | Became a rule | design.ui-kitSame requirement, and the rule adds a measurable: 0 detached instances. |
| 1.2 | Separate mockups for every unique block and page | Became a rule | design.mockup-coverageOne named frame per section and per page. |
| 1.3 | Contrast meets WCAG AA: 4.5:1 body, 3:1 large text and UI | Became a rule | design.contrast-in-mockup, a11y.contrastSplit deliberately: proven in the mockup, then measured in the browser. |
| 1.4 | Text over images readable, overlay or scrim where needed | Became a rule | design.text-over-mediaThe rule adds where to measure - the image's darkest and lightest region. |
| 1.5 | Every action has clear visual feedback | Became a rule | design.state-set, states.interactive-set, states.loading-feedbackSplit across the design side and the build side, with the 500 ms threshold on the third. |
| 1.6 | Meaning never carried by colour alone | Became a rule | design.not-colour-aloneThe rule gives it a test: a greyscale filter loses nothing. |
| 1.7 | Naming convention agreed with the developer | Became a rule | design.naming-conventionThe one item of Mariya's that had no counterpart on the developer side until the standard added html.bem-naming's partner. |
2. Animations 14
| Item | What they asked for | Outcome | What we did with it |
|---|---|---|---|
| 2.1 | Text reveal | Became a rule | design.motion-specOne of the eight surfaces the motion sheet must name. |
| 2.2 | Button hover, all buttons | Became a rule | design.motion-specOne of the eight surfaces. |
| 2.3 | Image reveal | Became a rule | design.motion-specOne of the eight surfaces. |
| 2.4 | Hover on multi-element cards and images | Became a rule | design.motion-specOne of the eight surfaces - card hover. |
| 2.5 | Preloader | Became a rule | design.motion-spec, states.preloader-budgetThe spec is design's; the 3 s cap is the build's. |
| 2.6 | Page transitions | Became a rule | design.motion-specOne of the eight surfaces. |
| 2.7 | Menu open, desktop and mobile | Became a rule | design.motion-specOne of the eight surfaces - menu on desktop and mobile. |
| 2.8 | Footer | Became a rule | design.motion-specOne of the eight surfaces. |
| 2.9 | Every hover effect has a touch equivalent | Became a rule | states.interactive-setCarried since 2026-09-10 by states.interactive-set, which now says nothing a hover reveals is the only route to it on touch. |
| 2.10 | `prefers-reduced-motion` respected | Became a rule | a11y.reduced-motionThe rule adds the failure mode: the final state, not a faster animation. |
| 2.11 | Preloader has a max duration and a fallback | Became a rule | states.preloader-budgetThe rule sets the cap she left open: visible within 3 s of first byte whatever fails. |
| 2.12 | Content stays visible if JS fails | Became a rule | states.no-js-fallbackThe rule's measurable is 0 elements left at opacity 0 with JavaScript off. |
| 2.13 | Only `transform` and `opacity` animated | Became a rule | perf.animation-costSame constraint, plus stopping off-screen animation. |
| 2.14 | Scroll animations work on anchor arrival and back navigation | Became a rule | states.scroll-reveal-recoveryVerbatim the same two cases: anchor arrival and back navigation. |
3. States 12
| Item | What they asked for | Outcome | What we did with it |
|---|---|---|---|
| 3.1 | Dropdowns and select menus | Became a rule | design.state-set, states.interactive-setSelects are named in both rules' do text. |
| 3.2 | Hovers on dynamic elements | Became a rule | states.interactive-set, design.state-setstates.interactive-set names this case exactly - an element inserted by a filter shows the same states as one present at first load - and design.state-set carries the design half, hover being one of its six. |
| 3.3 | Focus state, visible, on every interactive element | Became a rule | a11y.focus-visible, design.state-setThe rule adds the 3:1 threshold and one global style. |
| 3.4 | Active / pressed | Became a rule | design.state-set, states.interactive-set |
| 3.5 | Disabled | Became a rule | design.state-set, states.interactive-setdesign.state-set names disabled as one of the two states that always go missing. |
| 3.6 | Loading | Became a rule | states.loading-feedback, design.state-setThe rule owns the 500 ms threshold and adds clearing on failure. |
| 3.7 | Current page / active nav item | Became a rule | states.current-page, design.state-setThe build rule's measurable is exactly one aria-current=page per navigation; current is one of the six states design.state-set requires the kit to draw. |
| 3.8 | Empty states: no results, empty list, empty cart | Became a rule | practices.empty-statesHer three cases are inside the rule's five. |
| 3.9 | Error messages | Became a rule | a11y.form-errorsThe rule adds announcement and focus placement. |
| 3.10 | Form success pop-up, dedicated page on the configurator | Became a rule | forms.confirmationThe rule's measurable is focus lands on it, announced, still there at 30 s. |
| 3.11 | 404 and 500 pages, in the right language | Became a rule | states.error-page-design, states.error-pagesDeliberately two rules: one designs them, one checks the status code and the lang attribute. |
| 3.12 | Overflow: long titles, long words, missing images | Became a rule | practices.empty-statesLong title and missing image are two of the rule's five cases. |
4. Forms 18
| Item | What they asked for | Outcome | What we did with it |
|---|---|---|---|
| 4.1 | Input text 16px minimum on mobile, no iOS auto-zoom | Became a rule | forms.input-font-sizeThe rule adds the viewport to measure at, 390 px, and that pinch-zoom must still work. |
| 4.2 | Required vs optional marked | Became a rule | a11y.form-labelsCarried since 2026-09-10 by a11y.form-labels: required fields marked in the label and in the markup, and the convention stated once. |
| 4.3 | Real `<label>` on every input, not a placeholder | Became a rule | a11y.form-labelsIdentical position, and it is a blocker both builds fail on the visible half. |
| 4.4 | Correct `type` and `autocomplete` attributes | Became a rule | forms.input-type-and-autocompleteThe rule pins the token list to the spec. |
| 4.5 | Errors shown on blur, not after full submission | Became a rule | forms.error-timingThe rule adds the other half: cleared once valid. |
| 4.6 | Error messages explicit and in the right language | Became a rule | a11y.form-errorsLanguage is carried here and by html.doctype-and-lang. |
| 4.7 | Email validated: `letter@letter.co`, 2 letters minimum after the dot | Became a rule | forms.value-formatsThe rule keeps the dot-TLD floor and drops the two-letter minimum, because .co and single-letter-plus-TLD cases exist; the do text argues it. |
| 4.8 | Phone validated with country code if international | Became a rule | forms.value-formatsThe rule refuses a pattern on the phone field and stores E.164 instead, which is stricter about storage and looser about input than the item. |
| 4.9 | Errors announced to screen readers, focus moved to the first one | Became a rule | a11y.form-errorsBoth halves - announced, focus on the first. |
| 4.10 | Server-side validation, not just client-side | Became a rule | forms.server-side-validationThe rule's measurable is a POST that bypasses the form, rejected field by field. |
| 4.11 | Anti-spam: honeypot or captcha + rate limiting | Became a rule | forms.anti-spam, security.public-post-rate-limitShe allows honeypot OR captcha; the rule requires three layers including the rate limit, so it is stricter than its source. |
| 4.12 | Double-submit blocked | Became a rule | forms.submit-lifecycle1 record on a double click. |
| 4.13 | Values preserved if submission fails | Became a rule | forms.submit-lifecycleValues kept on failure. |
| 4.14 | Spinner or "sending" message beyond 0.5s | Became a rule | states.loading-feedbackHer 0.5 s is the rule's 500 ms; the rule adds clearing on failure and a live region rather than only a spinner. |
| 4.15 | Clear confirmation after submission | Became a rule | forms.confirmation |
| 4.16 | File uploads: allowed types, max size, clear rejection message | Became a rule | forms.file-uploads, security.upload-types-and-executionThe rule adds MIME sniffing rather than trusting the extension, and a second rule keeps uploads non-executable. |
| 4.17 | Results sent by email and/or to the CRM | Became a rule | comms.crm-field-map, comms.submission-deliveryHer wording permits email only with no stored record, which comms.submission-delivery deliberately refuses. The standard is stricter than its source here. |
| 4.18 | Thank-you page set to `noindex` | Became a rule | crawl.indexability-decidedThank-you pages are named in her 7.6 and covered by the recorded decision per template. |
5. Consent & legal 19
| Item | What they asked for | Outcome | What we did with it |
|---|---|---|---|
| 5.1 | Terms checkbox: "I accept the general terms and conditions of [Company]" | Became a rule | legal.terms-consent-checkboxThe rule requires the box name the company, as her wording does. |
| 5.2 | Terms link opens a pop-up or a dedicated page | Became a rule | legal.documents-publishedThe rule requires an own permalink returning 200, linked from the footer and every form. |
| 5.3 | Checkbox unchecked by default, mandatory | Became a rule | legal.terms-consent-checkboxThe rule adds the two failures: still unchecked after a back-nav, and refused server-side. |
| 5.4 | Newsletter checkbox separate and optional | Became a rule | legal.newsletter-separateThe rule's measurable is 0 subscriber records when terms are ticked and newsletter is not. |
| 5.5 | Newsletter opt-ins sent to CRM or by email | Became a rule | comms.crm-field-mapConsent fields are named in the rule's own accept. |
| 5.6 | Cookie banner with granular choice, refusing as easy as accepting | Became a rule | legal.cookie-bannerRefuse in one click at the same visual weight. Both reference builds fail this, and it is CNIL's subject rather than ours. |
| 5.7 | Privacy policy and legal notice published and linked | Became a rule | legal.documents-published |
| 5.8 | Consent log stores: user identifier | Became a rule | legal.consent-recordThe who of who, when, wording, version. |
| 5.9 | Consent log stores: status, accepted or refused | Became a rule | legal.consent-recordAccepted or refused is the status the record must carry. |
| 5.10 | Consent log stores: date and time | Became a rule | legal.consent-recordThe when. |
| 5.11 | Consent log stores: exact consent text shown | Became a rule | legal.consent-recordThe exact wording shown, which is the field that makes the record provable. |
| 5.12 | Consent log stores: consent version | Became a rule | legal.consent-recordIts version. |
| 5.13 | Consent log stores: source, page URL or form name | Became a rule | legal.consent-record-contextSource URL, set by the caller. |
| 5.14 | Consent log stores: IP address | Declined in public | declined: Consent log stores the IP addressDeclined on the ground that it adds directly identifying personal data to a record kept for years without helping prove anything Art. 7(1) asks for. |
| 5.15 | Consent log stores: method of consent | Became a rule | legal.consent-record-contextMethod, set by the caller. |
| 5.16 | Consent log stores: purpose of consent | Became a rule | legal.consent-record-contextPurpose, set by the caller. |
| 5.17 | Consent log exportable, retention period defined | Became a rule | legal.consent-retentionThe rule adds that the retention job actually runs. |
| 5.18 | No analytics or marketing scripts before consent | Became a rule | legal.no-tags-before-consent0 third-party requests before a choice, exactly 1 container. Both reference builds fail it. |
| 5.19 | No personal data in URL parameters | Became a rule | legal.no-pii-in-urlsThe rule enumerates what counts: emails, names, phones, tokens. |
6. Images & video 13
| Item | What they asked for | Outcome | What we did with it |
|---|---|---|---|
| 6.1 | All files properly named | Declined in public | declined: All media files properly namedDeclined as unmeasurable at the file level; the descriptive-filename half of the same idea is declined again from the audit side. |
| 6.2 | Images max 200 KB, video max 2 MB | Became a rule | perf.image-formats, perf.video-weightCarried since 2026-09-10 by perf.image-formats (200 KB per image on the wire) and perf.video-weight (2 MB per video file). |
| 6.3 | No oversized images in small blocks | Became a rule | perf.image-formatsThe rule's accept is the measurable version: no image transfers more than twice the bytes needed at its displayed size. |
| 6.4 | Default social image 1200×630, custom one for the homepage | Became a rule | seo.open-graphThe rule requires the absolute og:image at 1200x630; the custom-homepage half is her 9.1. |
| 6.5 | Favicon set | Became a rule | onpage.faviconThe rule adds what Google needs: square, a multiple of 48px, 200, not Disallowed. |
| 6.6 | WebP/AVIF with `srcset` and `sizes` | Became a rule | perf.image-formatsVerbatim the same three. |
| 6.7 | `width`/`height` or aspect-ratio declared, prevents CLS | Became a rule | perf.clsThe mechanism is in the rule's do text; the rule grades the outcome, CLS 0.1, rather than the attribute. |
| 6.8 | Lazy loading below the fold, hero eager and preloaded | Became a rule | perf.lazy-and-priorityBoth halves, including fetchpriority on the LCP image. |
| 6.9 | `alt` on informative images | Became a rule | a11y.alt-text |
| 6.10 | `alt=""` + `aria-hidden="true"` on decorative icons | Became a rule | a11y.alt-text, a11y.icon-semantics |
| 6.11 | `aria-label` on clickable icons | Became a rule | a11y.icon-semanticsActing icons named. |
| 6.12 | Video: poster, muted and inline if autoplay, subtitles if speech | Became a rule | perf.video-weight, a11y.media-alternativesPoster, muted, playsinline on one rule; captions on the other. |
| 6.13 | SVGs optimised, icons in a sprite or inline | Declined in public | declined: SVGs delivered as a sprite or inlined, one request per icon avoidedDeclined because HTTP/2 removed the request-count argument the item rests on. |
7. Critical — breaks indexation 13
| Item | What they asked for | Outcome | What we did with it |
|---|---|---|---|
| 7.1 | One piece of content = one indexable URL | Became a rule | crawl.signals-agree, seo.canonicalHer meta-principle 1 says the same thing. |
| 7.2 | Canonical self-referencing, always to a 200, never to a redirect | Became a rule | seo.canonicalOne, absolute, on the live host. |
| 7.3 | Canonicals updated after every slug change | Became a rule | crawl.slug-change-redirect, seo.canonical |
| 7.4 | Sitemap contains only 200 + indexable + self-canonical pages | Became a rule | seo.sitemapGenerated, all 200, none noindex. |
| 7.5 | One sitemap source: the SEO plugin, not WP core | Became a rule | seo.sitemapCarried since 2026-09-10 by seo.sitemap: one sitemap source answers, the other returns 404, and robots.txt names the one. |
| 7.6 | `noindex` on utility pages: thank-you, login, account, search, cart, checkout | Became a rule | crawl.indexability-decidedHer list of utility pages is the rule's list of URL-minting templates. |
| 7.7 | `noindex` never combined with `Disallow` | Became a rule | crawl.signals-agreeThe rule's spec is 0 URLs both noindex and Disallowed. |
| 7.8 | Order respected: `noindex` → wait for de-indexation → then `Disallow` | Became a rule | crawl.signals-agreeThe ordering is written into the rule's do text: noindex, wait for it to drop out of Coverage, then Disallow. |
| 7.9 | Virtual and non-HTML pages use the `X-Robots-Tag` header | Became a rule | crawl.indexability-decidedCarried since 2026-09-10 by crawl.indexability-decided: non-HTML routes sit in the decision table and carry the decision as X-Robots-Tag. |
| 7.10 | Every indexable page has at least one real `<a href>` link to it | Became a rule | crawl.internal-reachabilityThe rule adds the JavaScript-off crawl and 0 orphans. |
| 7.11 | Large page sets (products, dealers, locations) have a crawlable listing | Became a rule | crawl.internal-reachability, colibrity.pagination-crawlableThis is the item that actually sources colibrity.pagination-crawlable, which currently cites Michael's brief and is not in it. The rule's do text records the 102 hidden dealer pages this came from. |
| 7.12 | dev / staging / admin blocked by Basic Auth or IP restriction | Became a rule | crawl.sibling-hosts, seo.no-noindex-leakThe rule allows noindex as well as a gate, which is looser than her wording and deliberate: a gate breaks PageSpeed measurement on staging. |
| 7.13 | Sitemap, canonical, robots and meta all agree on every page | Became a rule | crawl.signals-agreeThe rule samples ten URLs where she says every page, so the rule is narrower than its source. |
8. Important — pollutes or weakens the index 25
| Item | What they asked for | Outcome | What we did with it |
|---|---|---|---|
| 8.1 | Site representation: `Organization` type, exact name, square logo | Became a rule | seo.structured-dataExactly one Organization node with a name matching the brand. The square-logo half is not graded by any rule. |
| 8.2 | All official brand accounts listed, feeds `sameAs` | Became a rule | onpage.site-identityCarried since 2026-09-10 by onpage.site-identity: every official account in the Organization node sameAs. |
| 8.3 | Default `og:image` set, 1200×630 | Became a rule | seo.open-graph |
| 8.4 | Site title, tagline and title separator consistent | Became a rule | onpage.site-identityCarried since 2026-09-10 by onpage.site-identity: title, tagline and separator set once, on purpose. |
| 8.5 | index/noindex set deliberately per content type | Became a rule | crawl.indexability-decidedOne recorded decision per template. |
| 8.6 | Schema `@type` correct: `Article` for articles, `WebPage` elsewhere | Became a rule | onpage.schema-fidelityType fits the page. |
| 8.7 | Title and description templates set per content type | Became a rule | seo.title-descriptionGive every template a title pattern is the rule's own do text. |
| 8.8 | Tags `noindex` unless they are real landing pages | Became a rule | crawl.indexability-decidedPaginated tags are named in the rule's list of URL-minting templates. |
| 8.9 | Author archives disabled if authorship is unused | Became a rule | crawl.indexability-decided, security.wp-attack-surfaceAuthor archives are named in the first; author enumeration is closed by the second. |
| 8.10 | Categories indexed only if they are real landing pages | Became a rule | crawl.indexability-decidedTaxonomy archives are named in the rule's list. |
| 8.11 | `<title>`, H1 and schema `headline` are full titles, not stubs | Became a rule | onpage.core-fields, onpage.schema-fidelityThe second rule requires headline equals the visible title. |
| 8.12 | Standard WP fields filled, not only ACF or the page builder | Became a rule | onpage.core-fieldsThe rule names the five consumers that read the core fields and show up in no rendered page. |
| 8.13 | Descriptive URLs: `/category/eau-dure/`, not `/?cat=38` | Became a rule | crawl.url-formatNo ids, no dates, under 115 chars, the page's language. |
| 8.14 | Filters lead to clean URLs, not query parameters | Declined in public | declined: Filters lead to clean URLs, not query parametersDeclined because colibrity.filter-url-state requires the opposite - filter state in query parameters, written with replaceState - and the two cannot both hold. |
| 8.15 | Redirects: one hop maximum, no chains | Became a rule | seo.internal-links-resolve, crawl.slug-change-redirect, migration.redirect-mapOne hop is asserted in all three. |
| 8.16 | Internal links point to final URLs | Became a rule | seo.internal-links-resolveNo chain over one hop. |
| 8.17 | No 4XX/5XX in the menu, sitemap or internal links | Became a rule | seo.internal-links-resolve, crawl.published-urls-resolveThe second rule exists because a published, sitemapped nav item was found 404ing on a live reference build. |
| 8.18 | Paginated pages self-canonical | Became a rule | colibrity.paged-canonicalPage two canonicals to page two. |
| 8.19 | Structured data matches what's visible on the page | Became a rule | onpage.schema-fidelityEvery emitted value matches the rendered page. |
| 8.20 | Review stars only if reviews are genuinely visible | Became a rule | onpage.schema-fidelityThe rule names this case: never emit an aggregateRating for reviews that only exist client-side. |
| 8.21 | Breadcrumbs on every page except the homepage, with `BreadcrumbList` | Became a rule | crawl.breadcrumb-trailOne trail, last item unlinked, BreadcrumbList mirroring it. |
| 8.22 | Unique title and meta description per page | Became a rule | seo.title-descriptionNo two sampled pages share either. |
| 8.23 | `hreflang` if multilingual | Became a rule | seo.hreflangThe rule adds reciprocity, self-reference and x-default. |
| 8.24 | 301 redirects mapped from all old URLs, redesign only | Became a rule | migration.redirect-map, seo.redirects-on-launch, crawl.slug-change-redirectThree rules, and all three drop her redesign-only scope and apply to every renamed URL, which is a deliberate generalisation past the source. crawl.slug-change-redirect was missing here until the forward and backward halves of the audit were cross-checked against each other: the rule cited this item and this item did not name it back. Neither half was wrong on its own, which is why only comparing them found it. |
| 8.25 | Search Console connected, sitemap submitted, indexation verified | Became a rule | crawl.search-consoleThe rule adds the part that keeps failing: the build team's own account can open Coverage. |
9. Polish 5
| Item | What they asked for | Outcome | What we did with it |
|---|---|---|---|
| 9.1 | Custom social image on the homepage | Became a rule | seo.open-graph |
| 9.2 | `og:title`, `og:description`, `og:url`, `og:image` per page | Became a rule | seo.open-graphHer four are inside the rule's eight. |
| 9.3 | One shared breadcrumb component across all templates | Became a rule | crawl.breadcrumb-trailOne trail per page is the rule's measurable; one shared component is how it is met. |
| 9.4 | First breadcrumb link in the site language, "Accueil" not "Home" | Became a rule | crawl.breadcrumb-trailCarried since 2026-09-10 by crawl.breadcrumb-trail: the root item is in the page language. |
| 9.5 | Share preview tested on Facebook, LinkedIn, iMessage | Became a rule | onpage.site-identityCarried since 2026-09-10 by onpage.site-identity: a dated preview of the home and one article in the three platforms. |
10. Performance — Core Web Vitals 13
| Item | What they asked for | Outcome | What we did with it |
|---|---|---|---|
| 10.1 | LCP under 2.5s | Became a rule | perf.lcpSame threshold, and the rule adds median of 3 on mobile. |
| 10.2 | CLS under 0.1 | Became a rule | perf.cls |
| 10.3 | INP under 200ms | Became a rule | perf.inp-tbtThe rule adds TBT, which is what a lab run can actually measure. |
| 10.4 | Heavy JS/CSS loaded on-demand, per page type | Became a rule | perf.bundle-budgets, perf.split-points-asserted, perf.enqueue-hygieneThe middle rule is the one Vocalcom fails: the assertion exists and nothing that ships runs it. |
| 10.5 | No file loaded twice, no empty stylesheets | Became a rule | perf.enqueue-hygieneVerbatim both halves, plus a 100-byte floor for near-empty files. |
| 10.6 | jQuery removed if unused | Became a rule | perf.enqueue-hygieneNo library loaded by a template that does not use it. |
| 10.7 | Dynamic JS classes safelisted against "Remove Unused CSS" | Became a rule | perf.optimiser-output-freshHer meta-principle 6 makes the same point and names .is-open and .is-visible. |
| 10.8 | Critical CSS regenerated after any optimisation change | Became a rule | perf.optimiser-output-fresh |
| 10.9 | Fonts subset, preloaded, `font-display: swap` | Became a rule | perf.fontsThe rule adds woff2 only, self-hosted, none over 100 KB, one preload. |
| 10.10 | Max 2 font families, 3–4 weights | Declined in public | declined: Max 2 font families, 3-4 weightsDeclined because the number cannot be defended; perf.fonts grades the bytes instead, which is the thing that actually costs. |
| 10.11 | Third-party scripts audited | Became a rule | perf.third-partyThe rule turns audited into a number: under 250 ms combined main-thread time. |
| 10.12 | Tested on throttled 3G and mid-range Android | Half and half | practices.real-device-check · declined: Tested on throttled 3GThe mid-range Android half is a rule and names the device class. The throttled-3G half is declined: the profile no longer matches any network real visitors use. |
| 10.13 | Caching, Brotli/gzip and CDN configured | Became a rule | perf.caching-and-compressionCaching and compression are graded, including reading what the host actually sends. A CDN is not required by any rule, deliberately - none of these sites has one. |
11. Responsive 8
| Item | What they asked for | Outcome | What we did with it |
|---|---|---|---|
| 11.1 | No horizontal scroll at any width | Became a rule | practices.responsive-breakpoints320 to 2560, no horizontal scroll, no overlap. |
| 11.2 | Tested at 320px | Became a rule | practices.responsive-breakpoints, a11y.zoom-and-reflow320 px is the floor in both. |
| 11.3 | Tested on tablet, laptop, large desktop | Became a rule | practices.responsive-breakpointsThe rule replaces named devices with a continuous range, which catches the widths between them. |
| 11.4 | Tested in landscape | Became a rule | practices.mobile-viewport-chromeLandscape usable is in the rule's spec. |
| 11.5 | Safe areas respected on notched iPhones | Became a rule | practices.mobile-viewport-chromeNothing clipped by the toolbar or notch. |
| 11.6 | Sticky header and mobile menu behaviour defined on scroll | Became a rule | states.sticky-chromeThe rule adds the three failures: shift on stick, anchors landing under the header, scroll not locked. |
| 11.7 | Tables and long content handled on small screens | Became a rule | practices.responsive-breakpointsCovered by no overlap and no horizontal scroll across the range; the rule does not name tables specifically. |
| 11.8 | Tested on real iOS Safari | Became a rule | practices.real-device-checkA real iPhone, not a simulator. |
12. Accessibility 9
| Item | What they asked for | Outcome | What we did with it |
|---|---|---|---|
| 12.1 | Touch targets 44×44px minimum | Became a rule | a11y.target-sizeThe rule grades 24x24, not her 44x44, and its do text argues why: 44 is SC 2.5.5 at AAA and a house bar for the kit, 24 is SC 2.5.8 at AA. This is a partial decline recorded inside a rule rather than on the declines page. |
| 12.2 | Full keyboard navigation, logical tab order, no traps | Became a rule | a11y.keyboard-operableOne reference build's mobile menu cannot be opened from a keyboard at all. |
| 12.3 | Modals and mobile menu: focus trapped, Escape closes, focus returns | Became a rule | a11y.dialog-behaviourAll three: trap, Escape, return. |
| 12.4 | One `h1` per page, hierarchical headings | Became a rule | html.single-h1, seo.headings-describe-content |
| 12.5 | Landmarks used: `nav`, `main`, `footer` | Became a rule | html.landmarksThe rule adds exactly one main and every nav named. |
| 12.6 | Skip-to-content link | Became a rule | a11y.skip-linkThe rule adds that it is the first focusable element and that its target exists. |
| 12.7 | `lang` attribute correct per page | Became a rule | html.doctype-and-langPer page, matching the visible copy. |
| 12.8 | Tested at 200% zoom | Became a rule | a11y.zoom-and-reflow |
| 12.9 | Tested with a screen reader on at least one page | Became a rule | a11y.screen-reader-passThe rule raises it to two surfaces - one content page plus one form - and names the software. |
13. Emails & CRM 5
| Item | What they asked for | Outcome | What we did with it |
|---|---|---|---|
| 13.1 | SPF, DKIM and DMARC configured | Became a rule | comms.email-authenticationThe rule adds one dated test send with all three passing. |
| 13.2 | Emails tested on Gmail, Outlook, iPhone Mail | Became a rule | comms.email-renderingThe rule adds a text part and the 102 KB Gmail clipping cap. |
| 13.3 | Correct language, sender name and reply-to | Became a rule | comms.sender-identityThe rule adds From on the site's domain and Reply-To a real inbox. |
| 13.4 | CRM mapping verified field by field, consent fields included | Became a rule | comms.crm-field-mapThe rule adds a dated signed map and one test record read back. |
| 13.5 | Alert if the form or CRM connection breaks | Became a rule | comms.delivery-alertingThe rule adds a named human and a one-day window. |
14. Analytics 3
| Item | What they asked for | Outcome | What we did with it |
|---|---|---|---|
| 14.1 | Analytics installed and consent-gated | Became a rule | legal.no-tags-before-consent, comms.conversion-eventsConsent-gating is the first rule; installation is implied by the second. |
| 14.2 | Conversion events tracked: form submit, newsletter, key clicks | Became a rule | comms.conversion-eventsHer three examples are the rule's agreed list. |
| 14.3 | Confirmation state usable as a conversion trigger | Became a rule | comms.conversion-events, forms.confirmationThe rule requires the form-submit event fire exactly once per action, which is only checkable because the confirmation is a distinct state. |
15. Pre-launch QA 7
| Item | What they asked for | Outcome | What we did with it |
|---|---|---|---|
| 15.1 | Real content proofread, no lorem ipsum, no typos | Became a rule | delivery.real-contentThe rule splits the item deliberately: the sweep is the build's, proofreading the French copy is Colibrity's sign-off and is said so rather than quietly implied. |
| 15.2 | Right language everywhere | Became a rule | html.doctype-and-lang, states.error-pages, comms.sender-identity, admin.editor-languageFour rules carry the four places language actually goes wrong: the page, the 404, the mail, the admin. |
| 15.3 | All links tested, external link behaviour defined | Half and half | seo.internal-links-resolve, crawl.published-urls-resolve · declined: External link behaviour defined - rel=noopener and a new-window warningAll-links-tested is two rules. The external-link half is declined: modern browsers imply noopener, and a new-window warning is a pattern we do not use. |
| 15.4 | Tested on Chrome, Safari desktop and iOS, Firefox, Edge | Half and half | delivery.browser-matrix · declined: The Edge row of the five-browser test matrixThe rule tests three engines rather than five browsers. Edge is declined because it is Blink, so its row duplicates Chrome's. |
| 15.5 | HTTPS everywhere, security headers set | Became a rule | seo.https-and-mixed-content, security.response-headersThe rule names the five headers and the HSTS max-age. |
| 15.6 | Uptime monitoring and backup schedule active | Became a rule | delivery.monitoring-and-backups, ops.backup-coverage, ops.recovery-drillThe third rule is the one she does not ask for and is the one that matters: a backup nobody has restored is not a backup. |
| 15.7 | Client handover: CMS training, documentation, credentials | Half and half | delivery.client-handover, practices.handover-notes, security.admin-accounts-at-handover · declined: Every account the site depends on is listed with an ownerTraining and documentation are rules, and so is the WordPress administrator list. The wider credential half - registrar, DNS, mail, licences, by holder - was a rule until 2026-08-26, when the citation audit found nothing behind it and it was withdrawn. This row became a split rather than staying green, because her item asked for credentials and we now cover only some of them. |
PP. Per-page checklist 15
| Item | What they asked for | Outcome | What we did with it |
|---|---|---|---|
| PP.1 | One URL, descriptive slug, no parameters | Became a rule | crawl.url-format |
| PP.2 | Self-canonical to a 200 | Became a rule | seo.canonical |
| PP.3 | index or noindex decided | Became a rule | crawl.indexability-decided |
| PP.4 | In the sitemap only if indexable | Became a rule | seo.sitemap |
| PP.5 | At least one real HTML link pointing to it | Became a rule | crawl.internal-reachabilityThe rule adds that a sitemap entry is a discovery hint and not a path. |
| PP.6 | Full `<title>` and H1 | Became a rule | onpage.core-fields, html.single-h1 |
| PP.7 | Breadcrumbs present, except homepage | Became a rule | crawl.breadcrumb-trail |
| PP.8 | Schema correct and matching what's visible | Became a rule | onpage.schema-fidelity |
| PP.9 | `og:title`, `og:description`, `og:image` set | Became a rule | seo.open-graph |
| PP.10 | `alt` set on every image | Became a rule | a11y.alt-text |
| PP.11 | Internal links point to final URLs | Became a rule | seo.internal-links-resolve |
| PP.12 | Signals don't conflict | Became a rule | crawl.signals-agree |
| PP.13 | All states present: focus, hover, active, disabled, loading, error, empty | Became a rule | states.interactive-set, a11y.focus-visible, states.loading-feedback, a11y.form-errors, practices.empty-statesHer seven states are five rules; focus is deliberately its own because it carries a contrast threshold the others do not. |
| PP.14 | Checked at 320px and on real iOS Safari | Became a rule | practices.responsive-breakpoints, practices.real-device-check |
| PP.15 | Images under 200 KB, correctly sized, dimensions declared | Became a rule | perf.image-formats, perf.clsCorrectly sized and dimensions declared are graded. The 200 KB cap is not, and is counted once as a gap against 6.2 rather than twice. |
Meta-principles 6
| Item | What they asked for | Outcome | What we did with it |
|---|---|---|---|
| MP.1 | One piece of content, one indexable URL. | Became a rule | crawl.signals-agree, seo.canonical |
| MP.2 | Signals never conflict: sitemap, canonical, robots, meta. | Became a rule | crawl.signals-agreeThe rule is this principle made measurable: 0 conflicts in 10 sampled URLs. |
| MP.3 | What you do for Google, do for humans: real links, visible content in schema, descriptive URLs, full titles. | Declined in public | declined: What you do for Google, do for humansDeclined as a principle rather than a rule: it is the reasoning behind four rules we did ship, and grading it separately would grade them twice. |
| MP.4 | After renaming slugs, re-check: redirects, canonicals, sitemap, internal links, breadcrumbs, schema. | Became a rule | crawl.slug-change-redirect, seo.canonical, seo.sitemap, seo.internal-links-resolve, crawl.breadcrumb-trailHer six re-checks are five rules; schema fidelity after a rename is the sixth and is onpage.schema-fidelity. |
| MP.5 | Separate code from settings: templates and filters on one side, SEO plugin dashboard and content on the other. | Declined in public | declined: Separate code from settingsDeclined because half is already asserted twice and the other half contradicts crawl.indexability-decided, which puts the index decision in the template rather than a plugin checkbox. |
| MP.6 | Animation classes (`.is-open`, `.is-visible`) are exactly what "Remove Unused CSS" strips. Safelist them at the start. | Became a rule | perf.optimiser-output-freshThe rule names the same failure and requires every JS-toggled class be present in the production CSS. |
The technical SEO control grid
- 124 became a rule
- 22 declined in public
- 1 half and half
- 12 no rule carries it
1. Crawl et Navigation 61
| Item | What they asked for | Outcome | What we did with it |
|---|---|---|---|
| 6 | Le nombre de pages HTML indexées est cohérent par rapport au nombre de pages dans la structure du site | Became a rule | crawl.sibling-hostsThe detail is the sibling-host case exactly: admin, etl and admin.dev subdomains answering 200 and crawlable. This is the row that sourced the rule. |
| 7 | Il n'y a pas de page(s) orpheline(s) sur le site (absence de pages de destination SEO visitées hors arborescence) | Became a rule | crawl.internal-reachability41 orphans, of which 102 dealer pages reachable only through a JavaScript map. The rule's do text carries this incident. |
| 8 | Les pages stratégiques (ex : catégories principales) sont accessibles depuis la page d'accueil | Became a rule | crawl.internal-reachability |
| 9 | Les autres pages sont accessibles depuis la page d'accueil via un nombre limité de clics (càd < 4) | Became a rule | crawl.internal-reachabilityThe audit says under 4 clicks, the rule says 3 or fewer, so the rule is stricter. |
| 10 | Il y a une balise de lien canonique (canonical) sur chaque page et pointant vers la page elle-même par défaut | Became a rule | seo.canonicalExactly one, absolute, self-referencing. |
| 11 | Il n'y a qu'une seule balise meta robots par page | Became a rule | crawl.signals-agreeTwo meta robots tags on one URL is a conflict, which is what the rule samples for. |
| 12 | Les balises meta robots n'empêchent pas l'indexation du contenu utile | Became a rule | crawl.indexability-decided, seo.no-noindex-leak |
| 13 | Les éléments de navigation entre les différentes pages utilisent une structure de lien HTML classique (<a href>). | Became a rule | html.buttons-vs-links, crawl.internal-reachabilityThe standard requires the same markup for a semantic reason rather than a crawl one, and both rules land on it. |
| 14 | Les éléments de navigation entre les différentes pages sont au format textuel. | Declined in public | declined: Navigation elements between pages are in text formDeclined after counter-verification: the label is complete in one element in the source and split into spans by JavaScript afterwards, so Google reads the whole label. |
| 15 | L'accès aux contenus importants (page d'accueil, catégories, produits, blog, etc.) n'est pas conditionné par : - le recours à certaines technologies comme le Flash - le support de JavaScript et/ou Ajax - l'utilisation de frames ou iframes - l'utilisation des cookies - l'ouverture de pop-up - l'usage de formulaires | Became a rule | crawl.content-in-server-htmlThe rule's accept is the measurable version: curl returns the h1, the first paragraph and every nav link. |
| 16 | Il y a un fichier robots.txt placé à la racine du site. | Became a rule | seo.robots-txt |
| 17 | Le fichier robots.txt autorise l'accès aux contenus importants, y compris les ressources CSS, JS et images nécessaires pour restituer le site comme un navigateur classique. | Became a rule | seo.robots-txtCarried since 2026-09-10 by seo.robots-txt: nothing a page needs to render is Disallowed. |
| 18 | Le fichier robots.txt bloque l'accès aux contenus à ne pas rendre accessibles (répertoires sensibles, scripts d'administration, répertoires de test, images protégées, etc.). | Became a rule | seo.robots-txtThe rule's do names sandbox, styleguide and internal preview routes. |
| 19 | Le fichier robots.txt bloque l’accès aux pages de résultats de recherche interne. | Became a rule | crawl.indexability-decidedThe standard reaches the same outcome by a different mechanism and says why: search results carry noindex, and crawl.signals-agree forbids adding Disallow on top of it, which is what this row asks for. |
| 20 | Il y a un ou plusieurs fichier(s) sitemap utilisé(s) au format XML ou TXT pour répertorier les ressources importantes du site. | Became a rule | seo.sitemap |
| 21 | Les URLs listées dans le(s) fichier(s) sitemap sont les URLs canoniques (URL principales préférées pour chaque page). | Became a rule | seo.sitemap, seo.canonical, crawl.signals-agree87 URLs in the sitemap were not self-canonical, all of them fallout from one rename. |
| 22 | Les URLs listées dans le(s) fichier(s) sitemap renvoient un code serveur "200 OK". | Became a rule | seo.sitemapEvery child 200, a sample of ten with no redirect. |
| 23 | Les URL listées dans le(s) fichier(s) sitemap ne contiennent pas de paramètres de session . | Became a rule | crawl.url-format, seo.sitemapSession identifiers are excluded by crawl.url-format, which governs the content URL. |
| 24 | Les URL listées dans le(s) fichier(s) sitemap sont autorisées au crawl dans le fichier robots.txt et sont indexables . | Became a rule | seo.sitemap, crawl.signals-agreeNo listed URL carries noindex, and no URL is both noindex and Disallowed. |
| 25 | Les URL listées dans le(s) fichier(s) sitemap contiennent les caractères d'échappement nécessaires pour les caractères spéciaux d'URL. | No rule carries it | XML escaping in the sitemap is asserted by nothing. seo.sitemap requires the file be generated rather than hand-maintained, which makes correct escaping true by construction, so this is unaccounted and deliberately not worth a rule. |
| 26 | Le fichier sitemap ne contient pas plus de 50 000 URL et ne dépasse pas 50 Mo. Le sitemap peut être scindé en plusieurs fichiers si besoin. | No rule carries it | The 50,000-URL and 50 MB protocol limits appear in no rule. Same reasoning as row 25: a generated sitemap splits itself, so this is unaccounted and not worth a rule. |
| 27 | L'emplacement du ou des fichier(s) sitemap est spécifié dans le fichier robots.txt. | Became a rule | seo.robots-txtAn absolute Sitemap: line that itself returns 200. |
| 28 | Le fil d'Ariane est présent sur toutes les pages du site à l'exception de la page d'accueil. | Became a rule | crawl.breadcrumb-trail |
| 29 | Le fil d'Ariane est maintenu sur mobile grâce à l'utilisation de techniques de conception responsive. | Became a rule | crawl.breadcrumb-trail, practices.responsive-breakpoints |
| 30 | Le fil d'Ariane est affiché au même emplacement sur l’ensemble des pages, en haut de page. | No rule carries it | crawl.breadcrumb-trail requires one trail per page and says nothing about where it sits. One shared component makes placement consistent by construction, which is the checklist's own 9.3, so this is unaccounted and not worth a rule of its own. |
| 31 | Le fil d’Ariane est basé sur l'emplacement dans l'arborescence et non sur l'historique de navigation du visiteur. | Became a rule | crawl.breadcrumb-trailVerbatim in the rule's do: where the page sits rather than how the visitor got there. |
| 32 | Le fil d'Ariane ne fait pas de lien vers la page en cours (dernier élément du fil d'Ariane). | Became a rule | crawl.breadcrumb-trailThe last item is the current page and is not a link. |
| 33 | Il n'y a qu'un seul fil d’Ariane par page même si celle-ci appartient à plusieurs catégories. | Became a rule | crawl.breadcrumb-trailTwo trails on a page is worse than none. |
| 34 | Le serveur renvoie un code HTTP "404 Not Found" pour les ressources non trouvées. | Became a rule | states.error-pagesThe rule adds the soft-404 failure and the per-language check. |
| 35 | La page d'erreur n'est pas un cul-de-sac pour la navigation. Elle permet de continuer à naviguer sur le site. Elle inclut le menu principal, un lien vers la page d'accueil, la page de contact et peut inclure une zone de recherche. Elle est exempte de modules publicitaires. | Became a rule | states.error-page-designSite chrome and at least one working route back. |
| 36 | Aucune ressource sur le site ne renvoie de code d'erreur (4XX ou 5XX). | Became a rule | crawl.published-urls-resolve, seo.internal-links-resolveThe one internal 404 was /author/fr/, reachable only from the author sitemap - which is why crawl.indexability-decided names author archives. |
| 37 | Le nombre de liens par page est raisonnable (maximum conseillé de 150 - 200 liens par page). | Declined in public | declined: No more than 150 to 200 links per pageDeclined because the number cannot be defended and was never Google's. |
| 38 | Les pages les plus importantes du site sont celles qui reçoivent le plus de liens internes. | Declined in public | declined: The most important pages receive the most internal linksDeclined as unmeasurable at handover. |
| 39 | Aucune ressource redirigée (3XX) n'est présente dans le maillage interne du site. | Became a rule | seo.internal-links-resolveCounter-verification found 84 of the 95 were canonical tags rather than navigation links, which is a different fault with a different fix. |
| 40 | Des boutons ou des éléments de formulaire sont utilisés pour l'ajout au panier, l'ajout à la liste de souhaits ou l'accès aux réseaux sociaux plutôt que des liens HTML. Cela permet d'éviter la dispersion de la popularité vers des contenus non-stratégiques. | Became a rule | html.buttons-vs-linksSame markup, different reason: the standard requires it because a link goes somewhere and a button does something, and rejects the popularity-dilution argument this row rests on. |
| 41 | Les systèmes de filtres (facettes), de tri, d'affichage en grille/liste et de nombre de résultats par page ne créent pas de pièges pour les robots d'exploration. Ils ne génèrent pas de nombreuses URL dupliquées, vides ou peu pertinentes. | Became a rule | colibrity.filter-indexabilityNo filter combination generates an unbounded set of indexable URLs. |
| 42 | Par défaut, les systèmes de filtres (facettes), de tri, d'affichage en grille/liste et de nombre de résultats par page ne créent pas de pages indexables. | Became a rule | colibrity.filter-indexability |
| 43 | Lorsqu'une page de filtre, de tri, d'affichage en grille/liste ou de nombre de résultats par page est générée, elle inclut une directive noindex et déclare la version non filtrée ou non triée comme version canonique (cf. sections 3.1 et 2.2). | Became a rule | colibrity.filter-indexabilityCanonicalise to the unfiltered listing, or carry noindex. |
| 44 | Les pages de filtres (facettes) générées par un système de bornes de valeurs (ex : un filtre de prix) sont bloquées dans le fichier robots.txt. | No rule carries it | Blocking range-filter URLs in robots.txt is the one route crawl.signals-agree explicitly forbids combining with noindex, and colibrity.filter-indexability reaches the same outcome by canonicalisation instead. Unaccounted by design, and the standard should not adopt it. |
| 45 | Le système de filtrage interne est fonctionnel | No rule carries it | That the filter returns the right results is asserted by no rule. colibrity.filter-url-state grades the URL contract and colibrity.filter-indexability grades what gets indexed; neither opens the listing and checks the count. A rule would have to assert one filtered result set matches a known expected set. |
| 46 | Par défaut, les systèmes de filtres (facettes), de tri, d'affichage en grille/liste et de nombre de résultats par page n'utilisent pas de liens hypertextes visibles dans le code source pour éviter de diluer la popularité interne. | Declined in public | declined: Filter systems do not use hyperlinks visible in the sourceDeclined: it is PageRank sculpting, and colibrity.filter-url-state requires the opposite - state in the URL. |
| 47 | Les systèmes de filtres (facettes), de tri, d'affichage en grille/liste et de nombre de résultats par page utilisent JavaScript/Ajax ou la méthode PRG (Post-Redirect-Get) afin de ne pas créer ou laisser apparaître de pages indexables. | Declined in public | declined: Filters use JavaScript/Ajax or the Post-Redirect-Get patternDeclined for the same reason as row 46. |
| 48 | Le système permet l'exploration et l'indexation de certains filtres (facettes) en générant des URL réécrites. | Became a rule | colibrity.filter-indexabilityFilters matching real search demand stay indexable and appear in the sitemap. |
| 49 | Chaque page d'une série paginée dispose d'une URL distincte (ex : avec paramètre de pagination) et inclut le numéro de page. | Became a rule | colibrity.pagination-in-urlThe rule sets the shape - /page/2/ - and adds that it must work with JavaScript off. |
| 50 | Des balises <link rel="prev" ... > et <link rel="next" ...> sont utilisées dans la section <head> des contenus paginés pour indiquer la relation séquentielle entre les URL. | Declined in public | declined: link rel=prev and rel=next on paginated seriesDeclined: Google stopped using rel=prev/next in 2019 and said so. Three rows of this grid rest on it. |
| 51 | La première page de la série paginée contient uniquement une balise <link rel="next" ...>. | Declined in public | declined: link rel=prev and rel=next on paginated seriesSame decline, first-page variant. |
| 52 | La dernière page de la série paginée contient uniquement une balise <link rel="prev" ...>. | Declined in public | declined: link rel=prev and rel=next on paginated seriesSame decline, last-page variant. |
| 53 | Il est possible de naviguer entre les pages de la série paginée à l'aide d'une structure de lien HTML classique. | Became a rule | colibrity.pagination-crawlableA real a element with an href that resolves to a 200. |
| 54 | L'accès aux pages de la séquence paginée ne nécessite pas le support du JavaScript (ex : infinite scroll) et n'est pas conditionné au clic sur des éléments de formulaire (ex : bouton "Plus").. | Became a rule | colibrity.pagination-crawlable, colibrity.pagination-in-urlThe rule names this failure: a listing whose only navigation is an offset load-more button does not satisfy it. |
| 55 | Les liens hypertextes du système de pagination ne contiennent pas d'attribut nofollow. | No rule carries it | No rule says anything about nofollow on pagination controls. Nothing in the standard emits nofollow anywhere, so this is unaccounted and true by construction rather than worth a rule. |
| 56 | La version canonique est correctement définie : la première page d'une séquence paginée n'est pas définie comme la page canonique. Chaque page de la séquence paginée est définie comme sa propre URL canonique ou pointe vers la page view-all (vue complète). | Became a rule | colibrity.paged-canonicalPage two canonicals to page two. |
| 57 | Les liens pointant vers la première page de la série sont corrects afin d'éviter les problèmes de contenu dupliqué (ex : pas de ?p=1 dans le lien). | Became a rule | colibrity.pagination-in-urlPage one is the bare listing URL, so no ?p=1 duplicate exists to link to. |
| 58 | Les séries paginées ne contiennent pas un nombre trop important de pages (ex : > 20). Dans le cas contraire, les éléments appelés (ex : produits, articles de blog) sont accessibles ailleurs sur le site, à des niveaux de profondeur acceptables. | Became a rule | crawl.internal-reachabilityThe rule's 3-clicks-maximum is the measurable version of this row's acceptable depth. |
| 59 | Les URL sont descriptives : elles contiennent les mots-clés pertinents qui facilitent la compréhension du contenu de la page. | Became a rule | crawl.url-format?cat=38 for a blog filter. The rule refuses numeric ids in the content URL. |
| 60 | Les URL ont une structure simple : elles ne contiennent pas d'ID long et complexe, de paramètres excessifs, d'identifiants de session ou de suivi (tracking), ni de répertoires trop imbriqués (ex : >4). Elles n'excèdent pas les 115 caractères. | Became a rule | crawl.url-formatThe row this rule cites: no long ids, no excessive parameters, no session identifiers, under 115 characters. |
| 61 | Les URL ne contiennent ni espace ni caractères spéciaux (non ASCII). | Became a rule | crawl.url-formatLower case and hyphen-separated is in the rule's do; the accept does not name non-ASCII characters, which on a French site is the case that matters. |
| 62 | Les mots des URL sont séparés par des traits d'union (-) plutôt que des traits de soulignement (_) ou d'autres séparateurs non standard ( , ; + ). Les URL n'utilisent pas de successions de mots sans caractère de séparation. | Became a rule | crawl.url-formatHyphens rather than underscores, in the rule's accept. |
| 63 | La langue de l'URL reflète celle du contenu de la page. | Became a rule | crawl.url-formatIn the same language as the page it serves. The counter-verification found the title and H1 were English too, which onpage.core-fields covers. |
| 64 | La structure des URL n'est pas le reflet de l'arborescence car cela peut poser problème dans le cas où un des contenus parents est renommé ou lorsque la page est déplacée. | Declined in public | declined: URL structure does not mirror the site treeDeclined: it argues against a hierarchy that crawl.breadcrumb-trail and crawl.internal-reachability both rely on. |
| 65 | Les URL ne contiennent pas de dates. Ces dates peuvent compromettre la permanence du contenu. | Became a rule | crawl.url-formatNo date segment, in the rule's spec. |
| 66 | La suppression du dernier niveau d'un répertoire dans une URL renvoie vers une ressource existante. | No rule carries it | Directory hackability - trimming the last URL segment lands on something real - is in no rule. It is a convention Google no longer rewards, so unaccounted and not worth a rule. |
2. Gestion de la Duplication de Contenu 8
| Item | What they asked for | Outcome | What we did with it |
|---|---|---|---|
| 67 | Des redirections permanentes (code de réponse HTTP 301) sont mises en place de la version HTTP vers la version HTTPS | Became a rule | seo.https-and-mixed-contentOne 301 from http to https. |
| 68 | Les autres variations fréquentes d'URL ne génèrent pas de duplication de contenu : - redirection permanente ou canonicalisation des différentes versions de la page d'accueil (index, home, etc.) vers la racine - redirection permanente des URL sans slash final ("/") vers URL avec slash final (ou inversement), sauf si une extension est présente - redirection permanente des URL partageant un même ID mais des slugs (libellés textuels descriptifs) différents | Became a rule | seo.canonical, crawl.sibling-hostsThe canonical must equal the URL requested once redirects have resolved, which settles the index, trailing-slash and case variants. A www duplicate is a sibling host and is enumerated by the second rule. |
| 69 | Chaque page indexable du site possède une URL canonique, c'est-à-dire une version privilégiée d'URL. | Became a rule | seo.canonical |
| 70 | La version canonique de l'URL est déclarée par l'une des méthodes suivantes : - balise <link rel="canonical"...> placée dans section <head> du code HTML - en-tête HTTP rel="canonical" (ex : pour les fichiers PDF générant de la duplication de contenu) La déclaration de la version canonique dans les sitemaps est évitée. | Declined in public | declined: Canonical declared by HTTP header for PDFsDeclined: a PDF that needs a canonical header is a PDF that should not be indexable in the first place. |
| 71 | La version canonique de l'URL n'est déclarée qu'une seule fois (ex : il n'existe qu'une seule balise <link rel="canonical"...> par page indexable). | Became a rule | seo.canonicalExactly one canonical link per page. |
| 72 | La version canonique renseignée dans la balise canonical est indexable et renvoie un code d'état HTTP "200 OK". | Became a rule | seo.canonical, crawl.signals-agreeNo page canonicalises to a URL that answers noindex, a redirect or a 404. |
| 73 | La version privilégiée des pages qui ne doivent pas être indexées (ex : CGU, CGV, mentions légales) ne déclare pas d'URL canonique. | Declined in public | declined: Pages that must not be indexed declare no canonical URLDeclined: a self-canonical on a noindex page is harmless, and removing it breaks nothing this grid measures. |
| 74 | La version canonique renseignée est une URL absolue, c'est-à-dire une URL complète qui inclut le protocole (HTTP ou HTTPS), le domaine et le chemin complet de la page. | Became a rule | seo.canonicalAbsolute, on the live host. |
3. Qualité des Contenus 43
| Item | What they asked for | Outcome | What we did with it |
|---|---|---|---|
| 75 | Aucune directive n'empêche l'indexation des contenus importants (page d'accueil, catégories, produits, blog, etc.) | Became a rule | seo.no-noindex-leak, crawl.indexability-decided |
| 76 | Les contenus de faible qualité ou sans intérêt pour le référencement sont rendus non indexables par l'une des méthodes suivantes : - balise <meta name="robots" content="noindex"> placée dans la section <head> du code HTML - en-tête HTTP X-Robots-Tag: noindex (ex : pour les ressources non HTML) | Became a rule | crawl.indexability-decidedEither mechanism, and the rule requires the decision be recorded per template rather than found per page. |
| 77 | Les pages suivantes contiennent l’instruction noindex : - pages de connexion ou de mot de passe perdu - pages d'archives - pages d'accès à l'admin - pages de résultats de recherche interne | Became a rule | crawl.indexability-decidedLogin, archives, admin and internal search are all named in the rule's list of URL-minting templates. |
| 78 | Une directive nofollow, utilisée pour spécifier aux moteurs de recherche de ne pas suivre les liens présents sur une page, n'est ajoutée à l'instruction noindex que lorsque les pages du site contiennent elles-mêmes des liens vers des pages de faible qualité. | Declined in public | declined: nofollow added alongside noindexDeclined: nofollow on a noindex page wastes the links it holds and Google treats nofollow as a hint. |
| 79 | L'instruction d'indexation ou de non indexation n'est déclarée qu'une seule fois (ex : il n'existe qu'une seule balise <meta name="robots"...> par page). | Became a rule | crawl.signals-agreeTwo robots directives on one URL is a conflict, which is what the rule samples for. |
| 80 | Les balises title sont définies sur chaque page | Became a rule | seo.title-description |
| 81 | Les balises title sont propres à chaque page (pas de duplication) | Became a rule | seo.title-descriptionNo two sampled pages share either. |
| 82 | Les balises title sont écrites selon les bonnes pratiques SEO (pas de bourrage de mots-clés, etc.) | No rule carries it | Editorial quality of a title is asserted by no rule. seo.title-description grades presence, uniqueness and length, which is the measurable proxy the standard deliberately uses instead. Unaccounted, and not worth a rule: keyword stuffing is a judgement, not a check. |
| 83 | Il n'y a qu'une seule balise title par page | Became a rule | html.valid-markupTwo title elements in one head is an HTML validity error, so the W3C validator run catches it. |
| 84 | Les balises meta description sont définies sur chaque page | Became a rule | seo.title-description |
| 85 | Les balises meta description sont propres à chaque page (pas de duplication) | Became a rule | seo.title-description |
| 86 | Les balises meta description sont écrites selon les bonnes pratiques SEO (pas de bourrage de mots-clés, etc.) | No rule carries it | Same as row 82, for the description rather than the title: editorial quality is a judgement, and seo.title-description grades the 70-to-160-character range instead, which is the measurable proxy the standard deliberately uses in its place. Not worth a rule. |
| 87 | Il n'y a qu'une seule balise meta description par page | Became a rule | seo.title-descriptionCarried since 2026-09-10 by seo.title-description: exactly one title element, one description and one robots meta per page. |
| 88 | Les balises h1 sont définies sur chaque page | Became a rule | html.single-h1 |
| 89 | Les balises h1 sont propres à chaque page (pas de duplication) | Became a rule | html.single-h1Carried since 2026-09-10 by html.single-h1: no two sampled pages share an h1. |
| 90 | Les balises h1 sont écrites selon les bonnes pratiques SEO (pas de bourrage de mots-clés, etc.) | Declined in public | declined: h1 tags under 70 charactersDeclined: Google imposes no h1 length, and the counter-verification says so. |
| 91 | Il n'y a qu'une seule balise h1 par page | Became a rule | html.single-h1 |
| 92 | La langue de la page est déclarée à l'aide de l'attribut lang de la balise <html>. La valeur employée respecte la directive RFC 5646. | Became a rule | html.doctype-and-lang |
| 93 | Il existe un seul menu de navigation qui s'adapte et se réorganise en fonction de la taille de l'écran. Cela signifie que le menu ne doit pas être répété à plusieurs endroits dans le code HTML d'une page. | Declined in public | declined: A single navigation menu, not a desktop and a mobile oneDeclined: two menus in the markup is a normal responsive pattern and costs nothing at crawl. |
| 94 | Les pages du site utilisent une structure sémantique HTML5 appropriée, en utilisant des balises pour leur signification intrinsèque et non leurs propriétés de style. Cela comprend notamment : - <article> pour représenter un contenu autonome ou indépendant sur la page - <section> pour les parties distinctes d'un contenu - <nav> pour la navigation - <main> pour le contenu principal de la page - <aside> pour le contenu tangentiel, accessoire ou complémentaire (ex : articles associés) - <header> et <footer> pour l'en-tête et le pied de page d'une section ou d'une page - <table> pour les tables de données (et non pour la mise en page) - <h1> à <h6> pour les titres et sous-titres - <p> pour les paragraphes - <ul> et <ol> pour les listes | Half and half | html.landmarks, html.lists-and-tables · declined: Blog and product pages could add an aside; article should wrap the whole itemThe semantic-HTML5 requirement is two rules. The specific aside and article advice in the row's own detail is declined. |
| 95 | Les balises <h1> à <h6> sont réservées au contenu principal de la page. Elles ne sont pas utilisées sur les éléments qui se répètent sur toutes les pages (éléments de navigation, footer, etc.). | Became a rule | seo.headings-describe-content, html.landmarksHeadings describe the section beneath them, and repeated chrome sits in landmarks rather than in the outline. |
| 96 | La hiérarchie et l'ordre des balises <h1> à <h6> sont respectés : ils suivent une progression logique. | Became a rule | html.single-h1, seo.headings-describe-contentNo skipped heading levels, and the outline reads as an outline. |
| 97 | Des données structurées Schema.org sont utilisées sur le site afin de permettre l'affichage de résultats de recherche enrichis. | Became a rule | seo.structured-data |
| 98 | Le fil d'Ariane fait l'objet de données structurées BreadcrumbList. | Became a rule | crawl.breadcrumb-trailBreadcrumbList carrying the same items, names and order as the visible trail. |
| 99 | La page d'accueil fait l'objet de données structurées Organization (organisation), LocalBusiness (entreprise locale) ou d'un sous-type représentatif de l'activité du site. Ces données sont administrables depuis le back office. | Became a rule | seo.structured-data, practices.no-hardcoded-contentOne Organization node with a name matching the brand; the editable-from-the-back-office half is the second rule. |
| 100 | Les pages de produits font l'objet de données structurées Product. | No rule carries it | seo.structured-data names Organization and BreadcrumbList as the types to emit, and onpage.schema-fidelity checks that whatever is emitted matches the page. Neither requires a Product node on a product page, and no project in this estate has products. A commerce project would need a rule naming the types its templates owe. |
| 101 | Les avis et évaluations des clients font l'objet de données structurées Review (avis spécifique) et/ou AggregateRating (évaluation globale). | No rule carries it | The standard takes the opposite position on purpose. onpage.schema-fidelity forbids emitting an aggregateRating for reviews that only exist client-side, and the checklist's own 8.20 says review stars only if the reviews are genuinely visible. Unaccounted by design; the standard should not adopt this row. |
| 102 | Les contenus éditoriaux, d'actualités ou de blog font l'objet de données structurées Article (contenu éditorial générique), NewsArticle (articles d'actualités) ou BlogPosting (articles de blog). | Became a rule | onpage.schema-fidelityType fits the page: Article for articles. |
| 103 | Les données structurées sont correctement intégrées au format JSON-LD. | Became a rule | seo.structured-dataJSON-LD is the format the rule's do assumes throughout. |
| 104 | Des noms de fichier descriptifs et explicites sont donnés aux images, en utilisant des traits d'union pour séparer les mots. | Declined in public | declined: Descriptive image filenames, hyphens not underscoresDeclined: Google reads alt text and surrounding copy, and a CMS renames uploads anyway. |
| 105 | Vos images sont toutes présentes sur le site (aucune image vide ou de remplissage) | Became a rule | delivery.real-content0 references to a starter-theme demo image across the sitemap. |
| 106 | L'attribut alt est renseigné pour chaque image porteuse d'information afin de décrire simplement ce que représente l'image. | Became a rule | a11y.alt-textAlt that earns its place, empty on decorative. |
| 107 | Le site utilise des URL distinctes pour chaque version linguistique ou régionale, sans ajustement basé sur les cookies ou les paramètres du navigateur ni modification dynamique. | Became a rule | crawl.language-urlsA distinct URL per language, no adjustment by cookie or browser setting. |
| 108 | Le site utilise l'une des structures suivantes : - des noms de domaine spécifiques au pays (domaines nationaux ccTLD) - des sous-domaines d'un domaine de premier niveau générique (gTLD) - des répertoires d'un domaine de premier niveau générique (gTLD) Le site n'utilise pas de paramètres d'URL pour la gestion du multilingue/multirégional. | Became a rule | crawl.language-urlsSubdirectory, subdomain or its own domain - the rule names the same three. |
| 109 | Le site permet aux utilisateurs de changer la langue de la page, par exemple par l'utilisation d'un lien hypertexte, d'un drapeau ou d'une liste déroulante. | Became a rule | crawl.language-urlsEvery switcher control is an a element with an href. |
| 110 | Aucune redirection automatique n'est utilisée en fonction des paramètres linguistiques du navigateur (attribut Accept-Language) ou de l'emplacement de l'adresse IP de l'utilisateur. | Became a rule | crawl.language-urls0 automatic redirects by IP or Accept-Language, which the rule argues costs a whole language index rather than a score. |
| 111 | Chaque page ne propose qu'une seule langue et évite les traductions côte à côte pour faciliter l'identification de la langue. | Became a rule | html.doctype-and-langA page carrying two languages cannot have a lang attribute that matches its visible copy, which is the rule's own measurable. |
| 112 | Le site utilise des annotations hreflang pour indiquer la correspondance entre les pages et les zones géographiques ou langues. | Became a rule | seo.hreflang |
| 113 | Les URL utilisées pour les annotations hreflang renvoient un code de réponse 200 et sont indexables. | Became a rule | seo.hreflangFollowing any alternate must land on a page that lists the original back, which a non-200 cannot do. |
| 114 | Les langues des annotations hreflang suivent le format ISO 639-1, et les régions (facultatives) sont conformes au format ISO 3166-1 Alpha 2. | Became a rule | seo.hreflangCarried since 2026-09-10 by seo.hreflang: ISO 639-1 codes with at most an ISO 3166-1 region, never a locale. |
| 115 | Les annotations hreflang sont correctes : pas de doublons pour une même langue, pas de liens de renvoi manquants ou de pages qui ne se référencent pas elles-mêmes. | Became a rule | seo.hreflangEvery version plus itself plus x-default, all pointing back. |
| 116 | La langue de l'URL reflète celle du contenu de la page. | Declined in public | declined: URL language reflects page content - two reviewers reached opposite verdictsDeclined here as an audit row while crawl.url-format keeps the requirement, because the grid states it twice and grades it two different ways - row 63 Incomplet, row 116 the same text. |
| 117 | La langue de la page est déclarée à l'aide de l'attribut lang de la balise <html>. La valeur employée respecte la directive RFC 5646. | Became a rule | html.doctype-and-langThe same control as row 92, stated twice in the grid. |
4. Expérience Utilisateur 8
| Item | What they asked for | Outcome | What we did with it |
|---|---|---|---|
| 118 | Le site utilise le protocole HTTPS, ce qui permet une connexion sécurisée entre l'utilisateur et le serveur. | Became a rule | seo.https-and-mixed-content |
| 119 | Il n'y a pas de mélange de contenus sécurisés (HTTPS) et non sécurisés (HTTP) sur les pages (contenu mixte). En particulier, toutes les ressources du site, telles que les images, les scripts et les feuilles de style, sont également sécurisées et utilisent le protocole HTTPS. | Became a rule | seo.https-and-mixed-contentNo sampled page contains an http:// asset URL. |
| 120 | Le site est conçu en suivant une logique Mobile First (expérience utilisateur optimale sur les appareils mobiles) et s’adapte aux différents appareils et tailles d’écran (ordinateurs de bureau, tablettes ou smartphones). | Became a rule | practices.responsive-breakpointsThe rule replaces mobile-first as a philosophy with a measurable range, 320 to 2560. |
| 121 | Les éléments interactifs, tels que des boutons ou des liens, ne sont pas placés trop près les uns des autres. | Became a rule | a11y.target-size24 px of clear space is the rule's alternative to the size floor. |
| 122 | La taille du texte utilisée sur le site est suffisamment grande pour être lisible facilement. | Became a rule | a11y.zoom-and-reflowCarried since 2026-09-10 by a11y.zoom-and-reflow: body text computes to 16 px or more at every width. |
| 123 | Le contenu de la page ne dépasse pas la largeur de l'écran et ne nécessite donc pas de défilement horizontal. | Became a rule | practices.responsive-breakpointsNo horizontal scroll across the range. |
| 124 | Le contenu est immédiatement accessible aux utilisateurs, sans être visuellement couvert ou obstrué par des fenêtres pop-up ou des interstitiels intrusifs. | Declined in public | declined: No intrusive interstitial covering the content on arrivalDeclined: the cookie banner is a required interstitial and legal.cookie-banner governs it. |
| 125 | Le contenu principal du site est visible par défaut. En particulier, le contenu important n'est pas masqué par des propriétés CSS telles que "display:none" ou chargé en utilisant uniquement du JavaScript. | Became a rule | crawl.content-in-server-html, states.no-js-fallbackTwo rules, deliberately: one for the crawler, one for the visitor. |
5. Web Performance 37
| Item | What they asked for | Outcome | What we did with it |
|---|---|---|---|
| 126 | Les pages indexables du site ont un score LCP (Largest Contentful Paint) inférieur à 4 s. | Declined in public | declined: LCP under 4 s, INP under 500 ms, CLS under 0.25Declined: these are the poor-threshold boundaries, not the good ones. perf.lcp holds 2.5 s instead. |
| 127 | Les pages indexables du site ont un score INP (Interaction To Next Paint) inférieur à 500 ms. | Declined in public | declined: LCP under 4 s, INP under 500 ms, CLS under 0.25perf.inp-tbt holds 200 ms instead. |
| 128 | Les pages indexables du site ont un score CLS (Cumulative Layout Shift) inférieur à 0,25. | Declined in public | declined: LCP under 4 s, INP under 500 ms, CLS under 0.25perf.cls holds 0.1 instead. |
| 129 | Le temps de réponse initial du serveur (TTFB) est inférieur à 600 ms. | Became a rule | perf.ttfbThe grid says 600 ms and the rule says 800 ms, so the rule is looser here and it is the only threshold in the grid where that is true. |
| 130 | Le protocole HTTP/2 est utilisé pour toutes les ressources du site. | Declined in public | declined: HTTP/2 used for all resourcesDeclined: it is a hosting fact rather than a build one, and every host in scope already serves it. |
| 131 | Le nombre de requêtes et la taille des transferts sont réduits au maximum. | Became a rule | perf.page-weight, perf.enqueue-hygieneTransfer size is budgeted; request count is graded as no asset requested twice and no unused library. |
| 132 | Les chaînes de requêtes critiques, qui sont des séquences de requêtes essentielles au rendu de la page et qui dépendent les unes des autres, sont évitées. | Became a rule | perf.no-render-blockingThe render-blocking audit lists nothing beyond the site's own critical stylesheet. |
| 133 | Les chaînes de redirections inutiles, telles que les redirections de HTTP vers HTTPS, puis de HTTPS vers HTTPS WWW, sont évitées. | Became a rule | seo.https-and-mixed-content, seo.internal-links-resolveOne 301 to https, and no chain of more than one redirect. |
| 134 | La taille totale des ressources chargées par chaque page est inférieure à 5000 KiB afin d'éviter des charges de données excessives. | Became a rule | perf.page-weightThe transfer half of the rule. The grid allows 5000 KiB and the rule allows 2 MB with video excluded, so the rule is materially stricter. Row 139 carries the DOM half, and the rule rests on both rows rather than this one - which its citation has said since 2026-08-26, when it turned out to name only this row while setting a limit from that one. |
| 135 | Les ressources statiques (polices, images, médias, scripts et feuilles de style) sont mises en cache de manière efficace. | Became a rule | perf.caching-and-compressionA year, immutable, on hashed assets. |
| 136 | La compression du texte est activée en utilisant des méthodes telles que Brotli, Gzip ou Deflate pour réduire la taille des fichiers. | Became a rule | perf.caching-and-compressionbr or gzip on HTML, CSS and JS, read off the live response rather than assumed. |
| 137 | Les requêtes clés vers des ressources tierces, comme Facebook ou YouTube, utilisent la préconnexion (<link rel=preconnect>). | Became a rule | perf.enqueue-hygieneThe rule caps resource hints at four rather than requiring them, which is a deliberate tension with this row: past four, hints compete with the requests they should speed up. |
| 138 | Les ressources tierces sont chargées à l'aide de façades, de sorte que leur chargement réel n'a lieu que lorsque l'utilisateur interagit avec elles. | Became a rule | perf.third-partyThe rule grades the outcome - under 250 ms combined main-thread time - and leaves the facade as one way to reach it. |
| 139 | La taille du DOM de chaque page est inférieure à 1500 nœuds, avec une profondeur de moins de 32 nœuds. | Became a rule | perf.page-weight1400 elements against the grid's 1500, with an escape the grid does not offer: since 2026-08-26 a template whose length is set by how much content it holds may pass the element half by measuring instead, on its largest page. The element cap is a proxy for main-thread cost, this standard measures that cost directly in perf.inp-tbt, and where a proxy and the thing it stands for disagree the proxy is what gives. This site is the worked example on /self-check/. The depth-under-32 half is in no rule and is rarely the binding constraint. |
| 140 | Les pages utilisent des écouteurs d'événements passifs pour améliorer les performances de défilement. | No rule carries it | Passive event listeners appear in no rule. perf.inp-tbt grades the outcome they serve - median mobile TBT of 200 ms or less - so this is unaccounted and not worth a rule of its own. |
| 141 | Tout le texte reste visible pendant le chargement des polices Web, garantissant une expérience de lecture continue. | Became a rule | perf.fontsfont-display is set, which is what keeps text visible during the swap. |
| 142 | Le thread principal des pages du site n'est pas occupé pendant plus de 4 secondes. | Became a rule | perf.inp-tbtThe grid allows 4 s of main-thread work and the rule allows 200 ms of TBT, so the rule is far stricter. |
| 143 | Le code tiers, tel que le suivi (tracking) ou le chargement des webfonts, ne bloque pas le thread principal pendant plus de 250 ms. | Became a rule | perf.third-party250 ms in both, and the only threshold in the grid the standard adopted unchanged. |
| 144 | Les animations non-composées, c'est-à-dire les modifications CSS/JS qui entraînent une réimpression des pixels sur la page, sont évitées pour améliorer les performances et la fluidité de l'expérience utilisateur. | Became a rule | perf.animation-costtransform and opacity only. |
| 145 | Les changements majeurs de mise en page (apparition soudaine ou déplacement d'éléments) sont évités pour ne pas perturber les utilisateurs. | Became a rule | perf.cls |
| 146 | Les images PNG et JPG sont compressées de manière efficace pour réduire leur taille. | Became a rule | perf.image-formats |
| 147 | Les images sont diffusées au format AVIF, WebP, JPEG 2000 ou JPEG XR. | Became a rule | perf.image-formatsThe rule requires WebP or AVIF and drops JPEG 2000 and JPEG XR, which no current browser needs. |
| 148 | Le chargement des images masquées ou situées en dessous de la ligne de flottaison est différé (lazy loading). | Became a rule | perf.lazy-and-priority |
| 149 | Les images sont correctement dimensionnées et ne nécessitent pas d'être réduites par le navigateur. | Became a rule | perf.image-formatsNo image transfers more than twice the bytes needed at its displayed size. |
| 150 | Les images ont des dimensions spécifiées explicitement avec les attributs width et height. | Became a rule | perf.clswidth and height on every image and video, in the rule's do. |
| 151 | L'image la plus large de la page (ex : bannière de la page d'accueil, visuel produit principal) est préchargée. | Became a rule | perf.lazy-and-priorityfetchpriority high on the LCP image, and never lazy. |
| 152 | Les fichiers GIF animés sont convertis en formats vidéo tels que MPEG4 ou WebM pour optimiser leur taille. | Became a rule | perf.image-formatsCarried since 2026-09-10 by perf.image-formats: no animated GIF is served. |
| 153 | Le temps d'exécution du JavaScript est maintenu en dessous de 3s. | Became a rule | perf.inp-tbtMain thread kept free during load. |
| 154 | Les scripts sont exécutés de manière à ne pas bloquer le rendu de la page. | Became a rule | perf.no-render-blockingDeferred or type=module. |
| 155 | La fonction JavaScript document.write() n'est pas utilisée. | Declined in public | declined: document.write() is not usedDeclined: no code in this estate uses it and no build tool emits it. |
| 156 | Les ressources JavaScript sont minifiées en supprimant les espaces, les virgules et les caractères inutiles. | Became a rule | perf.bundle-budgetsThe rule grades the bytes rather than the technique, and a gzip budget per chunk cannot be met unminified. |
| 157 | Les ressources JavaScript inutilisées ou non-critiques sont supprimées ou réduites. | Became a rule | perf.bundle-budgets, perf.split-points-assertedThe second rule is the one Vocalcom fails: the chunk assertion exists and nothing that ships runs it. |
| 158 | L'ancien standard JavaScript (ES5) n'est pas proposé aux navigateurs modernes afin d'éviter les téléchargements inutiles de fichiers. | Became a rule | perf.bundle-budgetsNo rule names a browser target; legacy bytes are caught as bytes. |
| 159 | Les pages n'héritent pas de modules JavaScript dupliqués provenant de différentes sources. | Became a rule | perf.split-points-assertedCarried since 2026-09-10 by perf.split-points-asserted: no module appears in two chunks. |
| 160 | Les ressources CSS sont minifiées en supprimant les espaces, les virgules et les caractères inutiles. | Became a rule | perf.bundle-budgetsSame as row 156, for CSS. |
| 161 | Les ressources CSS inutilisées ou non-critiques sont supprimées ou réduites. | Became a rule | perf.bundle-budgets, perf.optimiser-output-freshThe second rule is the one that keeps a Remove Unused CSS pass from stripping the classes JavaScript toggles. |
| 162 | Les feuilles de style ne bloquent pas le rendu de la page. | Became a rule | perf.no-render-blockingOnly above-the-fold CSS is render-blocking. |
6. Vérification et Mesure 2
| Item | What they asked for | Outcome | What we did with it |
|---|---|---|---|
| 163 | Une propriété Search Console a été ajoutée pour le site. | Became a rule | crawl.search-consoleThe rule adds the half that keeps failing: the build team's own account can open Coverage. |
| 164 | Un outil de suivi de trafic (ex : Google Analytics) a été installé sur le site. | Became a rule | comms.conversion-events, legal.no-tags-before-consentInstalled by the first, consent-gated by the second. |