Self-check
This site's own audit
We sell verifiable marketing, so this site is checked the way a customer's assets are checked, and the report is published whatever it says. Every result below names the method that produced it. Where a check was not run, it says so and claims nothing.
- Generated
- 2026-10-24 09:04:15 UTC
- Files scanned
- 170 under site/src and packages/core/src
- Checks run
- 20 pass · 0 fail
- Not run
- 7 of 27
The report is produced by scripts/self-check.mjs, a dependency-free Node script that reads this repository and writes src/data/proof.generated.json. The page you are reading renders that file and nothing else — no result on this page is typed by hand. The timestamp is passed into the script by its caller, so the check logic is a function of the repository contents alone. The generated report is excluded from its own source scan.
Checks that ran
Every check below is deterministic: the same repository produces the same verdict every time, with no model in the loop. Each states what its method can and cannot see, because a method that overstates its reach is how a vendor ends up under a twenty-year order.
SC-FONT-ORIGIN
No font is loaded from a third-party origin
DeterministicPassScanned 170 source files. No reference to a hosted font origin. Fonts are self-hosted through next/font, so no request leaves the origin to fetch type.
Method
Literal substring scan of every .ts/.tsx/.js/.jsx/.mjs/.css file under src/ and packages/core/src for fonts.googleapis.com, fonts.gstatic.com, use.typekit.net, fonts.bunny.net, and any CSS @import of an absolute http(s) URL.
SC-EXTERNAL-ORIGIN
No third-party script or stylesheet is loaded in the markup
DeterministicPassNo <script src> or <link href> pointing at an absolute or protocol-relative remote URL appears in the source.
Method
Regular-expression scan for <script> or <link> tags whose src/href begins with http:, https:, or //. This inspects authored source only; it does not observe what the deployed page actually requests at runtime.
SC-NO-RAW-IMG
Images go through next/image or inline SVG, never a raw <img>
DeterministicPassNo raw <img> element in src/ or packages/core/src. Every raster asset is rendered by next/image, which enforces explicit dimensions and prevents layout shift.
Method
Literal scan for the token "<img" in every scanned source file, skipping occurrences inside a regular-expression literal — the scanner detects <img> tags on other sites, and its detector is not a raw image here. A raw <img> written by a runtime string or third-party package would not be caught.
SC-SVG-LABEL
Every inline SVG is either named or explicitly hidden from assistive technology
DeterministicPassInspected 7 inline <svg> element(s). Each carries aria-hidden="true", or an aria-label / aria-labelledby / role, or a <title> child.
Method
Parses each <svg> opening tag from source and looks for aria-hidden="true", aria-label, aria-labelledby, role, or a <title> element within the following 800 characters. This is a source-level approximation of the rendered accessibility tree, not a rendered-DOM audit — a name supplied by a wrapper component would not be seen here.
SC-LINK-NAME
Every link carries an accessible name
DeterministicPassInspected 44 <a> and <Link> element(s) in source. Each has literal text, a JSX expression rendering its label, or an aria-label / aria-labelledby.
Method
Regular-expression match of paired <a>…</a> and <Link>…</Link> elements. Literal text, an aria-label/aria-labelledby attribute, or any JSX expression in the body counts as a name. This is deliberately an approximation: a link whose label comes from an expression is credited without evaluating that expression, and self-closing or dynamically composed links are not matched at all. It catches empty and icon-only links; it does not prove every rendered link is well named.
SC-CRAWLER-ALLOW
Answer-engine crawlers are not blocked by robots rules
DeterministicPasssrc/app/robots.ts contains no rule disallowing GPTBot, OAI-SearchBot, ChatGPT-User, PerplexityBot, ClaudeBot, Claude-User, Google-Extended, Applebot-Extended, CCBot, meta-externalagent.
Method
Read src/app/robots.ts and, for each of 10 named answer-engine user agents, inspected the 400 characters following its mention for a disallow of the site root. This checks the source of the robots response only. Whether the deployed origin, a CDN, or a WAF actually answers those agents is a live HTTP check and is not run here.
SC-CLAIM-PHRASE
No prohibited compliance claim is asserted anywhere in the source
DeterministicPassScanned 170 source files for 20 prohibited claim phrases. 22 occurrence(s) were found, all of them inside a disavowal or a quotation — this site names these phrases in order to refuse them. Zero occurrences assert the claim.
Method
Case-insensitive substring scan of every scanned source file for 20 prohibited claim phrases: "guaranteed", "guarantee compliance", "guarantees compliance", "fully compliant", "ada compliant", "ada-compliant", "wcag compliant", "wcag-compliant", "certified compliant", "certified accessible", "legally compliant", "ensures compliance", "ensures accessibility", "ensure compliance", "100% compliant", "100% accessible", "always compliant", "never fails", "risk-free", "risk free". Each hit is classified by the surrounding sentence: an occurrence within a negation or a quotation is recorded as disavowed, otherwise it is recorded as asserted and the check fails. The classifier is a heuristic, so every occurrence is listed in the evidence for human review. src/data/proof.generated.json is excluded from the corpus, since it is this report rather than authored copy. The list is not exhaustive of every possible overclaim; it is exhaustive of what this check scanned.
Occurrences recorded
- disavowed packages/core/src/data/checks.ts:16 — "guaranteed"
- disavowed packages/core/src/data/checks.ts:97 — "guaranteed"
- disavowed packages/core/src/data/checks.ts:603 — "guaranteed"
- disavowed packages/core/src/data/checks.ts:603 — "guaranteed"
- disavowed packages/core/src/data/checks.ts:681 — "guaranteed"
- disavowed src/app/legal/claims/page.tsx:20 — "guaranteed"
- disavowed src/app/legal/claims/page.tsx:115 — "guaranteed"
- disavowed src/app/legal/claims/page.tsx:119 — "guaranteed"
- disavowed src/app/legal/claims/page.tsx:120 — "fully compliant"
- disavowed src/app/legal/claims/page.tsx:119 — "ensures compliance"
- disavowed src/app/legal/claims/page.tsx:120 — "risk-free"
- disavowed src/app/legal/terms/page.tsx:45 — "guarantee compliance"
- disavowed src/app/pricing/page.tsx:114 — "guaranteed"
- disavowed src/app/r/[id]/[token]/page.tsx:71 — "never fails"
- disavowed src/components/Footer.tsx:78 — "guaranteed"
- disavowed src/components/site/NeverClaim.tsx:5 — "guaranteed"
- disavowed src/components/site/NeverClaim.tsx:4 — "ada compliant"
- disavowed src/components/site/NeverClaim.tsx:4 — "wcag compliant"
- disavowed src/lib/scan/phrases.ts:45 — "guaranteed"
- disavowed src/lib/scan/phrases.ts:45 — "guaranteed"
- disavowed src/lib/scan/phrases.ts:45 — "guaranteed"
- disavowed src/lib/scan/report.ts:38 — "guaranteed"
SC-PAGE-METADATA
Every route declares a title and description
DeterministicPassAll 15 route(s) resolve metadata: 14 export their own, 1 inherit it from a layout in the same directory (src/app/page.tsx).
Method
Enumerates every page.tsx under src/app and requires an exported `metadata` or `generateMetadata`, or the same in a layout file sitting in the same directory (Next.js resolves metadata down the segment tree, so a route directly under a layout inherits its title and description). The exported value is not evaluated, so an empty title would pass here.
SC-STATIC-RENDER
Every marketing route is statically rendered
DeterministicPassScanned 15 page routes. 13 are statically rendered and 2 are dynamic by design, each with its reason recorded, so every marketing page is served as a prebuilt document. This is the structural half of page experience — the half decidable without a browser.
Method
For each page.tsx under src/app, test for the four source-level opt-outs from static rendering: export const dynamic = 'force-dynamic', export const revalidate = 0, export const fetchCache = 'force-no-store', and any import from next/headers. This check says nothing about measured performance — field metrics are reported as not-run in src/data/proof.ts, because a 75th-percentile field metric cannot be read out of source.
Occurrences recorded
- dynamic by design: src/app/r/[id]/[token]/page.tsx — dynamic = 'force-dynamic' — Serves one practice their own report. It reads a stored row and verifies a signed token, neither of which exists at build time, and it must never be prebuilt or cached — the page is private to whoever holds the link.
- dynamic by design: src/app/r/[id]/[token]/page.tsx — next/headers (cookies/headers force dynamic) — Serves one practice their own report. It reads a stored row and verifies a signed token, neither of which exists at build time, and it must never be prebuilt or cached — the page is private to whoever holds the link.
SC-FUNNEL-ROUTES
Every funnel step resolves to a real route, and exactly one converts
DeterministicPassParsed 7 funnel steps from src/data/funnel.ts. Each href resolves to a page.tsx under src/app, and exactly one step (audit_request) is marked as a conversion.
Method
Parse id/href/isConversion triples out of src/data/funnel.ts, then for each href test that the corresponding page.tsx exists under src/app (with / mapping to app/page.tsx). Separately assert that exactly one step is marked isConversion. This checks the funnel definition against the route tree; it does not observe any analytics traffic.
SC-CORPUS-GATING
No legally-required rule that would gate is muted by a missing verbatim quote
DeterministicPass42 rules in the catalogue. 29 are legally required, of which 29 carry the source's own words and 0 do not. 4 advisory rules can never block, by tier. No rule that would otherwise gate is muted by a missing quote; 0 quoteless rule(s) could not gate anyway and are backlog.
Method
Imports the loaded corpus from packages/core/src/data/corpus.ts and calls gatingButForQuote from packages/core/src/corpus/loader.ts, which asks the loader's own canGate whether each rule refused to gate would gate with its quote on record, at the report's generated-at date. Any such rule fails the check. Quoteless legal rules that cannot gate for another reason (advisory, repealed, not yet in force) are listed as backlog, not failures. Nothing about gating is re-derived here.
SC-CHECK-STATUS
Every check's status agrees with whether its remedy instrument exists
DeterministicPass34 of 42 checks agree with the instrument table; 8 disagree and are pending owner copy review.
Method
Imports the catalogue through packages/core/src/data/corpus.ts and reads packages/core/src/data/instruments.json, one row per check naming the commit that shipped its remedy instrument or "not built", and what is still missing. A check should be `available` only when its row names a commit and lists nothing missing, and `in-build` otherwise; its statusLabel should start "In build" exactly when it is `in-build`. Disagreements the owner has yet to word are held in a pending list in this script. What this cannot see: whether a row is true. The rows are checked against git (instruments.test.ts) and by reading the code, not here.
Occurrences recorded
- pending owner copy review: MED-PHI-AUTH (says "In build · phase one", table says available)
- pending owner copy review: MED-PHI-FACE (says "In build · phase two", table says available)
- pending owner copy review: AD-RESULTS-DISCLAIMER (says "In build · phase two", table says available)
- pending owner copy review: KS-ADV-SUPERIORITY (says "In build · phase one", table says available)
- pending owner copy review: MED-PHI-FILENAME (says "In build · phase one", table says available)
- pending owner copy review: MSG-EMAIL-OPTOUT (says "In build · phase two", table says available)
- pending owner copy review: MSG-EMAIL-DISCLOSE (says "In build · phase two", table says available)
- pending owner copy review: CA-CALOPPA-POSTED (says "In build · phase one", table says available)
SC-CITATION-AUTHORITY
Every citation names its source document, or the rule says why it has none
DeterministicPass42 rules in the catalogue. 41 have registered source documents and were checked against them: 29 name the document by a provision number carried in its id, title or url, 3 cite the document by its own address, 1 cite several documents and name every one of them and nothing else, and 8 name the document only through the provision-numbering scheme it declares — WCAG 2.2 publishes every success criterion in one document, so 'Success Criterion 1.4.3' confirms the document and cannot confirm the criterion. 1 are declared, each with its own reason, to have no source document and were not compared; they are listed below. 0 failure(s): a citation naming no authority that identifies its document — the defect D-032 was written about — or a rule neither registered nor declared.
Method
Reads packages/core/src/data/checks.ts and packages/core/src/corpus/sources.ts as text; nothing is imported. Rule blocks are anchored on the slug line, and their number must equal the slugs the file declares, counted separately and more loosely, or this reports not-run. Every rule must be in exactly one of RULE_DOCUMENT, RULE_CITED_DOCUMENTS or NO_SOURCE_DOCUMENT; a rule in none, in two, with no citation, or declared with an empty reason fails, as does a declaration or cited-documents entry for a slug the catalogue does not have. Each citation is split on ";" into the authorities it names, and parenthesised subdivisions are dropped. For a RULE_DOCUMENT rule, some authority must be the registered document's url (ignoring scheme, case and trailing slash) or be identified by number — title, part, section, statute or RFC number — as a whole token in the document's id, title or url, allowing one level of coarsening so a section citation matches a document registered at part level (16 CFR §255.2 against 16 CFR Part 255) and no further. A document may instead declare sectionScheme, for a standard whose provisions have no address of their own; a citation in that scheme confirms the document only, and every such rule is listed rather than counted as fully checked. For a RULE_CITED_DOCUMENTS rule every authority must identify one of its documents by number and every document must be named. A NO_SOURCE_DOCUMENT rule is not compared; its reason is printed beside it. What this cannot see: whether every authority in a multi-authority citation governs the requirement — for a RULE_DOCUMENT rule this proves its one document is among the authorities named — or whether a registered document is still the current edition; per-finding citation (D-032) is not built.
Occurrences recorded
- document confirmed, provision number not checkable against its address: colour-contrast — 'Success Criterion 1.4.3' against wcag-22
- document confirmed, provision number not checkable against its address: images-have-alt-text — 'Success Criterion 1.1.1' against wcag-22
- document confirmed, provision number not checkable against its address: form-inputs-have-labels — 'Success Criterion 3.3.2' against wcag-22
- document confirmed, provision number not checkable against its address: links-say-where-they-go — 'Success Criterion 2.4.4' against wcag-22
- document confirmed, provision number not checkable against its address: page-has-a-title — 'Success Criterion 2.4.2' against wcag-22
- document confirmed, provision number not checkable against its address: page-declares-its-language — 'Success Criterion 3.1.1' against wcag-22
- document confirmed, provision number not checkable against its address: structure-is-programmatic — 'Success Criterion 1.3.1' against wcag-22
- document confirmed, provision number not checkable against its address: controls-expose-name-and-role — 'Success Criterion 4.1.2' against wcag-22
- declared to have no source document, so not compared: ai-crawler-access — 'Operator-published user-agent documentation'. Reason: The citation names a class of documents, not one: each answer-engine operator publishes its own user-agent list, and the rule checks every named agent. No statute or standard governs crawler access. Registering one operator page would not match the citation as written, and rewriting the citation to name each page is a corpus change for the owner.
SC-SCAN-COVERAGE
Every published rule is either detectable or declared unreachable
DeterministicPass42 rules published. 34 are reachable by a tier-one or tier-two scan and 34 have a detector (tier-one DETECTED_SLUGS plus what tier two — axe-core and CrUX — reaches). 8 are declared out of reach, each with a stated reason, and 0 are a known backlog with no instrument yet. 0 are unaccounted for — a rule in none of these is one a report will silently never mention.
Method
Read the slug list from packages/core/src/data/checks.ts, the DETECTED_SLUGS/NOT_SCANNABLE/TIER_TWO declarations in src/lib/scan/detectors.ts, and AXE_TO_RULE/CRUX_SLUGS from tier2/axe.ts and tier2/crux.ts, then assert every slug appears in one of them. Fails the build on any rule that is neither detected, excused, nor a stated backlog item, so a new rule cannot become an invisible gap by omission.
SC-COVERAGE-DERIVED
No rule is both implemented and declared unbuilt
DeterministicPass0 instrument(s) genuinely unbuilt; 8 rule(s) reached by tier two.
Method
Parses TIER_TWO from detectors.ts and AXE_TO_RULE from tier2/axe.ts and intersects them.
SC-RULE-CATEGORY
Every published rule carries a coverage category
DeterministicPass42 published rules, 42 carrying a category.
Method
Counts slug: and category: declarations in packages/core/src/data/checks.ts.
SC-READINESS-STATE-DETECTED
A market whose own state law no scan reaches is not ready
DeterministicPassNone scannable: "1 rule is tagged as Oregon law, but no scan reaches it, so a scan here checks none of Oregon's own law." None tagged: "No rule in the corpus is tagged as Oregon law; only rules tagged for no state reach it."
Method
Imports verdict() from src/lib/readiness/verdict.ts and runs it on a fixture Oregon market with one rule per category, each with a detector, plus one Oregon-tagged rule. With that rule detected the market must have no gap (the fixture is otherwise ready). With it declared not scannable, and again with no Oregon rule at all, the market must have exactly one gap naming Oregon, and the two gaps must be worded differently, so a reader can tell "none tagged" from "none scannable". Nothing about readiness is re-derived here.
SC-ONE-STATE-TABLE
One table of states, with the address pattern derived from it
DeterministicPassOne table, 8 states (KS, MO, TX, NY, FL, CA, WA, OR). No other scanned file declares a second; the address pattern's alternation is derived from this table, not written out; and src/lib/scan/scan.ts imports it. Adding a state is one edit and cannot half-land.
Method
Reads src/lib/scan/jurisdiction.ts as text and parses the STATE_BY_ABBR literal, then asserts three things: no other scanned file (src/ and packages/core/src) declares a second abbreviation-to-state-name table (the literal shape `XX: 'State Name'`); no state token from the table appears beside a `|` anywhere in src/lib/scan/jurisdiction.ts, so the address pattern's alternation is built from the table rather than spelled out; and src/lib/scan/scan.ts imports STATE_BY_ABBR from ./jurisdiction rather than keeping its own copy. Static text inspection only — nothing is evaluated, so this proves the tables cannot disagree, not that any particular state is present.
SC-CHECKED-DATES
No research date moves without an edit to the ledger
DeterministicPass42 research date(s) across 42 rules, every one matching the committed ledger. A date cannot move, appear or vanish without an edit to packages/core/src/data/checked-dates.json in the same commit.
Method
Reads packages/core/src/data/checks.ts as text, anchors on each slug line, and collects the `checked` dates that follow it up to the next slug. Compares that map against the committed ledger at packages/core/src/data/checked-dates.json, reporting dates that moved later, moved earlier, appeared or vanished. What this cannot see: whether any date is true. It proves only that a date cannot change silently — a forward move must be accompanied by an edit to the ledger, which is where a reviewer can ask whether the source was actually re-read. Truth of a quote against its source needs the network: that is checkProvenance in src/lib/acquisition/provenance.ts, run from scripts/provenance.ts, and it is not asserted here.
SC-DEPLOY-GUARD
The mechanism that reconciles main with what is served still exists
DeterministicPassAll six parts present. src/app/api/version/route.ts and portal/src/app/api/version/route.ts report the commit and refuse caching, the portal's middleware lets the checker reach its stamp without a session, scripts/deployed.ts checks both apps and imports the one shared comparator, src/lib/deploy/stamp.ts still fails on 'unknown', and .github/workflows/deployed.yml runs on a push to main and twice daily on a schedule. This says the guard exists, not that the deployment is current — for that, run scripts/deployed.ts.
Method
Reads src/app/api/version/route.ts, portal/src/app/api/version/route.ts, portal/src/middleware.ts, scripts/deployed.ts, src/lib/deploy/stamp.ts and .github/workflows/deployed.yml as text; nothing is imported or run. Asserts each app's stamp route returns VERCEL_GIT_COMMIT_SHA and that its cache-control header itself contains no-store, that the portal's isPublicRoute list names /api/version on an uncommented line, that scripts/deployed.ts checks https://app.governedmarketing.com as well as the site, that scripts/deployed.ts imports compare/isFailure from the shared module rather than carrying its own copy, that src/lib/deploy/stamp.ts still counts 'unknown' as a failure, and that the workflow triggers on a push to main and on a schedule and invokes scripts/deployed.ts. What this cannot see: whether the deployment is actually current, whether the workflow is enabled in GitHub's settings, or whether its last run passed. Those need the network — run scripts/deployed.ts.
What was not run
Not run means not run. It is never a quiet pass.
The checks listed here apply to this site and are not yet wired into the self-check. They need something static inspection of source cannot supply — a rendered page, a computed style, a request made from outside the origin — and they are pending the rule-pack engine that does that work. Until then they carry no verdict. A report that quietly omits what it did not examine is worse than no report, because it reads like coverage.
PX-CWV-FIELD
Not runCore Web Vitals, at the percentile the assessment actually uses
Not run, and it cannot be. web.dev states the target is "the 75th percentile of page loads, segmented across mobile and desktop devices" — a distribution across real users on real devices and networks. Source code contains no such distribution, and this site has no field data yet because it is not publicly reachable. Reporting a number here would be reporting a different metric under the same name.
Pending field data. Once the site is public and first-party analytics is collecting, this reports LCP, CLS and INP at the 75th percentile with the sample count, and says so when the sample is too small to mean anything. The structural half is covered today by SC-STATIC-RENDER.
PX-CWV-LAB
Not runA lab page-experience measurement, labelled as lab
Not run. A lab measurement needs a browser driving the rendered page, which static inspection of source cannot provide. It is also, by web.dev's own wording, "not a substitute for field measurement" — so it will be published as the lab signal it is and never as the assessed metric.
Pending the rule-pack engine, which drives a real browser. Will report the run conditions alongside the numbers, because a lab figure without its throttling profile is not reproducible.
A11Y-CONTRAST
Not runText meets minimum contrast against its background
Not run. Contrast is a property of computed styles against rendered backgrounds. Tailwind utility classes in source do not settle what colour pair a given text node ends up with, so no honest verdict can be read out of the source alone.
Pending the rule-pack engine, which measures the rendered page and reports the exact ratio and the failing pair.
A11Y-ALT
Not runImages carry alternative text
Not run as a rendered check. The self-check confirms that no raw HTML image element exists and that inline SVGs are named or hidden (SC-NO-RAW-IMG, SC-SVG-LABEL), which is adjacent evidence but not the same claim: it does not inspect the alt text of next/image instances or of anything composed at runtime.
Pending the rule-pack engine, which reads the rendered accessibility tree rather than the source.
GEO-CRAWLER
Not runAnswer-engine crawlers are not blocked at the origin
Not run against the live origin. The self-check reads robots source only (SC-CRAWLER-ALLOW). A host default, security plug-in, CDN rule, or WAF can return 403 to a named agent while robots says nothing about it, and that is the failure this check exists to catch.
Pending the rule-pack engine, which issues one request per named user agent from outside the origin and records the response code.
PROV-AI-MARK
Not runAI-generated content carries machine-readable marking
Not run. This site publishes no synthetic imagery, so there is nothing here to mark, and a check that has nothing to inspect must not be reported as a pass. If AI-generated media is published on this site later, this check becomes live and applicable.
Pending the generation pipeline, which applies the marking at production time and the engine which reads it back out of the asset.
AD-DISCLOSURE-POS
Not runDisclosures are placed where they will actually be read
Not run. Placement is a rendered-layout property at a given viewport width. Reading it out of JSX would mean guessing at layout, and a guess is not a verdict.
Pending the rule-pack engine, which evaluates proximity and prominence against the rendered page at several viewport widths.
How to reproduce this
Clone the repository and run pnpm self-check. The script takes an optional --generated-at timestamp and writes the same JSON this page renders. Pass --strict to make a failure exit non-zero.
What this page is not: a certificate. It is a dated record of a specific set of checks against a specific commit, at the deterministic tier, with the method for each one written down. That is the same thing we publish for a customer, and it is the most any honest report can be.