@brandlab-digital/conformance 3.7.0 → 3.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +26 -0
- package/dist/current-release.js +5 -5
- package/dist/current-release.js.map +1 -1
- package/dist/engineering.js +4 -2
- package/dist/engineering.js.map +1 -1
- package/dist/public-copy.d.ts +7 -0
- package/dist/public-copy.d.ts.map +1 -1
- package/dist/public-copy.js +8 -3
- package/dist/public-copy.js.map +1 -1
- package/dist/ready-cli.d.ts +38 -0
- package/dist/ready-cli.d.ts.map +1 -0
- package/dist/ready-cli.js +327 -0
- package/dist/ready-cli.js.map +1 -0
- package/dist/site-system/checks.d.ts +389 -0
- package/dist/site-system/checks.d.ts.map +1 -0
- package/dist/site-system/checks.js +96 -0
- package/dist/site-system/checks.js.map +1 -0
- package/dist/site-system/config.d.ts +40 -0
- package/dist/site-system/config.d.ts.map +1 -0
- package/dist/site-system/config.js +214 -0
- package/dist/site-system/config.js.map +1 -0
- package/dist/site-system/index.d.ts +14 -0
- package/dist/site-system/index.d.ts.map +1 -0
- package/dist/site-system/index.js +14 -0
- package/dist/site-system/index.js.map +1 -0
- package/dist/site-system/journeys/access.d.ts +7 -0
- package/dist/site-system/journeys/access.d.ts.map +1 -0
- package/dist/site-system/journeys/access.js +263 -0
- package/dist/site-system/journeys/access.js.map +1 -0
- package/dist/site-system/journeys/browser.d.ts +79 -0
- package/dist/site-system/journeys/browser.d.ts.map +1 -0
- package/dist/site-system/journeys/browser.js +218 -0
- package/dist/site-system/journeys/browser.js.map +1 -0
- package/dist/site-system/journeys/conversion.d.ts +3 -0
- package/dist/site-system/journeys/conversion.d.ts.map +1 -0
- package/dist/site-system/journeys/conversion.js +152 -0
- package/dist/site-system/journeys/conversion.js.map +1 -0
- package/dist/site-system/journeys/menu.d.ts +11 -0
- package/dist/site-system/journeys/menu.d.ts.map +1 -0
- package/dist/site-system/journeys/menu.js +395 -0
- package/dist/site-system/journeys/menu.js.map +1 -0
- package/dist/site-system/journeys/page-helpers.d.ts +146 -0
- package/dist/site-system/journeys/page-helpers.d.ts.map +1 -0
- package/dist/site-system/journeys/page-helpers.js +426 -0
- package/dist/site-system/journeys/page-helpers.js.map +1 -0
- package/dist/site-system/journeys/plan.d.ts +82 -0
- package/dist/site-system/journeys/plan.d.ts.map +1 -0
- package/dist/site-system/journeys/plan.js +112 -0
- package/dist/site-system/journeys/plan.js.map +1 -0
- package/dist/site-system/journeys/shell.d.ts +24 -0
- package/dist/site-system/journeys/shell.d.ts.map +1 -0
- package/dist/site-system/journeys/shell.js +269 -0
- package/dist/site-system/journeys/shell.js.map +1 -0
- package/dist/site-system/playwright-report.d.ts +22 -0
- package/dist/site-system/playwright-report.d.ts.map +1 -0
- package/dist/site-system/playwright-report.js +131 -0
- package/dist/site-system/playwright-report.js.map +1 -0
- package/dist/site-system/records.d.ts +30 -0
- package/dist/site-system/records.d.ts.map +1 -0
- package/dist/site-system/records.js +98 -0
- package/dist/site-system/records.js.map +1 -0
- package/dist/site-system/report.d.ts +116 -0
- package/dist/site-system/report.d.ts.map +1 -0
- package/dist/site-system/report.js +366 -0
- package/dist/site-system/report.js.map +1 -0
- package/dist/site-system/rule-modules.d.ts +8 -0
- package/dist/site-system/rule-modules.d.ts.map +1 -0
- package/dist/site-system/rule-modules.js +33 -0
- package/dist/site-system/rule-modules.js.map +1 -0
- package/dist/site-system/rules/design/d4-distinctness.d.ts +36 -0
- package/dist/site-system/rules/design/d4-distinctness.d.ts.map +1 -0
- package/dist/site-system/rules/design/d4-distinctness.js +207 -0
- package/dist/site-system/rules/design/d4-distinctness.js.map +1 -0
- package/dist/site-system/rules/design/index.d.ts +17 -0
- package/dist/site-system/rules/design/index.d.ts.map +1 -0
- package/dist/site-system/rules/design/index.js +7 -0
- package/dist/site-system/rules/design/index.js.map +1 -0
- package/dist/site-system/rules/enquiry/c2-quote-form.d.ts +31 -0
- package/dist/site-system/rules/enquiry/c2-quote-form.d.ts.map +1 -0
- package/dist/site-system/rules/enquiry/c2-quote-form.js +211 -0
- package/dist/site-system/rules/enquiry/c2-quote-form.js.map +1 -0
- package/dist/site-system/rules/enquiry/common.d.ts +37 -0
- package/dist/site-system/rules/enquiry/common.d.ts.map +1 -0
- package/dist/site-system/rules/enquiry/common.js +59 -0
- package/dist/site-system/rules/enquiry/common.js.map +1 -0
- package/dist/site-system/rules/enquiry/e1-recorded-titles.d.ts +8 -0
- package/dist/site-system/rules/enquiry/e1-recorded-titles.d.ts.map +1 -0
- package/dist/site-system/rules/enquiry/e1-recorded-titles.js +59 -0
- package/dist/site-system/rules/enquiry/e1-recorded-titles.js.map +1 -0
- package/dist/site-system/rules/enquiry/e9-cost-guides.d.ts +22 -0
- package/dist/site-system/rules/enquiry/e9-cost-guides.d.ts.map +1 -0
- package/dist/site-system/rules/enquiry/e9-cost-guides.js +55 -0
- package/dist/site-system/rules/enquiry/e9-cost-guides.js.map +1 -0
- package/dist/site-system/rules/enquiry/html.d.ts +53 -0
- package/dist/site-system/rules/enquiry/html.d.ts.map +1 -0
- package/dist/site-system/rules/enquiry/html.js +294 -0
- package/dist/site-system/rules/enquiry/html.js.map +1 -0
- package/dist/site-system/rules/enquiry/index.d.ts +17 -0
- package/dist/site-system/rules/enquiry/index.d.ts.map +1 -0
- package/dist/site-system/rules/enquiry/index.js +26 -0
- package/dist/site-system/rules/enquiry/index.js.map +1 -0
- package/dist/site-system/rules/enquiry/k8-sections.d.ts +17 -0
- package/dist/site-system/rules/enquiry/k8-sections.d.ts.map +1 -0
- package/dist/site-system/rules/enquiry/k8-sections.js +76 -0
- package/dist/site-system/rules/enquiry/k8-sections.js.map +1 -0
- package/dist/site-system/rules/enquiry/literal.d.ts +29 -0
- package/dist/site-system/rules/enquiry/literal.d.ts.map +1 -0
- package/dist/site-system/rules/enquiry/literal.js +189 -0
- package/dist/site-system/rules/enquiry/literal.js.map +1 -0
- package/dist/site-system/rules/enquiry/t11-licence-classes.d.ts +73 -0
- package/dist/site-system/rules/enquiry/t11-licence-classes.d.ts.map +1 -0
- package/dist/site-system/rules/enquiry/t11-licence-classes.js +275 -0
- package/dist/site-system/rules/enquiry/t11-licence-classes.js.map +1 -0
- package/dist/site-system/rules/enquiry/t5-reviews.d.ts +23 -0
- package/dist/site-system/rules/enquiry/t5-reviews.d.ts.map +1 -0
- package/dist/site-system/rules/enquiry/t5-reviews.js +91 -0
- package/dist/site-system/rules/enquiry/t5-reviews.js.map +1 -0
- package/dist/site-system/rules/form/c11-contact-route.d.ts +5 -0
- package/dist/site-system/rules/form/c11-contact-route.d.ts.map +1 -0
- package/dist/site-system/rules/form/c11-contact-route.js +132 -0
- package/dist/site-system/rules/form/c11-contact-route.js.map +1 -0
- package/dist/site-system/rules/form/c7-thank-you.d.ts +20 -0
- package/dist/site-system/rules/form/c7-thank-you.d.ts.map +1 -0
- package/dist/site-system/rules/form/c7-thank-you.js +67 -0
- package/dist/site-system/rules/form/c7-thank-you.js.map +1 -0
- package/dist/site-system/rules/form/c8-forgiving-form.d.ts +19 -0
- package/dist/site-system/rules/form/c8-forgiving-form.d.ts.map +1 -0
- package/dist/site-system/rules/form/c8-forgiving-form.js +128 -0
- package/dist/site-system/rules/form/c8-forgiving-form.js.map +1 -0
- package/dist/site-system/rules/form/index.d.ts +14 -0
- package/dist/site-system/rules/form/index.d.ts.map +1 -0
- package/dist/site-system/rules/form/index.js +13 -0
- package/dist/site-system/rules/form/index.js.map +1 -0
- package/dist/site-system/rules/library/common.d.ts +36 -0
- package/dist/site-system/rules/library/common.d.ts.map +1 -0
- package/dist/site-system/rules/library/common.js +70 -0
- package/dist/site-system/rules/library/common.js.map +1 -0
- package/dist/site-system/rules/library/index.d.ts +16 -0
- package/dist/site-system/rules/library/index.d.ts.map +1 -0
- package/dist/site-system/rules/library/index.js +19 -0
- package/dist/site-system/rules/library/index.js.map +1 -0
- package/dist/site-system/rules/library/k1-shared-components.d.ts +29 -0
- package/dist/site-system/rules/library/k1-shared-components.d.ts.map +1 -0
- package/dist/site-system/rules/library/k1-shared-components.js +97 -0
- package/dist/site-system/rules/library/k1-shared-components.js.map +1 -0
- package/dist/site-system/rules/navigation/extract.d.ts +50 -0
- package/dist/site-system/rules/navigation/extract.d.ts.map +1 -0
- package/dist/site-system/rules/navigation/extract.js +220 -0
- package/dist/site-system/rules/navigation/extract.js.map +1 -0
- package/dist/site-system/rules/navigation/html.d.ts +23 -0
- package/dist/site-system/rules/navigation/html.d.ts.map +1 -0
- package/dist/site-system/rules/navigation/html.js +219 -0
- package/dist/site-system/rules/navigation/html.js.map +1 -0
- package/dist/site-system/rules/navigation/index.d.ts +37 -0
- package/dist/site-system/rules/navigation/index.d.ts.map +1 -0
- package/dist/site-system/rules/navigation/index.js +163 -0
- package/dist/site-system/rules/navigation/index.js.map +1 -0
- package/dist/site-system/rules/navigation/record.d.ts +8 -0
- package/dist/site-system/rules/navigation/record.d.ts.map +1 -0
- package/dist/site-system/rules/navigation/record.js +39 -0
- package/dist/site-system/rules/navigation/record.js.map +1 -0
- package/dist/site-system/rules/sections/exif.d.ts +22 -0
- package/dist/site-system/rules/sections/exif.d.ts.map +1 -0
- package/dist/site-system/rules/sections/exif.js +218 -0
- package/dist/site-system/rules/sections/exif.js.map +1 -0
- package/dist/site-system/rules/sections/images.d.ts +31 -0
- package/dist/site-system/rules/sections/images.d.ts.map +1 -0
- package/dist/site-system/rules/sections/images.js +96 -0
- package/dist/site-system/rules/sections/images.js.map +1 -0
- package/dist/site-system/rules/sections/index.d.ts +20 -0
- package/dist/site-system/rules/sections/index.d.ts.map +1 -0
- package/dist/site-system/rules/sections/index.js +34 -0
- package/dist/site-system/rules/sections/index.js.map +1 -0
- package/dist/site-system/rules/sections/k11-density.d.ts +23 -0
- package/dist/site-system/rules/sections/k11-density.d.ts.map +1 -0
- package/dist/site-system/rules/sections/k11-density.js +88 -0
- package/dist/site-system/rules/sections/k11-density.js.map +1 -0
- package/dist/site-system/rules/sections/k12-contact.d.ts +13 -0
- package/dist/site-system/rules/sections/k12-contact.d.ts.map +1 -0
- package/dist/site-system/rules/sections/k12-contact.js +70 -0
- package/dist/site-system/rules/sections/k12-contact.js.map +1 -0
- package/dist/site-system/rules/sections/k2-skin-coverage.d.ts +11 -0
- package/dist/site-system/rules/sections/k2-skin-coverage.d.ts.map +1 -0
- package/dist/site-system/rules/sections/k2-skin-coverage.js +126 -0
- package/dist/site-system/rules/sections/k2-skin-coverage.js.map +1 -0
- package/dist/site-system/rules/sections/n9-footer.d.ts +40 -0
- package/dist/site-system/rules/sections/n9-footer.d.ts.map +1 -0
- package/dist/site-system/rules/sections/n9-footer.js +186 -0
- package/dist/site-system/rules/sections/n9-footer.js.map +1 -0
- package/dist/site-system/rules/sections/t6-media-entries.d.ts +14 -0
- package/dist/site-system/rules/sections/t6-media-entries.d.ts.map +1 -0
- package/dist/site-system/rules/sections/t6-media-entries.js +96 -0
- package/dist/site-system/rules/sections/t6-media-entries.js.map +1 -0
- package/dist/site-system/rules/sections/t7-main-images.d.ts +13 -0
- package/dist/site-system/rules/sections/t7-main-images.d.ts.map +1 -0
- package/dist/site-system/rules/sections/t7-main-images.js +41 -0
- package/dist/site-system/rules/sections/t7-main-images.js.map +1 -0
- package/dist/site-system/rules/sections/t8-prices.d.ts +13 -0
- package/dist/site-system/rules/sections/t8-prices.d.ts.map +1 -0
- package/dist/site-system/rules/sections/t8-prices.js +92 -0
- package/dist/site-system/rules/sections/t8-prices.js.map +1 -0
- package/dist/site-system/rules/sections/t9-location-metadata.d.ts +3 -0
- package/dist/site-system/rules/sections/t9-location-metadata.d.ts.map +1 -0
- package/dist/site-system/rules/sections/t9-location-metadata.js +54 -0
- package/dist/site-system/rules/sections/t9-location-metadata.js.map +1 -0
- package/dist/site-system/rules/shell/banned-wording.d.ts +24 -0
- package/dist/site-system/rules/shell/banned-wording.d.ts.map +1 -0
- package/dist/site-system/rules/shell/banned-wording.js +212 -0
- package/dist/site-system/rules/shell/banned-wording.js.map +1 -0
- package/dist/site-system/rules/shell/budgets.d.ts +43 -0
- package/dist/site-system/rules/shell/budgets.d.ts.map +1 -0
- package/dist/site-system/rules/shell/budgets.js +297 -0
- package/dist/site-system/rules/shell/budgets.js.map +1 -0
- package/dist/site-system/rules/shell/cta-labels.d.ts +17 -0
- package/dist/site-system/rules/shell/cta-labels.d.ts.map +1 -0
- package/dist/site-system/rules/shell/cta-labels.js +86 -0
- package/dist/site-system/rules/shell/cta-labels.js.map +1 -0
- package/dist/site-system/rules/shell/facts.d.ts +33 -0
- package/dist/site-system/rules/shell/facts.d.ts.map +1 -0
- package/dist/site-system/rules/shell/facts.js +217 -0
- package/dist/site-system/rules/shell/facts.js.map +1 -0
- package/dist/site-system/rules/shell/headings.d.ts +5 -0
- package/dist/site-system/rules/shell/headings.d.ts.map +1 -0
- package/dist/site-system/rules/shell/headings.js +23 -0
- package/dist/site-system/rules/shell/headings.js.map +1 -0
- package/dist/site-system/rules/shell/hero-location.d.ts +4 -0
- package/dist/site-system/rules/shell/hero-location.d.ts.map +1 -0
- package/dist/site-system/rules/shell/hero-location.js +45 -0
- package/dist/site-system/rules/shell/hero-location.js.map +1 -0
- package/dist/site-system/rules/shell/html.d.ts +53 -0
- package/dist/site-system/rules/shell/html.d.ts.map +1 -0
- package/dist/site-system/rules/shell/html.js +341 -0
- package/dist/site-system/rules/shell/html.js.map +1 -0
- package/dist/site-system/rules/shell/index.d.ts +18 -0
- package/dist/site-system/rules/shell/index.d.ts.map +1 -0
- package/dist/site-system/rules/shell/index.js +65 -0
- package/dist/site-system/rules/shell/index.js.map +1 -0
- package/dist/site-system/rules/shell/licence.d.ts +4 -0
- package/dist/site-system/rules/shell/licence.d.ts.map +1 -0
- package/dist/site-system/rules/shell/licence.js +60 -0
- package/dist/site-system/rules/shell/licence.js.map +1 -0
- package/dist/site-system/rules/shell/location-wording.d.ts +13 -0
- package/dist/site-system/rules/shell/location-wording.d.ts.map +1 -0
- package/dist/site-system/rules/shell/location-wording.js +15 -0
- package/dist/site-system/rules/shell/location-wording.js.map +1 -0
- package/dist/site-system/rules/shell/navigation.d.ts +5 -0
- package/dist/site-system/rules/shell/navigation.d.ts.map +1 -0
- package/dist/site-system/rules/shell/navigation.js +272 -0
- package/dist/site-system/rules/shell/navigation.js.map +1 -0
- package/dist/site-system/rules/shell/overlays.d.ts +4 -0
- package/dist/site-system/rules/shell/overlays.d.ts.map +1 -0
- package/dist/site-system/rules/shell/overlays.js +93 -0
- package/dist/site-system/rules/shell/overlays.js.map +1 -0
- package/dist/site-system/rules/shell/page.d.ts +51 -0
- package/dist/site-system/rules/shell/page.d.ts.map +1 -0
- package/dist/site-system/rules/shell/page.js +256 -0
- package/dist/site-system/rules/shell/page.js.map +1 -0
- package/dist/site-system/rules/shell/phone.d.ts +13 -0
- package/dist/site-system/rules/shell/phone.d.ts.map +1 -0
- package/dist/site-system/rules/shell/phone.js +99 -0
- package/dist/site-system/rules/shell/phone.js.map +1 -0
- package/dist/site-system/rules/shell/proof-numbers.d.ts +7 -0
- package/dist/site-system/rules/shell/proof-numbers.d.ts.map +1 -0
- package/dist/site-system/rules/shell/proof-numbers.js +81 -0
- package/dist/site-system/rules/shell/proof-numbers.js.map +1 -0
- package/dist/site-system/rules/shell/types.d.ts +80 -0
- package/dist/site-system/rules/shell/types.d.ts.map +1 -0
- package/dist/site-system/rules/shell/types.js +17 -0
- package/dist/site-system/rules/shell/types.js.map +1 -0
- package/dist/site-system/runners.d.ts +37 -0
- package/dist/site-system/runners.d.ts.map +1 -0
- package/dist/site-system/runners.js +48 -0
- package/dist/site-system/runners.js.map +1 -0
- package/dist/site-system/samples.d.ts +43 -0
- package/dist/site-system/samples.d.ts.map +1 -0
- package/dist/site-system/samples.js +99 -0
- package/dist/site-system/samples.js.map +1 -0
- package/dist/site-system/steps.d.ts +66 -0
- package/dist/site-system/steps.d.ts.map +1 -0
- package/dist/site-system/steps.js +45 -0
- package/dist/site-system/steps.js.map +1 -0
- package/dist/site-system/streamed-html.d.ts +9 -0
- package/dist/site-system/streamed-html.d.ts.map +1 -0
- package/dist/site-system/streamed-html.js +43 -0
- package/dist/site-system/streamed-html.js.map +1 -0
- package/dist/site-system-e2e.d.ts +6 -0
- package/dist/site-system-e2e.d.ts.map +1 -0
- package/dist/site-system-e2e.js +54 -0
- package/dist/site-system-e2e.js.map +1 -0
- package/package.json +22 -5
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ready-cli.js","sourceRoot":"","sources":["../src/ready-cli.ts"],"names":[],"mappings":"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","sourcesContent":["#!/usr/bin/env node\nimport { existsSync, mkdirSync, readFileSync, realpathSync, writeFileSync } from \"node:fs\";\nimport { dirname, isAbsolute, join, relative, resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { detectInstalledBrandlabRelease, evaluateBrandlabProject } from \"./project.js\";\nimport type { SiteSystemFinding } from \"./site-system/checks.js\";\nimport { readSiteSystemProjectConfig } from \"./site-system/config.js\";\nimport { readSiteSystemJourneyReport } from \"./site-system/playwright-report.js\";\nimport { appendSiteSystemRecord, readSiteSystemRecords } from \"./site-system/records.js\";\nimport {\n buildSiteSystemReadyReport,\n renderSiteSystemReadyMarkdown,\n SITE_SYSTEM_READY_REPORT_PATHS,\n type SiteSystemReadyReport,\n type SiteSystemVerifyResult,\n} from \"./site-system/report.js\";\nimport { SITE_SYSTEM_RENDERED_RUNNERS } from \"./site-system/rule-modules.js\";\nimport {\n isSiteSystemFinding,\n runSiteSystemRenderedRunners,\n type SiteSystemRenderedRunner,\n} from \"./site-system/runners.js\";\nimport { loadSiteSystemPages, planSiteSystemSamplePaths, type SiteSystemFetch } from \"./site-system/samples.js\";\nimport { SITE_SYSTEM_RECORDED_CHECK_IDS } from \"./site-system/steps.js\";\n\ninterface ReadyReportOptions {\n command: \"report\";\n root: string;\n playwrightReport: string;\n baseUrl?: string;\n buildDir: string;\n findings: string[];\n installedRelease?: string;\n launch: boolean;\n}\n\ninterface ReadyRecordOptions {\n command: \"record\";\n root: string;\n id: string;\n evidence?: string;\n note?: string;\n}\n\ntype ReadyCliOptions = ReadyReportOptions | ReadyRecordOptions | { command: \"help\" };\n\ninterface CliIo {\n stdout: (value: string) => void;\n stderr: (value: string) => void;\n}\n\nexport interface BrandlabReadyCliDependencies {\n /** The rule modules to run (default: SITE_SYSTEM_RENDERED_RUNNERS). */\n runners?: readonly SiteSystemRenderedRunner[];\n fetch?: SiteSystemFetch;\n now?: () => Date;\n}\n\nconst DEFAULT_PLAYWRIGHT_REPORT = \"test-results/site-system.json\";\n/** The checks a --findings file may set: K10 (the lenient harness) and the other recorded checks. */\nconst SUPPLIABLE_IDS = new Set<string>(SITE_SYSTEM_RECORDED_CHECK_IDS);\nconst DEFAULT_BUILD_DIR = \".next\";\n\nconst HELP = `Brandlab ready gate\n\nWrites docs/ready/ready-report.md and .json for the Site System tier declared in\nbrandlab.config.ts (siteSystem: { tier }), and records launch-day and human steps.\n\nUsage:\n brandlab-ready [--root <path>]\n [--playwright-report <path>] journey results (default ${DEFAULT_PLAYWRIGHT_REPORT})\n [--base-url <url>] fetch the sample pages from the running site\n [--build-dir <path>] otherwise read their HTML from the build (default ${DEFAULT_BUILD_DIR})\n [--findings <path>]... K10 or X1 results as SiteSystemFinding JSON (the lenient harness)\n [--installed-release <version>]\n [--launch] also require every launch-day and human step\n brandlab-ready record <id> --evidence <where the proof is> [--note <text>] [--root <path>]\n\nExit status:\n 0 ready at the declared tier, or nothing blocks (no tier declared, or none of its checks released)\n 1 a blocking check failed or did not run, home or the contact page could not be read, a --base-url\n sample did not answer with HTML, or brandlab.config.ts could not be read in full\n (with --launch, also a step not recorded)\n 2 the gate could not run (bad arguments, an unreadable config or records file)\n`;\n\nexport function parseBrandlabReadyArgs(argv: readonly string[]): ReadyCliOptions {\n if (argv.includes(\"--help\") || argv.includes(\"-h\")) return { command: \"help\" };\n if (argv[0] === \"record\") return parseRecordArgs(argv.slice(1));\n const parsed: ReadyReportOptions = {\n command: \"report\",\n root: process.cwd(),\n playwrightReport: DEFAULT_PLAYWRIGHT_REPORT,\n buildDir: DEFAULT_BUILD_DIR,\n findings: [],\n launch: false,\n };\n for (let index = 0; index < argv.length; index += 1) {\n const argument = argv[index];\n if (argument === \"--root\") parsed.root = resolve(requireValue(argv, ++index, argument));\n else if (argument === \"--playwright-report\") parsed.playwrightReport = requireValue(argv, ++index, argument);\n else if (argument === \"--build-dir\") parsed.buildDir = requireValue(argv, ++index, argument);\n else if (argument === \"--findings\") parsed.findings.push(requireValue(argv, ++index, argument));\n else if (argument === \"--installed-release\") parsed.installedRelease = requireValue(argv, ++index, argument);\n else if (argument === \"--launch\") parsed.launch = true;\n else if (argument === \"--base-url\") {\n const value = requireValue(argv, ++index, argument);\n let url: URL;\n try {\n url = new URL(value);\n } catch {\n throw new Error(`--base-url ${value} is not a URL.`);\n }\n if (url.protocol !== \"http:\" && url.protocol !== \"https:\") throw new Error(\"--base-url must be an http or https URL.\");\n parsed.baseUrl = value;\n } else {\n throw new Error(`Unknown argument ${argument}.`);\n }\n }\n return parsed;\n}\n\nfunction parseRecordArgs(argv: readonly string[]): ReadyRecordOptions {\n const parsed: ReadyRecordOptions = { command: \"record\", root: process.cwd(), id: \"\" };\n for (let index = 0; index < argv.length; index += 1) {\n const argument = argv[index]!;\n if (argument === \"--evidence\") parsed.evidence = requireValue(argv, ++index, argument);\n else if (argument === \"--note\") parsed.note = requireValue(argv, ++index, argument);\n else if (argument === \"--root\") parsed.root = resolve(requireValue(argv, ++index, argument));\n else if (!argument.startsWith(\"--\") && !parsed.id) parsed.id = argument;\n else throw new Error(`Unknown argument ${argument}.`);\n }\n if (!parsed.id) throw new Error(\"record needs a step id, for example: brandlab-ready record X3 --evidence <PR link>.\");\n if (parsed.evidence === undefined) throw new Error(`record ${parsed.id} needs --evidence <where the proof is>.`);\n return parsed;\n}\n\nexport async function runBrandlabReadyCli(\n argv: readonly string[],\n io: CliIo = {\n stdout: (value) => process.stdout.write(value),\n stderr: (value) => process.stderr.write(value),\n },\n dependencies: BrandlabReadyCliDependencies = {},\n): Promise<number> {\n let options: ReadyCliOptions;\n try {\n options = parseBrandlabReadyArgs(argv);\n } catch (error) {\n io.stderr(`${errorMessage(error)}\\n\\n${HELP}`);\n return 2;\n }\n if (options.command === \"help\") {\n io.stdout(HELP);\n return 0;\n }\n const now = dependencies.now ?? (() => new Date());\n try {\n if (options.command === \"record\") {\n const { path, record } = appendSiteSystemRecord(options.root, {\n id: options.id,\n evidence: options.evidence ?? \"\",\n ...(options.note !== undefined ? { note: options.note } : {}),\n now: now(),\n });\n io.stdout(`Recorded ${record.id} in ${path}.\\n`);\n return 0;\n }\n const report = await createReadyReport(options, dependencies, now());\n const markdownPath = join(options.root, SITE_SYSTEM_READY_REPORT_PATHS.markdown);\n mkdirSync(dirname(markdownPath), { recursive: true });\n writeFileSync(markdownPath, renderSiteSystemReadyMarkdown(report));\n writeFileSync(join(options.root, SITE_SYSTEM_READY_REPORT_PATHS.json), `${JSON.stringify(report, null, 2)}\\n`);\n const problems = report.problems.length;\n io.stdout(\n `${report.verdict.summary}.\\n` +\n (problems > 0 ? `The report lists ${problems} problem${problems === 1 ? \"\" : \"s\"} with the inputs.\\n` : \"\") +\n `Wrote ${SITE_SYSTEM_READY_REPORT_PATHS.markdown} and ${SITE_SYSTEM_READY_REPORT_PATHS.json}.\\n`,\n );\n return report.verdict.exitCode;\n } catch (error) {\n io.stderr(`${errorMessage(error)}\\n`);\n return 2;\n }\n}\n\nasync function createReadyReport(\n options: ReadyReportOptions,\n dependencies: BrandlabReadyCliDependencies,\n now: Date,\n): Promise<SiteSystemReadyReport> {\n const root = options.root;\n const config = readSiteSystemProjectConfig(root);\n const release = options.installedRelease ?? detectInstalledBrandlabRelease(readPackageJson(root));\n if (config.siteSystem && !release) {\n throw new Error(\n \"The installed Brandlab release could not be read from package.json. Pin all four Brandlab packages to one exact version, or pass --installed-release.\",\n );\n }\n const problems: string[] = [...config.problems];\n const findings: SiteSystemFinding[] = [];\n\n // Journeys: the Playwright JSON report of the site-system spec.\n const journeyPath = resolveIn(root, options.playwrightReport);\n let journeyReport: string | null = null;\n let journeyTests = 0;\n if (!existsSync(journeyPath)) {\n problems.push(`No Playwright report at ${displayPath(root, journeyPath)}, so the journey checks did not run (run the site-system journeys with the JSON reporter first).`);\n } else {\n journeyReport = displayPath(root, journeyPath);\n const parsed = readJson(journeyPath);\n if (parsed === undefined) {\n problems.push(`${journeyReport} is not valid JSON, so the journey checks did not run.`);\n } else {\n const journeys = readSiteSystemJourneyReport(parsed);\n findings.push(...journeys.findings);\n problems.push(...journeys.problems);\n journeyTests = journeys.tests;\n }\n }\n\n // Rendered and static rule modules over the sampled pages.\n const buildDir = resolveIn(root, options.buildDir);\n const prerenderManifest = readJson(join(buildDir, \"prerender-manifest.json\"));\n const paths = planSiteSystemSamplePaths({\n representativeRoutes: config.representativeRoutes,\n samples: config.siteSystem?.samples ?? [],\n prerenderManifest,\n });\n if (!options.baseUrl && prerenderManifest === undefined) {\n problems.push(`No production build at ${displayPath(root, buildDir)}: run next build first, or pass --base-url.`);\n }\n const loaded = options.baseUrl || prerenderManifest !== undefined\n ? await loadSiteSystemPages({ paths, buildDir, baseUrl: options.baseUrl, fetch: dependencies.fetch })\n : { pages: [], missing: paths, source: \"build\" as const, problems: [] };\n problems.push(...loaded.problems);\n if (loaded.pages.length === 0) problems.push(\"No page HTML was available, so the rule modules ran on the project files only.\");\n // Every runner runs: static rules read the project, rendered rules report not-applicable without pages.\n const runners = dependencies.runners ?? SITE_SYSTEM_RENDERED_RUNNERS;\n const rendered = await runSiteSystemRenderedRunners(runners, {\n baseUrl: options.baseUrl ?? \"\",\n pages: loaded.pages,\n missing: loaded.missing,\n projectRoot: root,\n siteSystem: config.siteSystem,\n });\n findings.push(...rendered.findings);\n problems.push(...rendered.problems);\n\n // Fail closed: a config the gate cannot read in full, and (for a declared tier) pages it could not read.\n const blockers: string[] = [];\n if (!config.complete) blockers.push(\"brandlab.config.ts could not be read in full\");\n if (config.siteSystem) {\n if (loaded.source === \"base-url\" && loaded.missing.length > 0) {\n blockers.push(`${loaded.missing.length} sample page${loaded.missing.length === 1 ? \"\" : \"s\"} did not answer with HTML`);\n } else {\n if (loaded.missing.includes(\"/\")) blockers.push(\"the home page could not be read\");\n const contact = config.representativeRoutes.contact;\n if (contact && loaded.missing.includes(contact)) blockers.push(\"the contact page could not be read\");\n }\n }\n\n // Results other tools wrote as SiteSystemFinding JSON.\n for (const file of options.findings) {\n const path = resolveIn(root, file);\n const parsed = readJson(path);\n const list = Array.isArray(parsed) ? parsed : isRecord(parsed) && Array.isArray(parsed.findings) ? parsed.findings : null;\n if (!list) {\n problems.push(`${displayPath(root, path)} is missing or is not a list of findings, so it was ignored.`);\n continue;\n }\n const valid = list.filter(isSiteSystemFinding);\n if (valid.length < list.length) {\n problems.push(`${list.length - valid.length} result(s) in ${displayPath(root, path)} name an unknown check or status, so they were ignored.`);\n }\n // Supplied files carry harness and recorded results only; they cannot pass a journey or rule check.\n const refused = [...new Set(valid.filter((finding) => !SUPPLIABLE_IDS.has(finding.checkId)).map((finding) => finding.checkId))];\n if (refused.length > 0) {\n problems.push(`${displayPath(root, path)} sets ${refused.join(\", \")}, but --findings may only set ${[...SUPPLIABLE_IDS].join(\" and \")}, so those results were ignored.`);\n }\n findings.push(...valid.filter((finding) => SUPPLIABLE_IDS.has(finding.checkId)));\n }\n\n // The existing brandlab-verify families the shell tier carries.\n let verify: SiteSystemVerifyResult | null = null;\n try {\n verify = evaluateBrandlabProject({\n root,\n ...(options.installedRelease !== undefined ? { installedRelease: options.installedRelease } : {}),\n });\n } catch (error) {\n problems.push(`brandlab-verify could not run (${errorMessage(error)}), so its search, contact and analytics checks did not run.`);\n }\n\n return buildSiteSystemReadyReport({\n projectId: config.projectId,\n siteSystem: config.siteSystem,\n release,\n findings,\n verify,\n launchRecords: readSiteSystemRecords(root, \"launch\"),\n humanRecords: readSiteSystemRecords(root, \"human\"),\n exceptions: config.exceptions,\n inputs: {\n journeyReport,\n journeyTests,\n pageSource: loaded.pages.length === 0 ? \"none\" : loaded.source,\n pages: loaded.pages.map((page) => page.path),\n runners: runners.length,\n findingFiles: options.findings.map((file) => displayPath(root, resolveIn(root, file))),\n },\n problems,\n now,\n launch: options.launch,\n blockers,\n });\n}\n\nfunction readPackageJson(root: string): Parameters<typeof detectInstalledBrandlabRelease>[0] {\n const parsed = readJson(join(root, \"package.json\"));\n return isRecord(parsed) ? (parsed as Parameters<typeof detectInstalledBrandlabRelease>[0]) : null;\n}\n\n/** Parsed JSON, or undefined when the file is missing or invalid. */\nfunction readJson(path: string): unknown {\n if (!existsSync(path)) return undefined;\n try {\n return JSON.parse(readFileSync(path, \"utf8\"));\n } catch {\n return undefined;\n }\n}\n\nfunction resolveIn(root: string, path: string): string {\n return isAbsolute(path) ? path : resolve(root, path);\n}\n\nfunction displayPath(root: string, path: string): string {\n const relativePath = relative(root, path);\n return relativePath && !relativePath.startsWith(\"..\") && !isAbsolute(relativePath) ? relativePath : path;\n}\n\nfunction requireValue(argv: readonly string[], index: number, argument: string): string {\n const value = argv[index];\n if (value === undefined || value.startsWith(\"--\")) throw new Error(`${argument} requires a value.`);\n return value;\n}\n\nfunction errorMessage(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return Boolean(value) && typeof value === \"object\" && !Array.isArray(value);\n}\n\nexport function isBrandlabReadyCliEntrypoint(moduleUrl: string, argvPath: string | undefined): boolean {\n if (!argvPath) return false;\n try {\n return realpathSync(fileURLToPath(moduleUrl)) === realpathSync(resolve(argvPath));\n } catch {\n return false;\n }\n}\n\nif (isBrandlabReadyCliEntrypoint(import.meta.url, process.argv[1])) {\n runBrandlabReadyCli(process.argv.slice(2)).then((code) => {\n process.exitCode = code;\n });\n}\n"]}
|
|
@@ -0,0 +1,389 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Site System v2 ready gate: every check, the adoption tier it blocks at and the release that brings it.
|
|
3
|
+
*
|
|
4
|
+
* A site declares `siteSystem: { tier }` in brandlab.config.ts. Checks of that tier and the tiers below it block;
|
|
5
|
+
* checks of higher tiers report without blocking. A check blocks only from the release named here, so new checks
|
|
6
|
+
* arrive with version bumps and never turn the fleet red at once. Holdouts use the project's Romie-owned
|
|
7
|
+
* `exceptions` record. D6 (leave reviews as they are) removes every review-exclusion clause; D7 (no call tracking)
|
|
8
|
+
* means no number-swap check.
|
|
9
|
+
*
|
|
10
|
+
* `kind` says where a check runs:
|
|
11
|
+
* - `journey`: the Playwright site-system journeys (`defineBrandlabSiteSystemTests`), in the site's e2e run;
|
|
12
|
+
* - `rendered`: rules over the built site's server HTML and assets (`brandlab-ready` reads them);
|
|
13
|
+
* - `static`: source and data rules (`brandlab-verify` and `brandlab-ready`);
|
|
14
|
+
* - `record`: launch-day and human steps recorded with `brandlab-ready record <id> --evidence <ref>`.
|
|
15
|
+
*/
|
|
16
|
+
export declare const SITE_SYSTEM_TIERS: readonly ["shell", "enquiry", "full"];
|
|
17
|
+
export type SiteSystemTier = (typeof SITE_SYSTEM_TIERS)[number];
|
|
18
|
+
/** The design check D4 blocks every new build and redesign, whatever its tier. */
|
|
19
|
+
export type SiteSystemCheckScope = SiteSystemTier | "new-build";
|
|
20
|
+
export type SiteSystemCheckKind = "journey" | "rendered" | "static" | "record";
|
|
21
|
+
export interface SiteSystemCheck {
|
|
22
|
+
readonly id: string;
|
|
23
|
+
readonly tier: SiteSystemCheckScope;
|
|
24
|
+
/** The first release in which the check blocks at its tier. */
|
|
25
|
+
readonly from: `3.${number}.0`;
|
|
26
|
+
readonly kind: SiteSystemCheckKind;
|
|
27
|
+
readonly summary: string;
|
|
28
|
+
}
|
|
29
|
+
export declare const SITE_SYSTEM_CHECKS: readonly [{
|
|
30
|
+
readonly id: "N1";
|
|
31
|
+
readonly tier: "shell";
|
|
32
|
+
readonly from: "3.9.0";
|
|
33
|
+
readonly kind: "rendered";
|
|
34
|
+
readonly summary: "Required nav links, About in the first two, services before Areas, Contact last, labels from the closed list, recorded orders kept.";
|
|
35
|
+
}, {
|
|
36
|
+
readonly id: "N2";
|
|
37
|
+
readonly tier: "shell";
|
|
38
|
+
readonly from: "3.8.0";
|
|
39
|
+
readonly kind: "rendered";
|
|
40
|
+
readonly summary: "Every dropdown link and hub link is an <a href> in the server HTML.";
|
|
41
|
+
}, {
|
|
42
|
+
readonly id: "N3";
|
|
43
|
+
readonly tier: "shell";
|
|
44
|
+
readonly from: "3.8.0";
|
|
45
|
+
readonly kind: "journey";
|
|
46
|
+
readonly summary: "Hover opens after a short delay and a diagonal path stays open; mouse-out closes; nothing sticks open.";
|
|
47
|
+
}, {
|
|
48
|
+
readonly id: "N4";
|
|
49
|
+
readonly tier: "shell";
|
|
50
|
+
readonly from: "3.8.0";
|
|
51
|
+
readonly kind: "journey";
|
|
52
|
+
readonly summary: "A chevron click after hover keeps the panel open; a link click closes it; click, Enter and outside click work.";
|
|
53
|
+
}, {
|
|
54
|
+
readonly id: "N5";
|
|
55
|
+
readonly tier: "shell";
|
|
56
|
+
readonly from: "3.8.0";
|
|
57
|
+
readonly kind: "journey";
|
|
58
|
+
readonly summary: "Keyboard and ARIA: aria-expanded follows the panel, Arrow keys move, Escape closes and returns focus; axe passes open and closed.";
|
|
59
|
+
}, {
|
|
60
|
+
readonly id: "N6";
|
|
61
|
+
readonly tier: "shell";
|
|
62
|
+
readonly from: "3.8.0";
|
|
63
|
+
readonly kind: "journey";
|
|
64
|
+
readonly summary: "The header stays at the top with the phone and quote visible at every desktop width; the compact band shows them from 1024 to 1279 px.";
|
|
65
|
+
}, {
|
|
66
|
+
readonly id: "N8";
|
|
67
|
+
readonly tier: "shell";
|
|
68
|
+
readonly from: "3.9.0";
|
|
69
|
+
readonly kind: "journey";
|
|
70
|
+
readonly summary: "The drawer is a modal dialog that traps focus and resets; the call bar uses placement fab; back-to-top appears (from 3.11.0).";
|
|
71
|
+
}, {
|
|
72
|
+
readonly id: "K1";
|
|
73
|
+
readonly tier: "shell";
|
|
74
|
+
readonly from: "3.9.0";
|
|
75
|
+
readonly kind: "rendered";
|
|
76
|
+
readonly summary: "Shared components in use for the parts the tier covers (data-bl present); no literal tel: outside PhoneLink.";
|
|
77
|
+
}, {
|
|
78
|
+
readonly id: "K3";
|
|
79
|
+
readonly tier: "shell";
|
|
80
|
+
readonly from: "3.8.0";
|
|
81
|
+
readonly kind: "journey";
|
|
82
|
+
readonly summary: "Text contrast 4.5:1 and non-text 3:1 in the browser.";
|
|
83
|
+
}, {
|
|
84
|
+
readonly id: "K4";
|
|
85
|
+
readonly tier: "shell";
|
|
86
|
+
readonly from: "3.8.0";
|
|
87
|
+
readonly kind: "journey";
|
|
88
|
+
readonly summary: "Targets at least 24 px, and 44 px for primary actions (call, quote, menu).";
|
|
89
|
+
}, {
|
|
90
|
+
readonly id: "K5";
|
|
91
|
+
readonly tier: "shell";
|
|
92
|
+
readonly from: "3.8.0";
|
|
93
|
+
readonly kind: "journey";
|
|
94
|
+
readonly summary: "Focus is never fully hidden by the sticky header or call bar at 390 px, in Chromium and WebKit.";
|
|
95
|
+
}, {
|
|
96
|
+
readonly id: "K6";
|
|
97
|
+
readonly tier: "shell";
|
|
98
|
+
readonly from: "3.8.0";
|
|
99
|
+
readonly kind: "journey";
|
|
100
|
+
readonly summary: "Phone and quote in the same relative order on every page, in the header, hero and call bar.";
|
|
101
|
+
}, {
|
|
102
|
+
readonly id: "K7";
|
|
103
|
+
readonly tier: "shell";
|
|
104
|
+
readonly from: "3.8.0";
|
|
105
|
+
readonly kind: "rendered";
|
|
106
|
+
readonly summary: "Dropdown links, accordion and tab panels and full review text are in the server HTML.";
|
|
107
|
+
}, {
|
|
108
|
+
readonly id: "K10";
|
|
109
|
+
readonly tier: "shell";
|
|
110
|
+
readonly from: "3.8.0";
|
|
111
|
+
readonly kind: "record";
|
|
112
|
+
readonly summary: "Adoption parity in the lenient harness: no section, link or text lost against the baseline.";
|
|
113
|
+
}, {
|
|
114
|
+
readonly id: "C4";
|
|
115
|
+
readonly tier: "shell";
|
|
116
|
+
readonly from: "3.8.0";
|
|
117
|
+
readonly kind: "journey";
|
|
118
|
+
readonly summary: "Phone taps report an allowed placement (header, footer, hero, cta, fab, contact, location, page).";
|
|
119
|
+
}, {
|
|
120
|
+
readonly id: "C5";
|
|
121
|
+
readonly tier: "shell";
|
|
122
|
+
readonly from: "3.8.0";
|
|
123
|
+
readonly kind: "rendered";
|
|
124
|
+
readonly summary: "Call-to-action labels come from the closed list or a recorded label.";
|
|
125
|
+
}, {
|
|
126
|
+
readonly id: "C9";
|
|
127
|
+
readonly tier: "shell";
|
|
128
|
+
readonly from: "3.8.0";
|
|
129
|
+
readonly kind: "rendered";
|
|
130
|
+
readonly summary: "No interstitial overlay in the first screen.";
|
|
131
|
+
}, {
|
|
132
|
+
readonly id: "C10";
|
|
133
|
+
readonly tier: "shell";
|
|
134
|
+
readonly from: "3.8.0";
|
|
135
|
+
readonly kind: "rendered";
|
|
136
|
+
readonly summary: "Every tel: href is E.164 (national digits for 13, 1300 and 1800) and matches the evidence-file phone.";
|
|
137
|
+
}, {
|
|
138
|
+
readonly id: "E1";
|
|
139
|
+
readonly tier: "shell";
|
|
140
|
+
readonly from: "3.8.0";
|
|
141
|
+
readonly kind: "static";
|
|
142
|
+
readonly summary: "Title patterns on new or changed URLs; recorded titles unchanged.";
|
|
143
|
+
}, {
|
|
144
|
+
readonly id: "E2";
|
|
145
|
+
readonly tier: "shell";
|
|
146
|
+
readonly from: "3.8.0";
|
|
147
|
+
readonly kind: "rendered";
|
|
148
|
+
readonly summary: "Exactly one H1 on every page, rendered once.";
|
|
149
|
+
}, {
|
|
150
|
+
readonly id: "E8";
|
|
151
|
+
readonly tier: "shell";
|
|
152
|
+
readonly from: "3.8.0";
|
|
153
|
+
readonly kind: "rendered";
|
|
154
|
+
readonly summary: "No banned phrase from any of the three layers, environmental claims included.";
|
|
155
|
+
}, {
|
|
156
|
+
readonly id: "T3";
|
|
157
|
+
readonly tier: "shell";
|
|
158
|
+
readonly from: "3.8.0";
|
|
159
|
+
readonly kind: "rendered";
|
|
160
|
+
readonly summary: "A licence line renders wherever licensed work is advertised, with the licensee where it differs.";
|
|
161
|
+
}, {
|
|
162
|
+
readonly id: "T4";
|
|
163
|
+
readonly tier: "shell";
|
|
164
|
+
readonly from: "3.8.0";
|
|
165
|
+
readonly kind: "rendered";
|
|
166
|
+
readonly summary: "No hard-coded rating or review numbers; proof claims resolve to renderable evidence.";
|
|
167
|
+
}, {
|
|
168
|
+
readonly id: "T11";
|
|
169
|
+
readonly tier: "shell";
|
|
170
|
+
readonly from: "3.8.0";
|
|
171
|
+
readonly kind: "static";
|
|
172
|
+
readonly summary: "No page for work over $5,000 outside the licence classes held; licence conditions carried.";
|
|
173
|
+
}, {
|
|
174
|
+
readonly id: "X1";
|
|
175
|
+
readonly tier: "shell";
|
|
176
|
+
readonly from: "3.8.0";
|
|
177
|
+
readonly kind: "record";
|
|
178
|
+
readonly summary: "Legacy URLs answer 200 or one redirect hop; earning-URL depth, titles and dollar figures kept.";
|
|
179
|
+
}, {
|
|
180
|
+
readonly id: "B1";
|
|
181
|
+
readonly tier: "shell";
|
|
182
|
+
readonly from: "3.8.0";
|
|
183
|
+
readonly kind: "rendered";
|
|
184
|
+
readonly summary: "Lab budgets: JavaScript, third-party requests, hero image and HTML within budget; no unrecorded chat widget, pixel, heatmap or tag manager.";
|
|
185
|
+
}, {
|
|
186
|
+
readonly id: "L10-hero";
|
|
187
|
+
readonly tier: "shell";
|
|
188
|
+
readonly from: "3.8.0";
|
|
189
|
+
readonly kind: "rendered";
|
|
190
|
+
readonly summary: "No kilometre figures, \"km from\" or \"based in\" in hero copy.";
|
|
191
|
+
}, {
|
|
192
|
+
readonly id: "C1";
|
|
193
|
+
readonly tier: "enquiry";
|
|
194
|
+
readonly from: "3.8.0";
|
|
195
|
+
readonly kind: "journey";
|
|
196
|
+
readonly summary: "Money pages: the form in the first section; at 390 x 844 the H1, a call and a quote action in the first viewport; at 1440 x 900 the form.";
|
|
197
|
+
}, {
|
|
198
|
+
readonly id: "C2";
|
|
199
|
+
readonly tier: "enquiry";
|
|
200
|
+
readonly from: "3.8.0";
|
|
201
|
+
readonly kind: "rendered";
|
|
202
|
+
readonly summary: "Form layout and labels; phone and email required; no helper or reassurance lines, no \"(required)\", no job select.";
|
|
203
|
+
}, {
|
|
204
|
+
readonly id: "E9";
|
|
205
|
+
readonly tier: "enquiry";
|
|
206
|
+
readonly from: "3.8.0";
|
|
207
|
+
readonly kind: "rendered";
|
|
208
|
+
readonly summary: "Every cost guide carries at least 8 dollar figures in a renderable price state.";
|
|
209
|
+
}, {
|
|
210
|
+
readonly id: "T5";
|
|
211
|
+
readonly tier: "enquiry";
|
|
212
|
+
readonly from: "3.8.0";
|
|
213
|
+
readonly kind: "rendered";
|
|
214
|
+
readonly summary: "Reviews from the feed, with Google's rating, count and link beside any selection; none on the contact page; no empty reviews section.";
|
|
215
|
+
}, {
|
|
216
|
+
readonly id: "K8";
|
|
217
|
+
readonly tier: "enquiry";
|
|
218
|
+
readonly from: "3.8.0";
|
|
219
|
+
readonly kind: "rendered";
|
|
220
|
+
readonly summary: "Section contract: no empty section, one H2 each, at most one band tone, neighbours differ, proof within the first five sections.";
|
|
221
|
+
}, {
|
|
222
|
+
readonly id: "C7";
|
|
223
|
+
readonly tier: "enquiry";
|
|
224
|
+
readonly from: "3.10.0";
|
|
225
|
+
readonly kind: "rendered";
|
|
226
|
+
readonly summary: "Thank-you page: a reply time, a tel: link and noindex, follow.";
|
|
227
|
+
}, {
|
|
228
|
+
readonly id: "C8";
|
|
229
|
+
readonly tier: "enquiry";
|
|
230
|
+
readonly from: "3.10.0";
|
|
231
|
+
readonly kind: "rendered";
|
|
232
|
+
readonly summary: "Forgiving form: tolerant phone input (13, 1300 and 1800 too), autocomplete tokens, no capture on the photo input.";
|
|
233
|
+
}, {
|
|
234
|
+
readonly id: "C11";
|
|
235
|
+
readonly tier: "enquiry";
|
|
236
|
+
readonly from: "3.10.0";
|
|
237
|
+
readonly kind: "static";
|
|
238
|
+
readonly summary: "The test marker is stripped before delivery and reporting; /api/contact is rate-limited.";
|
|
239
|
+
}, {
|
|
240
|
+
readonly id: "N9";
|
|
241
|
+
readonly tier: "enquiry";
|
|
242
|
+
readonly from: "3.11.0";
|
|
243
|
+
readonly kind: "rendered";
|
|
244
|
+
readonly summary: "Footer content: column 1 brand, licences, socials and contact; services, areas and company columns; © name, ABN and legal links; no CTA, \"based in\", hours or guides column.";
|
|
245
|
+
}, {
|
|
246
|
+
readonly id: "K2";
|
|
247
|
+
readonly tier: "enquiry";
|
|
248
|
+
readonly from: "3.11.0";
|
|
249
|
+
readonly kind: "rendered";
|
|
250
|
+
readonly summary: "Every rendered shared component has a skin entry; no reference-skin class ships.";
|
|
251
|
+
}, {
|
|
252
|
+
readonly id: "K11";
|
|
253
|
+
readonly tier: "enquiry";
|
|
254
|
+
readonly from: "3.11.0";
|
|
255
|
+
readonly kind: "rendered";
|
|
256
|
+
readonly summary: "Density: no section with more than one H2, more than 8 cards or more than 2 calls to action; measure and section padding within limits.";
|
|
257
|
+
}, {
|
|
258
|
+
readonly id: "K12-contact";
|
|
259
|
+
readonly tier: "enquiry";
|
|
260
|
+
readonly from: "3.11.0";
|
|
261
|
+
readonly kind: "rendered";
|
|
262
|
+
readonly summary: "The contact page is the page header, then the contact block, and nothing else.";
|
|
263
|
+
}, {
|
|
264
|
+
readonly id: "T6";
|
|
265
|
+
readonly tier: "enquiry";
|
|
266
|
+
readonly from: "3.11.0";
|
|
267
|
+
readonly kind: "static";
|
|
268
|
+
readonly summary: "Every image has a media.ts entry with provenance.";
|
|
269
|
+
}, {
|
|
270
|
+
readonly id: "T7";
|
|
271
|
+
readonly tier: "enquiry";
|
|
272
|
+
readonly from: "3.11.0";
|
|
273
|
+
readonly kind: "rendered";
|
|
274
|
+
readonly summary: "No image is the main image of two pages.";
|
|
275
|
+
}, {
|
|
276
|
+
readonly id: "T8";
|
|
277
|
+
readonly tier: "enquiry";
|
|
278
|
+
readonly from: "3.11.0";
|
|
279
|
+
readonly kind: "rendered";
|
|
280
|
+
readonly summary: "Prices: GST flag set; no \"+ GST\" or \"from $X\" teasers on cards and menus; one band per job site-wide.";
|
|
281
|
+
}, {
|
|
282
|
+
readonly id: "T9";
|
|
283
|
+
readonly tier: "enquiry";
|
|
284
|
+
readonly from: "3.11.0";
|
|
285
|
+
readonly kind: "static";
|
|
286
|
+
readonly summary: "No image in /public carries location metadata.";
|
|
287
|
+
}, {
|
|
288
|
+
readonly id: "K12";
|
|
289
|
+
readonly tier: "full";
|
|
290
|
+
readonly from: "3.12.0";
|
|
291
|
+
readonly kind: "rendered";
|
|
292
|
+
readonly summary: "Section manifest: every required section rendered or skipped with a data-backed reason; conditional sections render when their data exists; canonical or recorded order.";
|
|
293
|
+
}, {
|
|
294
|
+
readonly id: "E5";
|
|
295
|
+
readonly tier: "full";
|
|
296
|
+
readonly from: "3.12.0";
|
|
297
|
+
readonly kind: "static";
|
|
298
|
+
readonly summary: "No orphan indexable pages, from the route catalogue and link data.";
|
|
299
|
+
}, {
|
|
300
|
+
readonly id: "E10";
|
|
301
|
+
readonly tier: "full";
|
|
302
|
+
readonly from: "3.12.0";
|
|
303
|
+
readonly kind: "static";
|
|
304
|
+
readonly summary: "Phrase-owner uniqueness in strategy data; no service-in-suburb page for the suburb page phrase; no service-region hub for the main trade.";
|
|
305
|
+
}, {
|
|
306
|
+
readonly id: "L3";
|
|
307
|
+
readonly tier: "full";
|
|
308
|
+
readonly from: "3.12.0";
|
|
309
|
+
readonly kind: "static";
|
|
310
|
+
readonly summary: "Neighbours by real distance.";
|
|
311
|
+
}, {
|
|
312
|
+
readonly id: "L4";
|
|
313
|
+
readonly tier: "full";
|
|
314
|
+
readonly from: "3.12.0";
|
|
315
|
+
readonly kind: "rendered";
|
|
316
|
+
readonly summary: "No copy rotated by page address, no name-swapped FAQs, no other suburb's job without the nearby label.";
|
|
317
|
+
}, {
|
|
318
|
+
readonly id: "L6";
|
|
319
|
+
readonly tier: "full";
|
|
320
|
+
readonly from: "3.12.0";
|
|
321
|
+
readonly kind: "static";
|
|
322
|
+
readonly summary: "Location pages have 6 or more inbound links from 3 or more page types.";
|
|
323
|
+
}, {
|
|
324
|
+
readonly id: "L7";
|
|
325
|
+
readonly tier: "full";
|
|
326
|
+
readonly from: "3.12.0";
|
|
327
|
+
readonly kind: "static";
|
|
328
|
+
readonly summary: "Location pages are 3 clicks or fewer from home.";
|
|
329
|
+
}, {
|
|
330
|
+
readonly id: "L8";
|
|
331
|
+
readonly tier: "full";
|
|
332
|
+
readonly from: "3.12.0";
|
|
333
|
+
readonly kind: "static";
|
|
334
|
+
readonly summary: "A hub per family per region.";
|
|
335
|
+
}, {
|
|
336
|
+
readonly id: "L9";
|
|
337
|
+
readonly tier: "full";
|
|
338
|
+
readonly from: "3.12.0";
|
|
339
|
+
readonly kind: "rendered";
|
|
340
|
+
readonly summary: "Data contract on service-location pages: price or cost-guide link, reviews or fallback, local facts; the nearby job card or none.";
|
|
341
|
+
}, {
|
|
342
|
+
readonly id: "L10";
|
|
343
|
+
readonly tier: "full";
|
|
344
|
+
readonly from: "3.12.0";
|
|
345
|
+
readonly kind: "rendered";
|
|
346
|
+
readonly summary: "No kilometre figures, \"km from\", \"based in\" or year stamps as local detail in location copy.";
|
|
347
|
+
}, {
|
|
348
|
+
readonly id: "S4";
|
|
349
|
+
readonly tier: "full";
|
|
350
|
+
readonly from: "3.12.0";
|
|
351
|
+
readonly kind: "static";
|
|
352
|
+
readonly summary: "No hand-written per-service or per-suburb files; no dynamic route with zero pages.";
|
|
353
|
+
}, {
|
|
354
|
+
readonly id: "LOC-INDEX";
|
|
355
|
+
readonly tier: "full";
|
|
356
|
+
readonly from: "3.12.0";
|
|
357
|
+
readonly kind: "static";
|
|
358
|
+
readonly summary: "No location route is noindex or left out of the sitemap unless the recorded wave schedule dates it (Romie's 20 Oct decision: every suburb page stays indexed).";
|
|
359
|
+
}, {
|
|
360
|
+
readonly id: "D4";
|
|
361
|
+
readonly tier: "new-build";
|
|
362
|
+
readonly from: "3.8.0";
|
|
363
|
+
readonly kind: "static";
|
|
364
|
+
readonly summary: "Same-trade distinctness: at least four of seven look levers differ from every listed competitor (advisory in 3.8.0, blocking from 3.9.0).";
|
|
365
|
+
}];
|
|
366
|
+
export type SiteSystemCheckId = (typeof SITE_SYSTEM_CHECKS)[number]["id"];
|
|
367
|
+
/** A release as one comparable number: "3.8.0" < "3.10.0". */
|
|
368
|
+
export declare function siteSystemReleaseRank(version: string): number;
|
|
369
|
+
/**
|
|
370
|
+
* Whether a check blocks for a site at `tier` on `release`. Checks of higher tiers, and checks newer than the
|
|
371
|
+
* installed release, report without blocking. D4 blocks new builds and redesigns from 3.9.0 whatever their tier.
|
|
372
|
+
*/
|
|
373
|
+
export declare function siteSystemCheckBlocks(check: Pick<SiteSystemCheck, "id" | "tier" | "from">, site: {
|
|
374
|
+
tier: SiteSystemTier;
|
|
375
|
+
release: string;
|
|
376
|
+
newBuild?: boolean;
|
|
377
|
+
}): boolean;
|
|
378
|
+
/** One result of one check, from any runner. `brandlab-ready` merges them into the ready report. */
|
|
379
|
+
export interface SiteSystemFinding {
|
|
380
|
+
readonly checkId: SiteSystemCheckId;
|
|
381
|
+
readonly status: "pass" | "fail" | "not-applicable";
|
|
382
|
+
/** The page path or file the result is about, when it is about one. */
|
|
383
|
+
readonly target?: string;
|
|
384
|
+
/** One plain sentence: what passed or what is wrong and where. */
|
|
385
|
+
readonly message: string;
|
|
386
|
+
/** A warning never blocks: the check still passes and the report shows "pass (warning)". */
|
|
387
|
+
readonly severity?: "warning";
|
|
388
|
+
}
|
|
389
|
+
//# sourceMappingURL=checks.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"checks.d.ts","sourceRoot":"","sources":["../../src/site-system/checks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,eAAO,MAAM,iBAAiB,uCAAwC,CAAC;AACvE,MAAM,MAAM,cAAc,GAAG,CAAC,OAAO,iBAAiB,CAAC,CAAC,MAAM,CAAC,CAAC;AAEhE,kFAAkF;AAClF,MAAM,MAAM,oBAAoB,GAAG,cAAc,GAAG,WAAW,CAAC;AAEhE,MAAM,MAAM,mBAAmB,GAAG,SAAS,GAAG,UAAU,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAE/E,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,IAAI,EAAE,oBAAoB,CAAC;IACpC,+DAA+D;IAC/D,QAAQ,CAAC,IAAI,EAAE,KAAK,MAAM,IAAI,CAAC;IAC/B,QAAQ,CAAC,IAAI,EAAE,mBAAmB,CAAC;IACnC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAgEgB,CAAC;AAEhD,MAAM,MAAM,iBAAiB,GAAG,CAAC,OAAO,kBAAkB,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC;AAI1E,8DAA8D;AAC9D,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAG7D;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,IAAI,CAAC,eAAe,EAAE,IAAI,GAAG,MAAM,GAAG,MAAM,CAAC,EACpD,IAAI,EAAE;IAAE,IAAI,EAAE,cAAc,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;CAAE,GAClE,OAAO,CAIT;AAED,oGAAoG;AACpG,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,OAAO,EAAE,iBAAiB,CAAC;IACpC,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,gBAAgB,CAAC;IACpD,uEAAuE;IACvE,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,kEAAkE;IAClE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,4FAA4F;IAC5F,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS,CAAC;CAC/B"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Site System v2 ready gate: every check, the adoption tier it blocks at and the release that brings it.
|
|
3
|
+
*
|
|
4
|
+
* A site declares `siteSystem: { tier }` in brandlab.config.ts. Checks of that tier and the tiers below it block;
|
|
5
|
+
* checks of higher tiers report without blocking. A check blocks only from the release named here, so new checks
|
|
6
|
+
* arrive with version bumps and never turn the fleet red at once. Holdouts use the project's Romie-owned
|
|
7
|
+
* `exceptions` record. D6 (leave reviews as they are) removes every review-exclusion clause; D7 (no call tracking)
|
|
8
|
+
* means no number-swap check.
|
|
9
|
+
*
|
|
10
|
+
* `kind` says where a check runs:
|
|
11
|
+
* - `journey`: the Playwright site-system journeys (`defineBrandlabSiteSystemTests`), in the site's e2e run;
|
|
12
|
+
* - `rendered`: rules over the built site's server HTML and assets (`brandlab-ready` reads them);
|
|
13
|
+
* - `static`: source and data rules (`brandlab-verify` and `brandlab-ready`);
|
|
14
|
+
* - `record`: launch-day and human steps recorded with `brandlab-ready record <id> --evidence <ref>`.
|
|
15
|
+
*/
|
|
16
|
+
export const SITE_SYSTEM_TIERS = ["shell", "enquiry", "full"];
|
|
17
|
+
export const SITE_SYSTEM_CHECKS = [
|
|
18
|
+
// shell: header, nav, call bar, placements, crawlable links, contrast and targets, call links, budgets, legal
|
|
19
|
+
{ id: "N1", tier: "shell", from: "3.9.0", kind: "rendered", summary: "Required nav links, About in the first two, services before Areas, Contact last, labels from the closed list, recorded orders kept." },
|
|
20
|
+
{ id: "N2", tier: "shell", from: "3.8.0", kind: "rendered", summary: "Every dropdown link and hub link is an <a href> in the server HTML." },
|
|
21
|
+
{ id: "N3", tier: "shell", from: "3.8.0", kind: "journey", summary: "Hover opens after a short delay and a diagonal path stays open; mouse-out closes; nothing sticks open." },
|
|
22
|
+
{ id: "N4", tier: "shell", from: "3.8.0", kind: "journey", summary: "A chevron click after hover keeps the panel open; a link click closes it; click, Enter and outside click work." },
|
|
23
|
+
{ id: "N5", tier: "shell", from: "3.8.0", kind: "journey", summary: "Keyboard and ARIA: aria-expanded follows the panel, Arrow keys move, Escape closes and returns focus; axe passes open and closed." },
|
|
24
|
+
{ id: "N6", tier: "shell", from: "3.8.0", kind: "journey", summary: "The header stays at the top with the phone and quote visible at every desktop width; the compact band shows them from 1024 to 1279 px." },
|
|
25
|
+
{ id: "N8", tier: "shell", from: "3.9.0", kind: "journey", summary: "The drawer is a modal dialog that traps focus and resets; the call bar uses placement fab; back-to-top appears (from 3.11.0)." },
|
|
26
|
+
{ id: "K1", tier: "shell", from: "3.9.0", kind: "rendered", summary: "Shared components in use for the parts the tier covers (data-bl present); no literal tel: outside PhoneLink." },
|
|
27
|
+
{ id: "K3", tier: "shell", from: "3.8.0", kind: "journey", summary: "Text contrast 4.5:1 and non-text 3:1 in the browser." },
|
|
28
|
+
{ id: "K4", tier: "shell", from: "3.8.0", kind: "journey", summary: "Targets at least 24 px, and 44 px for primary actions (call, quote, menu)." },
|
|
29
|
+
{ id: "K5", tier: "shell", from: "3.8.0", kind: "journey", summary: "Focus is never fully hidden by the sticky header or call bar at 390 px, in Chromium and WebKit." },
|
|
30
|
+
{ id: "K6", tier: "shell", from: "3.8.0", kind: "journey", summary: "Phone and quote in the same relative order on every page, in the header, hero and call bar." },
|
|
31
|
+
{ id: "K7", tier: "shell", from: "3.8.0", kind: "rendered", summary: "Dropdown links, accordion and tab panels and full review text are in the server HTML." },
|
|
32
|
+
{ id: "K10", tier: "shell", from: "3.8.0", kind: "record", summary: "Adoption parity in the lenient harness: no section, link or text lost against the baseline." },
|
|
33
|
+
{ id: "C4", tier: "shell", from: "3.8.0", kind: "journey", summary: "Phone taps report an allowed placement (header, footer, hero, cta, fab, contact, location, page)." },
|
|
34
|
+
{ id: "C5", tier: "shell", from: "3.8.0", kind: "rendered", summary: "Call-to-action labels come from the closed list or a recorded label." },
|
|
35
|
+
{ id: "C9", tier: "shell", from: "3.8.0", kind: "rendered", summary: "No interstitial overlay in the first screen." },
|
|
36
|
+
{ id: "C10", tier: "shell", from: "3.8.0", kind: "rendered", summary: "Every tel: href is E.164 (national digits for 13, 1300 and 1800) and matches the evidence-file phone." },
|
|
37
|
+
{ id: "E1", tier: "shell", from: "3.8.0", kind: "static", summary: "Title patterns on new or changed URLs; recorded titles unchanged." },
|
|
38
|
+
{ id: "E2", tier: "shell", from: "3.8.0", kind: "rendered", summary: "Exactly one H1 on every page, rendered once." },
|
|
39
|
+
{ id: "E8", tier: "shell", from: "3.8.0", kind: "rendered", summary: "No banned phrase from any of the three layers, environmental claims included." },
|
|
40
|
+
{ id: "T3", tier: "shell", from: "3.8.0", kind: "rendered", summary: "A licence line renders wherever licensed work is advertised, with the licensee where it differs." },
|
|
41
|
+
{ id: "T4", tier: "shell", from: "3.8.0", kind: "rendered", summary: "No hard-coded rating or review numbers; proof claims resolve to renderable evidence." },
|
|
42
|
+
{ id: "T11", tier: "shell", from: "3.8.0", kind: "static", summary: "No page for work over $5,000 outside the licence classes held; licence conditions carried." },
|
|
43
|
+
{ id: "X1", tier: "shell", from: "3.8.0", kind: "record", summary: "Legacy URLs answer 200 or one redirect hop; earning-URL depth, titles and dollar figures kept." },
|
|
44
|
+
{ id: "B1", tier: "shell", from: "3.8.0", kind: "rendered", summary: "Lab budgets: JavaScript, third-party requests, hero image and HTML within budget; no unrecorded chat widget, pixel, heatmap or tag manager." },
|
|
45
|
+
{ id: "L10-hero", tier: "shell", from: "3.8.0", kind: "rendered", summary: 'No kilometre figures, "km from" or "based in" in hero copy.' },
|
|
46
|
+
// enquiry: the form, thank-you page, reviews, proof strip, footer, CTA band, contact page, prices, media, density
|
|
47
|
+
{ id: "C1", tier: "enquiry", from: "3.8.0", kind: "journey", summary: "Money pages: the form in the first section; at 390 x 844 the H1, a call and a quote action in the first viewport; at 1440 x 900 the form." },
|
|
48
|
+
{ id: "C2", tier: "enquiry", from: "3.8.0", kind: "rendered", summary: 'Form layout and labels; phone and email required; no helper or reassurance lines, no "(required)", no job select.' },
|
|
49
|
+
{ id: "E9", tier: "enquiry", from: "3.8.0", kind: "rendered", summary: "Every cost guide carries at least 8 dollar figures in a renderable price state." },
|
|
50
|
+
{ id: "T5", tier: "enquiry", from: "3.8.0", kind: "rendered", summary: "Reviews from the feed, with Google's rating, count and link beside any selection; none on the contact page; no empty reviews section." },
|
|
51
|
+
{ id: "K8", tier: "enquiry", from: "3.8.0", kind: "rendered", summary: "Section contract: no empty section, one H2 each, at most one band tone, neighbours differ, proof within the first five sections." },
|
|
52
|
+
{ id: "C7", tier: "enquiry", from: "3.10.0", kind: "rendered", summary: "Thank-you page: a reply time, a tel: link and noindex, follow." },
|
|
53
|
+
{ id: "C8", tier: "enquiry", from: "3.10.0", kind: "rendered", summary: "Forgiving form: tolerant phone input (13, 1300 and 1800 too), autocomplete tokens, no capture on the photo input." },
|
|
54
|
+
{ id: "C11", tier: "enquiry", from: "3.10.0", kind: "static", summary: "The test marker is stripped before delivery and reporting; /api/contact is rate-limited." },
|
|
55
|
+
{ id: "N9", tier: "enquiry", from: "3.11.0", kind: "rendered", summary: 'Footer content: column 1 brand, licences, socials and contact; services, areas and company columns; © name, ABN and legal links; no CTA, "based in", hours or guides column.' },
|
|
56
|
+
{ id: "K2", tier: "enquiry", from: "3.11.0", kind: "rendered", summary: "Every rendered shared component has a skin entry; no reference-skin class ships." },
|
|
57
|
+
{ id: "K11", tier: "enquiry", from: "3.11.0", kind: "rendered", summary: "Density: no section with more than one H2, more than 8 cards or more than 2 calls to action; measure and section padding within limits." },
|
|
58
|
+
{ id: "K12-contact", tier: "enquiry", from: "3.11.0", kind: "rendered", summary: "The contact page is the page header, then the contact block, and nothing else." },
|
|
59
|
+
{ id: "T6", tier: "enquiry", from: "3.11.0", kind: "static", summary: "Every image has a media.ts entry with provenance." },
|
|
60
|
+
{ id: "T7", tier: "enquiry", from: "3.11.0", kind: "rendered", summary: "No image is the main image of two pages." },
|
|
61
|
+
{ id: "T8", tier: "enquiry", from: "3.11.0", kind: "rendered", summary: 'Prices: GST flag set; no "+ GST" or "from $X" teasers on cards and menus; one band per job site-wide.' },
|
|
62
|
+
{ id: "T9", tier: "enquiry", from: "3.11.0", kind: "static", summary: "No image in /public carries location metadata." },
|
|
63
|
+
// full: page families, location estates, section manifests, links and the data contract
|
|
64
|
+
{ id: "K12", tier: "full", from: "3.12.0", kind: "rendered", summary: "Section manifest: every required section rendered or skipped with a data-backed reason; conditional sections render when their data exists; canonical or recorded order." },
|
|
65
|
+
{ id: "E5", tier: "full", from: "3.12.0", kind: "static", summary: "No orphan indexable pages, from the route catalogue and link data." },
|
|
66
|
+
{ id: "E10", tier: "full", from: "3.12.0", kind: "static", summary: "Phrase-owner uniqueness in strategy data; no service-in-suburb page for the suburb page phrase; no service-region hub for the main trade." },
|
|
67
|
+
{ id: "L3", tier: "full", from: "3.12.0", kind: "static", summary: "Neighbours by real distance." },
|
|
68
|
+
{ id: "L4", tier: "full", from: "3.12.0", kind: "rendered", summary: "No copy rotated by page address, no name-swapped FAQs, no other suburb's job without the nearby label." },
|
|
69
|
+
{ id: "L6", tier: "full", from: "3.12.0", kind: "static", summary: "Location pages have 6 or more inbound links from 3 or more page types." },
|
|
70
|
+
{ id: "L7", tier: "full", from: "3.12.0", kind: "static", summary: "Location pages are 3 clicks or fewer from home." },
|
|
71
|
+
{ id: "L8", tier: "full", from: "3.12.0", kind: "static", summary: "A hub per family per region." },
|
|
72
|
+
{ id: "L9", tier: "full", from: "3.12.0", kind: "rendered", summary: "Data contract on service-location pages: price or cost-guide link, reviews or fallback, local facts; the nearby job card or none." },
|
|
73
|
+
{ id: "L10", tier: "full", from: "3.12.0", kind: "rendered", summary: 'No kilometre figures, "km from", "based in" or year stamps as local detail in location copy.' },
|
|
74
|
+
{ id: "S4", tier: "full", from: "3.12.0", kind: "static", summary: "No hand-written per-service or per-suburb files; no dynamic route with zero pages." },
|
|
75
|
+
{ id: "LOC-INDEX", tier: "full", from: "3.12.0", kind: "static", summary: "No location route is noindex or left out of the sitemap unless the recorded wave schedule dates it (Romie's 20 Oct decision: every suburb page stays indexed)." },
|
|
76
|
+
// new builds and redesigns
|
|
77
|
+
{ id: "D4", tier: "new-build", from: "3.8.0", kind: "static", summary: "Same-trade distinctness: at least four of seven look levers differ from every listed competitor (advisory in 3.8.0, blocking from 3.9.0)." },
|
|
78
|
+
];
|
|
79
|
+
const TIER_RANK = { shell: 0, enquiry: 1, full: 2 };
|
|
80
|
+
/** A release as one comparable number: "3.8.0" < "3.10.0". */
|
|
81
|
+
export function siteSystemReleaseRank(version) {
|
|
82
|
+
const [major = 0, minor = 0, patch = 0] = version.split(/[.-]/).map((part) => Number.parseInt(part, 10) || 0);
|
|
83
|
+
return major * 1_000_000 + minor * 1_000 + patch;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Whether a check blocks for a site at `tier` on `release`. Checks of higher tiers, and checks newer than the
|
|
87
|
+
* installed release, report without blocking. D4 blocks new builds and redesigns from 3.9.0 whatever their tier.
|
|
88
|
+
*/
|
|
89
|
+
export function siteSystemCheckBlocks(check, site) {
|
|
90
|
+
if (check.tier === "new-build")
|
|
91
|
+
return site.newBuild === true && siteSystemReleaseRank(site.release) >= siteSystemReleaseRank("3.9.0");
|
|
92
|
+
if (siteSystemReleaseRank(site.release) < siteSystemReleaseRank(check.from))
|
|
93
|
+
return false;
|
|
94
|
+
return TIER_RANK[check.tier] <= TIER_RANK[site.tier];
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=checks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"checks.js","sourceRoot":"","sources":["../../src/site-system/checks.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The Site System v2 ready gate: every check, the adoption tier it blocks at and the release that brings it.\n *\n * A site declares `siteSystem: { tier }` in brandlab.config.ts. Checks of that tier and the tiers below it block;\n * checks of higher tiers report without blocking. A check blocks only from the release named here, so new checks\n * arrive with version bumps and never turn the fleet red at once. Holdouts use the project's Romie-owned\n * `exceptions` record. D6 (leave reviews as they are) removes every review-exclusion clause; D7 (no call tracking)\n * means no number-swap check.\n *\n * `kind` says where a check runs:\n * - `journey`: the Playwright site-system journeys (`defineBrandlabSiteSystemTests`), in the site's e2e run;\n * - `rendered`: rules over the built site's server HTML and assets (`brandlab-ready` reads them);\n * - `static`: source and data rules (`brandlab-verify` and `brandlab-ready`);\n * - `record`: launch-day and human steps recorded with `brandlab-ready record <id> --evidence <ref>`.\n */\n\nexport const SITE_SYSTEM_TIERS = [\"shell\", \"enquiry\", \"full\"] as const;\nexport type SiteSystemTier = (typeof SITE_SYSTEM_TIERS)[number];\n\n/** The design check D4 blocks every new build and redesign, whatever its tier. */\nexport type SiteSystemCheckScope = SiteSystemTier | \"new-build\";\n\nexport type SiteSystemCheckKind = \"journey\" | \"rendered\" | \"static\" | \"record\";\n\nexport interface SiteSystemCheck {\n readonly id: string;\n readonly tier: SiteSystemCheckScope;\n /** The first release in which the check blocks at its tier. */\n readonly from: `3.${number}.0`;\n readonly kind: SiteSystemCheckKind;\n readonly summary: string;\n}\n\nexport const SITE_SYSTEM_CHECKS = [\n // shell: header, nav, call bar, placements, crawlable links, contrast and targets, call links, budgets, legal\n { id: \"N1\", tier: \"shell\", from: \"3.9.0\", kind: \"rendered\", summary: \"Required nav links, About in the first two, services before Areas, Contact last, labels from the closed list, recorded orders kept.\" },\n { id: \"N2\", tier: \"shell\", from: \"3.8.0\", kind: \"rendered\", summary: \"Every dropdown link and hub link is an <a href> in the server HTML.\" },\n { id: \"N3\", tier: \"shell\", from: \"3.8.0\", kind: \"journey\", summary: \"Hover opens after a short delay and a diagonal path stays open; mouse-out closes; nothing sticks open.\" },\n { id: \"N4\", tier: \"shell\", from: \"3.8.0\", kind: \"journey\", summary: \"A chevron click after hover keeps the panel open; a link click closes it; click, Enter and outside click work.\" },\n { id: \"N5\", tier: \"shell\", from: \"3.8.0\", kind: \"journey\", summary: \"Keyboard and ARIA: aria-expanded follows the panel, Arrow keys move, Escape closes and returns focus; axe passes open and closed.\" },\n { id: \"N6\", tier: \"shell\", from: \"3.8.0\", kind: \"journey\", summary: \"The header stays at the top with the phone and quote visible at every desktop width; the compact band shows them from 1024 to 1279 px.\" },\n { id: \"N8\", tier: \"shell\", from: \"3.9.0\", kind: \"journey\", summary: \"The drawer is a modal dialog that traps focus and resets; the call bar uses placement fab; back-to-top appears (from 3.11.0).\" },\n { id: \"K1\", tier: \"shell\", from: \"3.9.0\", kind: \"rendered\", summary: \"Shared components in use for the parts the tier covers (data-bl present); no literal tel: outside PhoneLink.\" },\n { id: \"K3\", tier: \"shell\", from: \"3.8.0\", kind: \"journey\", summary: \"Text contrast 4.5:1 and non-text 3:1 in the browser.\" },\n { id: \"K4\", tier: \"shell\", from: \"3.8.0\", kind: \"journey\", summary: \"Targets at least 24 px, and 44 px for primary actions (call, quote, menu).\" },\n { id: \"K5\", tier: \"shell\", from: \"3.8.0\", kind: \"journey\", summary: \"Focus is never fully hidden by the sticky header or call bar at 390 px, in Chromium and WebKit.\" },\n { id: \"K6\", tier: \"shell\", from: \"3.8.0\", kind: \"journey\", summary: \"Phone and quote in the same relative order on every page, in the header, hero and call bar.\" },\n { id: \"K7\", tier: \"shell\", from: \"3.8.0\", kind: \"rendered\", summary: \"Dropdown links, accordion and tab panels and full review text are in the server HTML.\" },\n { id: \"K10\", tier: \"shell\", from: \"3.8.0\", kind: \"record\", summary: \"Adoption parity in the lenient harness: no section, link or text lost against the baseline.\" },\n { id: \"C4\", tier: \"shell\", from: \"3.8.0\", kind: \"journey\", summary: \"Phone taps report an allowed placement (header, footer, hero, cta, fab, contact, location, page).\" },\n { id: \"C5\", tier: \"shell\", from: \"3.8.0\", kind: \"rendered\", summary: \"Call-to-action labels come from the closed list or a recorded label.\" },\n { id: \"C9\", tier: \"shell\", from: \"3.8.0\", kind: \"rendered\", summary: \"No interstitial overlay in the first screen.\" },\n { id: \"C10\", tier: \"shell\", from: \"3.8.0\", kind: \"rendered\", summary: \"Every tel: href is E.164 (national digits for 13, 1300 and 1800) and matches the evidence-file phone.\" },\n { id: \"E1\", tier: \"shell\", from: \"3.8.0\", kind: \"static\", summary: \"Title patterns on new or changed URLs; recorded titles unchanged.\" },\n { id: \"E2\", tier: \"shell\", from: \"3.8.0\", kind: \"rendered\", summary: \"Exactly one H1 on every page, rendered once.\" },\n { id: \"E8\", tier: \"shell\", from: \"3.8.0\", kind: \"rendered\", summary: \"No banned phrase from any of the three layers, environmental claims included.\" },\n { id: \"T3\", tier: \"shell\", from: \"3.8.0\", kind: \"rendered\", summary: \"A licence line renders wherever licensed work is advertised, with the licensee where it differs.\" },\n { id: \"T4\", tier: \"shell\", from: \"3.8.0\", kind: \"rendered\", summary: \"No hard-coded rating or review numbers; proof claims resolve to renderable evidence.\" },\n { id: \"T11\", tier: \"shell\", from: \"3.8.0\", kind: \"static\", summary: \"No page for work over $5,000 outside the licence classes held; licence conditions carried.\" },\n { id: \"X1\", tier: \"shell\", from: \"3.8.0\", kind: \"record\", summary: \"Legacy URLs answer 200 or one redirect hop; earning-URL depth, titles and dollar figures kept.\" },\n { id: \"B1\", tier: \"shell\", from: \"3.8.0\", kind: \"rendered\", summary: \"Lab budgets: JavaScript, third-party requests, hero image and HTML within budget; no unrecorded chat widget, pixel, heatmap or tag manager.\" },\n { id: \"L10-hero\", tier: \"shell\", from: \"3.8.0\", kind: \"rendered\", summary: 'No kilometre figures, \"km from\" or \"based in\" in hero copy.' },\n\n // enquiry: the form, thank-you page, reviews, proof strip, footer, CTA band, contact page, prices, media, density\n { id: \"C1\", tier: \"enquiry\", from: \"3.8.0\", kind: \"journey\", summary: \"Money pages: the form in the first section; at 390 x 844 the H1, a call and a quote action in the first viewport; at 1440 x 900 the form.\" },\n { id: \"C2\", tier: \"enquiry\", from: \"3.8.0\", kind: \"rendered\", summary: 'Form layout and labels; phone and email required; no helper or reassurance lines, no \"(required)\", no job select.' },\n { id: \"E9\", tier: \"enquiry\", from: \"3.8.0\", kind: \"rendered\", summary: \"Every cost guide carries at least 8 dollar figures in a renderable price state.\" },\n { id: \"T5\", tier: \"enquiry\", from: \"3.8.0\", kind: \"rendered\", summary: \"Reviews from the feed, with Google's rating, count and link beside any selection; none on the contact page; no empty reviews section.\" },\n { id: \"K8\", tier: \"enquiry\", from: \"3.8.0\", kind: \"rendered\", summary: \"Section contract: no empty section, one H2 each, at most one band tone, neighbours differ, proof within the first five sections.\" },\n { id: \"C7\", tier: \"enquiry\", from: \"3.10.0\", kind: \"rendered\", summary: \"Thank-you page: a reply time, a tel: link and noindex, follow.\" },\n { id: \"C8\", tier: \"enquiry\", from: \"3.10.0\", kind: \"rendered\", summary: \"Forgiving form: tolerant phone input (13, 1300 and 1800 too), autocomplete tokens, no capture on the photo input.\" },\n { id: \"C11\", tier: \"enquiry\", from: \"3.10.0\", kind: \"static\", summary: \"The test marker is stripped before delivery and reporting; /api/contact is rate-limited.\" },\n { id: \"N9\", tier: \"enquiry\", from: \"3.11.0\", kind: \"rendered\", summary: 'Footer content: column 1 brand, licences, socials and contact; services, areas and company columns; © name, ABN and legal links; no CTA, \"based in\", hours or guides column.' },\n { id: \"K2\", tier: \"enquiry\", from: \"3.11.0\", kind: \"rendered\", summary: \"Every rendered shared component has a skin entry; no reference-skin class ships.\" },\n { id: \"K11\", tier: \"enquiry\", from: \"3.11.0\", kind: \"rendered\", summary: \"Density: no section with more than one H2, more than 8 cards or more than 2 calls to action; measure and section padding within limits.\" },\n { id: \"K12-contact\", tier: \"enquiry\", from: \"3.11.0\", kind: \"rendered\", summary: \"The contact page is the page header, then the contact block, and nothing else.\" },\n { id: \"T6\", tier: \"enquiry\", from: \"3.11.0\", kind: \"static\", summary: \"Every image has a media.ts entry with provenance.\" },\n { id: \"T7\", tier: \"enquiry\", from: \"3.11.0\", kind: \"rendered\", summary: \"No image is the main image of two pages.\" },\n { id: \"T8\", tier: \"enquiry\", from: \"3.11.0\", kind: \"rendered\", summary: 'Prices: GST flag set; no \"+ GST\" or \"from $X\" teasers on cards and menus; one band per job site-wide.' },\n { id: \"T9\", tier: \"enquiry\", from: \"3.11.0\", kind: \"static\", summary: \"No image in /public carries location metadata.\" },\n\n // full: page families, location estates, section manifests, links and the data contract\n { id: \"K12\", tier: \"full\", from: \"3.12.0\", kind: \"rendered\", summary: \"Section manifest: every required section rendered or skipped with a data-backed reason; conditional sections render when their data exists; canonical or recorded order.\" },\n { id: \"E5\", tier: \"full\", from: \"3.12.0\", kind: \"static\", summary: \"No orphan indexable pages, from the route catalogue and link data.\" },\n { id: \"E10\", tier: \"full\", from: \"3.12.0\", kind: \"static\", summary: \"Phrase-owner uniqueness in strategy data; no service-in-suburb page for the suburb page phrase; no service-region hub for the main trade.\" },\n { id: \"L3\", tier: \"full\", from: \"3.12.0\", kind: \"static\", summary: \"Neighbours by real distance.\" },\n { id: \"L4\", tier: \"full\", from: \"3.12.0\", kind: \"rendered\", summary: \"No copy rotated by page address, no name-swapped FAQs, no other suburb's job without the nearby label.\" },\n { id: \"L6\", tier: \"full\", from: \"3.12.0\", kind: \"static\", summary: \"Location pages have 6 or more inbound links from 3 or more page types.\" },\n { id: \"L7\", tier: \"full\", from: \"3.12.0\", kind: \"static\", summary: \"Location pages are 3 clicks or fewer from home.\" },\n { id: \"L8\", tier: \"full\", from: \"3.12.0\", kind: \"static\", summary: \"A hub per family per region.\" },\n { id: \"L9\", tier: \"full\", from: \"3.12.0\", kind: \"rendered\", summary: \"Data contract on service-location pages: price or cost-guide link, reviews or fallback, local facts; the nearby job card or none.\" },\n { id: \"L10\", tier: \"full\", from: \"3.12.0\", kind: \"rendered\", summary: 'No kilometre figures, \"km from\", \"based in\" or year stamps as local detail in location copy.' },\n { id: \"S4\", tier: \"full\", from: \"3.12.0\", kind: \"static\", summary: \"No hand-written per-service or per-suburb files; no dynamic route with zero pages.\" },\n { id: \"LOC-INDEX\", tier: \"full\", from: \"3.12.0\", kind: \"static\", summary: \"No location route is noindex or left out of the sitemap unless the recorded wave schedule dates it (Romie's 20 Oct decision: every suburb page stays indexed).\" },\n\n // new builds and redesigns\n { id: \"D4\", tier: \"new-build\", from: \"3.8.0\", kind: \"static\", summary: \"Same-trade distinctness: at least four of seven look levers differ from every listed competitor (advisory in 3.8.0, blocking from 3.9.0).\" },\n] as const satisfies readonly SiteSystemCheck[];\n\nexport type SiteSystemCheckId = (typeof SITE_SYSTEM_CHECKS)[number][\"id\"];\n\nconst TIER_RANK: Record<SiteSystemTier, number> = { shell: 0, enquiry: 1, full: 2 };\n\n/** A release as one comparable number: \"3.8.0\" < \"3.10.0\". */\nexport function siteSystemReleaseRank(version: string): number {\n const [major = 0, minor = 0, patch = 0] = version.split(/[.-]/).map((part) => Number.parseInt(part, 10) || 0);\n return major * 1_000_000 + minor * 1_000 + patch;\n}\n\n/**\n * Whether a check blocks for a site at `tier` on `release`. Checks of higher tiers, and checks newer than the\n * installed release, report without blocking. D4 blocks new builds and redesigns from 3.9.0 whatever their tier.\n */\nexport function siteSystemCheckBlocks(\n check: Pick<SiteSystemCheck, \"id\" | \"tier\" | \"from\">,\n site: { tier: SiteSystemTier; release: string; newBuild?: boolean },\n): boolean {\n if (check.tier === \"new-build\") return site.newBuild === true && siteSystemReleaseRank(site.release) >= siteSystemReleaseRank(\"3.9.0\");\n if (siteSystemReleaseRank(site.release) < siteSystemReleaseRank(check.from)) return false;\n return TIER_RANK[check.tier] <= TIER_RANK[site.tier];\n}\n\n/** One result of one check, from any runner. `brandlab-ready` merges them into the ready report. */\nexport interface SiteSystemFinding {\n readonly checkId: SiteSystemCheckId;\n readonly status: \"pass\" | \"fail\" | \"not-applicable\";\n /** The page path or file the result is about, when it is about one. */\n readonly target?: string;\n /** One plain sentence: what passed or what is wrong and where. */\n readonly message: string;\n /** A warning never blocks: the check still passes and the report shows \"pass (warning)\". */\n readonly severity?: \"warning\";\n}\n"]}
|