@brandlab-digital/conformance

中文文档
4.2.2发布于 2026/11/06UNLICENSEDTypeScriptES Module近 30 天下载 8035

Proprietary software © Brandlab Digital Marketing. All rights reserved. Published for Brandlab client sites.

原始使用文档
文档目录5 节
  1. Service-area maps (from 3.6.0)
  2. Site System ready gate (from 3.8.0)
  3. Release and CI tools (4.2.0)
  4. Contact journeys
  5. Cost guards (from 3.13.0)

@brandlab-digital/conformance

Proprietary software © Brandlab Digital Marketing. All rights reserved. Published for Brandlab client sites.

Service-area maps (from 3.6.0)

  • brandlab-area-map places --out src/data/locations/siteOwnedBoundaries.json Young@2594 Cowra Cootamundra writes a site's own towns (outside the Sydney and Central Coast registries) and the land around them in the shared area-map format, from the NSW Spatial Services suburb layer (name, and postcode where it repeats; registry places are refused). Options: --margin-km (land around the towns, default 15) and --tolerance (metres, default 20).
  • The estate journey fails a service-area map (<figure data-area-map>) without a caption carrying the CC BY boundary credit, with a link that is a tab stop or does not go to an indexable catalogue page, with more than areaMapMaxBytes inline (default 60 000), or whose <use> base-layer file does not answer 200 as image/svg+xml with the groups it uses.

Site System ready gate (from 3.8.0)

A site adopts Site System v2 by declaring siteSystem: { tier: 'shell' | 'enquiry' | 'full' } in brandlab.config.ts (newBuild: true for new builds and redesigns; samples adds pages to check; labels, freeQuotes, thirdParties and phones record the quote labels, free-quote offer, third-party hosts and extra tel: links the shell rules accept; refreshExceptions lists estate families allowed to refresh more often than every 7 days, each { family, revalidateSeconds, reason, decisionId }, for W3 from 3.13.0; replyTime records a decision to promise no reply time on the thank-you page, for C7 from 3.15.0, below). Without it, nothing in the gate blocks.

C7, the thank-you page (enquiry tier): every sampled thank-you page (a /thank-you-style path or the library's ThankYou block) is noindex, follow, has a tel: link in the block (or <main>) and says in its reply slot (data-slot="reply") when the business will reply, as a specific time ("within the hour", "within one to two business days"; C7_REPLY_TIME). Vague words such as "shortly" or "as soon as we can" fail. When the owner decides to promise no time, the site records it (3.15.0):

siteSystem: {
  tier: 'enquiry',
  replyTime: { promise: false, wording: 'We will call you back as soon as possible.', decidedBy: 'owner', decidedOn: '2026-10-24' },
},

C7 then accepts that wording in the reply slot instead of a time (compared ignoring case, spacing and punctuation), fails a page without it or one that still promises a time, and names the recorded decision in its pass message. The wording may not contain a time itself (digits, minutes, hours, "same day", "next day", a business or working day, "today", "tomorrow"); decidedBy is owner or romie (for the owner) and decidedOn a real date. { promise: true } or no record keeps the specific-time rule. Noindex, the call link and everything else C7 checks are unchanged.

  • brandlab-ready (after next build and the site-system journeys) writes docs/ready/ready-report.md and .json: every check with its tier, whether it blocks for this site, its status (pass, fail, not run, excepted, n/a; a pass may carry warnings, which never block) and what was found. Checks of the declared tier and the tiers below it block from the release that brings them; a blocking check that failed or did not run exits 1, and so does a missing home or contact page, a --base-url sample that does not answer with HTML, or a brandlab.config.ts the gate cannot read in full. Higher tiers and later releases report only. It reads the Playwright JSON report (--playwright-report, default test-results/site-system.json; test titles start with the check id, [N3] …), runs the rule modules over sample pages (home, contact, the representative routes, one page per other built route and samples) read from the build or fetched with --base-url, merges --findings <file> results for K10 and X1 (the lenient harness) and the brandlab-verify search, contact and analytics families, and honours the project's exceptions (ruleId is the check id; expired exceptions do not count).

  • The journeys come from tests/e2e/site-system.spec.ts, run with the JSON reporter into test-results/site-system.json:

    import { defineBrandlabSiteSystemTests } from '@brandlab-digital/conformance/site-system-e2e'
    
    defineBrandlabSiteSystemTests({
      tier: 'full', // the tier brandlab.config.ts declares
      pages: {
        home: '/',
        money: ['/services/blocked-drains'], // C1, from the enquiry tier: service pages with the enquiry form
        contact: '/contact',
        families: ['/locations/ryde', '/blog/blocked-drain-cost-sydney'], // W9, full tier: one built page per dynamic route family
      },
    })
    

    A journey registers from the release that brings it (W2 and W9 from 3.13.0). The release is the site's installed Brandlab release, read from package.json as brandlab-ready reads it, a canary included (3.15.0: before it the journeys used the conformance package's last published release, so a canary ran none of its newer journeys while the gate blocked on them). Leave release out; set it only to preview a later release's journeys. When the report has journey results but none for a blocking journey check, the gate says which tier, pages and release it needs.

  • brandlab-ready record <id> --evidence <where the proof is> [--note <text>] records a launch-day step (T2, T3-R, C6, X3 to X10) or a recorded check (K10, X1) in docs/ready/launch.json, or a human step (truth-pass, trust-carry-over, usefulness-read, codex-second-opinion, launch-proof, look-pick) in docs/ready/human.json. brandlab-ready --launch also fails until every step is recorded.

  • Rule modules export a SiteSystemRenderedRunner from @brandlab-digital/conformance/site-system and are listed in SITE_SYSTEM_RENDERED_RUNNERS.

  • W2 (shell tier, from 3.13.0) runs inside the site-system journeys on each sampled page at 390 x 844 and 1440 x 900: at most 8 prefetched pages on landing and 12 after a full scroll; none from footer, header panel, drawer, area (coverage), nearby (nearby-areas), map (area-map, data-area-map), finder or other-services links (a site marks its own lists with data-bl-links="area|nearby|map|finder|other-services"), none through a hidden link and never the current page. Compressed prefetch bytes above twice the page's own HTML add a warning.

  • brandlab-prefetch-probe <url> [--viewport 390x844 ...] [--json] [--strict] measures one page locally (a local build, a preview or a live page) in headless Chromium: the pages prefetched on landing and after a full scroll at each viewport, their compressed and decoded bytes, the edge cache result and the W2 result. No request leaves for another site, and it never crawls.

Release and CI tools (4.2.0)

  • brandlab-preview-enquiry <preview-url> [--changed-from origin/main] [--path /contact] [--field key=value]... sends one marked test enquiry (bl_test=1) through a pull request's Preview when the change touches contact or runtime files (package files, next.config, vercel.json, the proxy or instrumentation, api/contact, contact config and forms); otherwise it sends nothing. It first posts an empty marked request, which the route rejects without sending, and goes on only when the answer carries x-brandlab-contact-mode: preview; test-inbox=brandlab (site-next 4.2.0+ on a Preview), so it can never reach a client's inbox. The enquiry uses ordinary wording that must pass the spam filter, with [email protected] as its email. From 4.2.2 it fills the site's own form: it reads the Preview's contact page (--path, default /contact), gives the usual fields test values, any other required field a plain value and a required select one of its own options, keeps hidden values, leaves honeypots empty and sends no field the form lacks (the route refuses unknown fields). --field key=value sets one of the form's own fields; a name the form does not have is refused. A page without the form in its HTML is refused before anything is sent. A protected Preview needs VERCEL_AUTOMATION_BYPASS_SECRET in the environment. Then confirm the email arrived.
  • brandlab-live-check <https://www.site> --service /path --location /path [--css token]... [--vercel-project name --vercel-scope team] is the check after a release goes live: home, the top service page, one location page and contact answer 200, sitemap.xml and robots.txt 200, a made-up URL 404, each --css class or token is in the stylesheets home links, and (with the Vercel CLI signed in) the production deployment, the rollback deployment (vercel rollback <id>), its runtime errors and any 5xx from /api/contact since --since (30m). Requests are one at a time, at least 0.5 s apart, and stop at the first 403. It never runs page JavaScript, so no GA4 session.
  • @brandlab-digital/conformance/playwright exports a Playwright test whose browser context blocks Google Analytics, Tag Manager and Ads requests in every test, expect, blockAnalytics(contextOrPage) for one-off scripts and isAnalyticsUrl. Use it for any site-owned spec or script that loads a page, above all a live one; the shared journeys already fail closed for every other host.
  • BRANDLAB_ESTATE_SCOPE=changed (set by CI v2 through brandlab-estate-scope on a ready-for-review pull request whose files stay inside page families) crawls the hubs, the first and last route of each kind, every route of a changed family, the routes changed content and data files feed and 20 fixed-seed routes; the family journeys open only the changed families and home. Shared changes keep the full crawl, which also runs on the merge to main.

Contact journeys

defineBrandlabContactTests and the contact journey of defineBrandlabAnalyticsTests expect an accepted enquiry to land on /thank-you. A form that confirms on its own page passes successPath (a path or a RegExp), for example successPath: '/contact'. Both block every request that leaves the site, Google's tag included. A site that takes over scrolling (GSAP ScrollSmoother, Lenis) can move the form after Playwright scrolls to the submit button; run the journeys at a width where the site scrolls natively: test.use({ viewport: { width: 390, height: 844 } }).

Cost guards (from 3.13.0)

  • W5 (static, shell): vercel.json regions equal brandlab.config.ts hosting.originRegion (Sydney, syd1, when there is no hosting block). Any other region needs an origin-region-v1 decision whose reviewBy is at most six months after decidedOn; the check fails once reviewBy passes (Sydney time). The engineering check vercel-region (brandlab-verify --engineering, inside every site's npm run verify) applies the same rule except the date: a lapsed reviewBy never stops a build, a fix or a rollback.
  • W10 (rendered, shell): the built robots.txt (or the running site's, with --base-url; a Preview that answers noindex, or a build made for a Preview whose robots.txt disallows everything, is not judged) lets every search and answer crawler (site-core BRANDLAB_SEARCH_CRAWLERS) fetch home and the representative routes, and gives none of them a Crawl-delay. Firewall rules that match on the user agent (vercel.json routes with mitigate, and hosting.firewall) must not deny or challenge them; a rate limit on one is a warning.
  • W9 (journey, full): defineBrandlabSiteSystemTests({ pages: { families: [...] } }) names one built page per dynamic route family; an unknown slug answers the shared 404, the uppercase slug answers it too or redirects once (301 or 308) to its exact lowercase form, and ?utm_source=x serves the same cacheable page as the clean URL. W9-params (static, full): no page under a dynamic route reads searchParams.
  • K12-slots (rendered, full, from 3.14.0): the lines a trade requires inside a section (site-core SECTION_TRADE_PROFILES, for the trade defineSectionOrder names): for trees, the council permit note in LocalFacts on suburb and service-in-suburb pages and the qualifications and insurance lines on the about page. The section carries data-bl-slot="<slot>", or lists <slot>:no-… in data-bl-slot-skip (a warning, so the record is re-checked). The skip is read only from the top-level section element (the outermost data-bl-section): a site element that wraps LocalFacts in its own section hides the skip, and the page fails as if no reason were given. Render LocalFacts itself as the sequenced section, not inside a wrapper. K13 (rendered, full, from 3.16.0): signature sections (data-bl-section="signature") carry a data-bl-signature name that their manifest lists, at most two on the home page, one on a service page and none elsewhere (site-core SIGNATURE_LIMITS), and the home page's are the ones strategy.ts records in look.homeSections.signatures, so D4 compares the real look (a recorded one the home page doesn't show is a warning). K12 leaves placed signatures out of its order walk and, from 3.16.0, warns when an optional or recommended section with data drops for the cap. E1-pattern (rendered, full, from 3.14.0): every location page outside docs/recorded-titles.json has the H1 "{Service} {Place}" (no "in", no "the") and a title that starts with it, at most 60 characters (site-core locationHeadingProblem). LOC-INDEX also reads estate in strategy.ts (3.14.0): every location page is indexed now or in a wave, a return wave's pages are in the build already, and a region page at a suburb's slug sends the suburb to "{slug}-suburb"; renamed slugs are read as their registry places.
  • Estate plan snapshot (3.15.0): the gate reads waves and estate from strategy.ts without running it. A site that computes them (from its location catalogue, as AA does) records them with writeEstatePlanSnapshot(siteStrategy, { projectRoot, sources? }) from @brandlab-digital/conformance/estate-snapshot, called from a site test so npm run verify keeps src/data/estate-plan.generated.json current (fail that test in CI when it reports changed; commit the file). The file is deterministic: waves in date order, every list sorted, no timestamp, and a hash of the files under sources (default src/data; tests and *.generated.json left out). LOC-INDEX (and L3, L6, L8, which read the same plan) use the snapshot when it is present, and LOC-INDEX fails it when it is stale: the hashed files changed since it was written, or the record is plain data and says something else. A literal record needs no snapshot.
  • Media snapshot (3.15.0): T6 reads src/data/media.ts the same way. A computed manifest (gallery entries spread in) is recorded with writeMediaSnapshot(media, { projectRoot, sources? }) from @brandlab-digital/conformance/media-snapshot into src/data/media.generated.json, kept current from a site test in the same way; T6 reads it, and fails it when stale. A computed manifest without a snapshot fails T6 with that instruction (before 3.15.0 it reported nothing, so the gate showed "No result").
  • brandlab-edge-probe [--json] <url>... (run locally as npm run probe:edge, at most 25 URLs) logs x-vercel-cache, age, x-vercel-id (edge and function region) and time to first byte for each page, its RSC payload and its _tree prefetch, and a GET to each origin's /api/contact (expected 405). It is the measuring stick of the origin-region benchmark (operations/shared-platform/ORIGIN_REGION.md).

版本与发布记录

@brandlab-digital/conformance 共发布 118 个版本,首次发布于 2026/05/26;过去 12 个月发布了 118 个版本。

版本发布日期距今
4.2.2latest2026/11/062 天前
4.2.12026/11/062 天前
4.2.02026/11/062 天前
4.1.02026/11/053 天前
4.0.02026/11/053 天前
3.20.02026/11/044 天前

其他发布通道:next → 1.0.0,maintenance-1-0 → 1.0.15,maintenance-3-4 → 3.4.1,maintenance-3-5 → 3.5.2,maintenance-3-3 → 3.3.6。

关于 @brandlab-digital/conformance 的常见问题

@brandlab-digital/conformance 是什么?

Proprietary software © Brandlab Digital Marketing. All rights reserved. Published for Brandlab client sites.

如何安装 @brandlab-digital/conformance?

在项目目录运行 npm install @brandlab-digital/conformance,或使用 pnpm add / yarn add / bun add。它还提供命令行工具 brandlab-ready、brandlab-verify、brandlab-area-map、brandlab-edge-probe、brandlab-live-check、brandlab-estate-scope、brandlab-prefetch-probe、brandlab-preview-enquiry,可以用 npx brandlab-ready 直接运行。

@brandlab-digital/conformance 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@brandlab-digital/conformance 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@brandlab-digital/conformance 可以商用吗?

@brandlab-digital/conformance 使用 UNLICENSED 许可。作者声明为 UNLICENSED,即不授予公开使用许可(与公共领域的 Unlicense 不同)。使用前需获得作者授权。以上为概括,不构成法律意见,请以许可原文为准。

@brandlab-digital/conformance 的下载量有多少?

根据 npm 官方下载统计,@brandlab-digital/conformance 在 2026/10/09 – 2026/11/07 这 30 天内被下载 8,035 次,日均约 268 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@brandlab-digital/conformance 还在维护吗?

最新版本 4.2.2 发布于 2026/11/06(2 天前);至今共发布 118 个版本,其中过去 12 个月发布了 118 个;首次发布于 2026/05/26。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。