The Marketing Truth Guard Test: Making an Unsubstantiated Pricing Claim Mechanically Unsayable
We deleted ten unsubstantiated cadence claims from our marketing copy and shipped a CI test so they cannot return. Inside the marketing truth guard test.
Article highlights
- Estimated reading time: 14 minutes
- Published on: September 4, 2026
- Last updated: September 4, 2026
Article
Abstract. On 2026-08-06 we deleted ten strings from our own marketing surface because they stated an audit frequency the product does not run, and shipped a lint-class CI test in the same change so the wrong wording cannot return. This piece describes that test, the marketing truth guard test, and draws a line most governance write-ups blur: one bounded claim class is enforced mechanically by a failing CI job, while the general rule that copy and behaviour ship together remains a documented norm enforced by human review. Neither gates deployment. The scope, the deliberate exceptions, and the limits are all stated below.
The copy outran the product
A routine audit-frequency review, the kind of check meant to confirm marketing copy still matches product behaviour, found that our own plan copy stated audit cadences the underlying system does not run. Not a typo and not a stale screenshot: cadence words appeared across ten separate strings, on plan cards, the homepage, feature pages, the billing tab, and the machine-readable structured data. None matched how the audit engine actually schedules work.
The marketing truth guard test is a lint-class CI test that fails the build when a marketing page states an audit frequency the product does not run.
The thesis is narrow and worth stating up front. Customer-facing copy and the product behaviour it describes ship in the same release. For one specific claim class, stated audit frequency, that rule is no longer a habit we ask engineers to remember. It is a test that fails continuous integration when the claim and the behaviour diverge.
Method
- Data source. Every marketing view template in the repository, read directly rather than from memory or from a previous inventory.
- Sample. n=10 strings, the complete set of cadence claims found on the marketing surface, not a sample of a larger set.
- Date range. A freshness and page-budget decision recorded on 2026-08-05 changed how audits are scheduled; the copy review and deletion followed on 2026-08-06.
- Filters. A string qualified if it stated a frequency for the audit engine, in any phrasing, on any customer-facing surface including structured data.
- Classification. Each string was checked against the scheduler and marked true, false, or unverifiable. False strings were deleted rather than reworded; true ones were left in place.
- Exclusions. Frequency claims whose subject is a different process, such as verification re-checks and leaderboard updates, were out of scope by design and recorded with a reason.
- Tooling. The guard was written from the deleted strings themselves, so its fixtures are the copy that was actually wrong rather than invented examples.
Rather than take the original decision notes at face value, we re-checked each claim in this article against the repository and the live site before publishing it, and recorded what we observed.
We read the guard test end to end and counted its parts: three cadence words, three subject words, one literal phrase, ten fixture strings, and a documented exclusion list. We opened the commit that introduced the guard and listed its changed files; the pricing template, the plan-cards partial, the billing-tab partial, the structured-data partial and the test file all appear in that one commit, which is what "shipped together" means here. We opened the continuous integration workflow and read the command it runs: it invokes the full test suite, so the guard executes on every run rather than in a separate optional job. That is what makes "fails CI" a description rather than an aspiration.
Finally we fetched the live pricing page and searched its rendered HTML for the page-budget and freshness figures. There were no matches. The page returns the coverage ladder instead. Cadence words do still appear in the rendered page, but each one attaches to a different subject, credit grants that reset each billing month being the main case, and none states a frequency for the audit engine.
That last check changed a sentence in this piece. An earlier draft stated that the pricing page now displays the page budget and freshness window as numbers. The fetch returned no such text, so the sentence was wrong and was rewritten. Those numbers appear on in-app surfaces; public pages carry the coverage word, and the split is deliberate. An article about copy drifting from behaviour is a poor place to let copy drift from behaviour.
Three different things, kept apart
Three separate mechanisms touch claims about our product. Conflating them is the most common way a governance story gets overstated, so each is listed with its own trigger, failure mode, and scope.
Mechanism Trigger Failure mode Scope Marketing truth guard test Marketing view text matches a forbidden pattern Failing CI test job Marketing view directories only In-product review queue Content moves from draft to publication Publication held pending human approval Content routed through the content workflow Co-release rule A copy change describes new or changed behaviour A reviewer flags it in code review All customer-facing copy, unenforced by codeSource: TrustGrowth engineering practice as of 2026-08-06; scopes taken from the test file and the content workflow configuration.
The mechanical CI guard
The guard is a lint-class test, test/lint/marketing_truth_guard_test.rb, that runs against marketing view templates in the standard test job on every continuous integration run. It fails the build when a marketing view places a cadence word (daily, weekly, or monthly) next to one of three subject words (audit, monitoring, or refresh) in either order, or when a view contains the literal phrase "audit cadence." Its scope stops at the marketing view directories. It says nothing about billing logic, the scheduler, or any other claim class.
The in-product review queue
Separately, published content moves through a draft, package, and publication-approval flow, with mandatory human sign-off at medium and high claim risk. This is a workflow inside the product rather than a CI check, and it has no visibility into the marketing view templates the guard covers. We described a comparable detect, fix, and verify discipline applied to a technical defect in an agent found, fixed, and verified a real defect on our own site. The review queue is the content-side analogue, and a different mechanism from the guard.
The co-release rule
The broader rule, that copy describing a feature and the feature itself land in the same release, is documented governance rather than code. Reviewers cite it and apply it by hand in code review. It sits in the same family as the anti-slop doctrine wired into every Groundcrew skill: a written norm people and agents are expected to apply, but one no build step currently checks. The distinction between that rule and the mechanical guard is the point of this piece. One is enforced by a test, the other by review discipline.
What was deleted on 2026-08-06, and why deletion beat rewording
Ten strings came out of the marketing surface, each stating a cadence the audit engine does not run. They were spread wider than the pricing page.
Location Removed string Pro plan card "Daily audits" Pricing comparison table The "Audit cadence" row Homepage sections "Starter adds weekly monitoring and credit-powered research." JSON-LD on every marketing page "Weekly growth audits (80+ checks)" JSON-LD offer description "Starter tier — weekly monitoring, proof refreshes" Proof feature page "Weekly refreshes, so the public page tracks the work" Proof feature page (Pro) "Daily refreshes and uncapped score history" Audit scoring feature page "one site, audited monthly: every check" Onboarding upsell "Weekly proof refreshes" Pro billing tab "Daily audits, full research suite."Source: the REMOVED_COPY fixture in test/lint/marketing_truth_guard_test.rb, which records each deleted string with the template it came from.
That spread is the first lesson. Only five of the ten used the word "audit" at all; the other five said "monitoring" or "refreshes." A guard built around a single keyword would therefore have certified half of the incident as clean. The cadence field the pricing table read from was retired from the customer-facing plan catalogue in the same change.
The daily and weekly claims were wrong by a full factor rather than a rounding difference, and a "daily" claim describing a process that does not run on a daily loop cannot be softened into accuracy with a different adverb. The real mechanism is two numbers rather than one word: a page budget, meaning how many pages of a site are in scope, and a freshness window, meaning how many days before a page is revisited.
Either number alone is half an answer. A 7-day window over 50 pages was precisely the promise this work existed to stop making, and a large page budget on a zero-day window is a pile of pages nobody visits.
So the replacement is not one sentence but a deliberate split, and the split is the interesting part. Public marketing pages ladder the tiers by a coverage word derived from the page budget, using four rungs at 100, 500, and 2,500 pages and above. The two literal numbers appear instead on in-app surfaces such as the billing tab and onboarding, in the shape of "2,500 pages per site, re-audited every 7 days." The stated reasoning for that division is that numbers on an in-app surface describe what a customer already bought, whereas the same numbers on a pricing page promise what a prospect will get.
Two properties of that ladder are deliberate. It is derived from the page budget rather than hardcoded per plan name, so retuning a budget cannot leave a stale word behind. And it has no "full," "complete," or "total" rung, because every budget is a sample of a large site, and a word implying whole-site coverage would re-make the exact claim the change deleted.
The copy deletion and the guard that forbids the copy from returning shipped in the same commit. That ordering matters. The fix is not "we corrected the copy" but "we corrected the copy and made the wrong version mechanically unsayable."
Inside the guard
The guard checks three phrasing families rather than one word, for the reason the deletion table shows: a pattern keyed only to the literal token "audit" would have missed "monitoring" and "refresh," which account for five of the ten removed strings. The pattern crosses three cadence words against three subject words in both directions, so that "daily audits" and "audited monthly" both match, tolerates up to two words in between, and adds a standalone match for the literal phrase "audit cadence."
CADENCE_SUBJECT = "(?:audit(?:s|ed|ing)?|monitoring|refresh(?:es)?)"
CADENCE_WORD = "(?:daily|weekly|monthly)"
CADENCE_CLAIM_PATTERN = /
#{CADENCE_WORD}\s+(?:\w+\s+){0,2}?#{CADENCE_SUBJECT}\b
| \b#{CADENCE_SUBJECT}\s+(?:\w+\s+){0,2}?#{CADENCE_WORD}\b
| \baudit\s+cadence\b
/ix
def self.cadence_offenders_in(content, file_label)
# Strip ERB comments: the views explain WHY the old words are
# banned, and the explanation must be allowed to quote them.
body = content.gsub(/<%#.*?%>/m, "")
body.scan(CADENCE_CLAIM_PATTERN).map { |match| "#{file_label}: #{match.strip}" }
end
Two details there are load-bearing and neither is obvious. The fragments are plain strings rather than Regexp objects, because interpolating a Regexp into another pattern stamps its own flags in as (?-mix:...), which switches the outer case-insensitive flag off inside that fragment; this behaviour is documented in the Ruby 3.4 Regexp reference. The guard would then quietly stop matching "Daily audits" while still matching "daily audits." The second detail is that ERB comments are stripped before scanning, because the templates carry comments explaining which words are banned and why. A guard that read its own warning label as a violation would make the explanation unwritable.
Every string in the table above is checked into the test suite as a fixture, with an assertion that the guard fires on each one if it were reintroduced. The deleted copy is what proves the guard covers the class it claims to cover, because a guard with no fixture from the actual incident is a guard nobody has tested against the failure it was built for. A separate self-fire test plants a synthetic violation and asserts the guard still catches it on every run, since a pattern that has quietly stopped matching, through a refactor or a template rename, is otherwise indistinguishable from a clean tree.
Two of the ten strings lived in schema.org JSON-LD rendered on every marketing page, which is why the guard scans shared partials and not only pages marked as marketing. Structured data is parsed directly by search engines and AI systems, so a false claim there travels further than the same sentence in body copy while being invisible to anyone reading the page.
The deliberate exceptions
Several frequency claims on the site are true, and the guard's scope is written narrowly so they survive. The exclusions recorded in the test include a daily verification re-check, a daily leaderboard refresh, a daily re-score on the about page, and a monthly credit reset. Each is excluded because its subject is not the audit engine; they describe different processes with their own schedules. Each exclusion is recorded with a reason in the test itself rather than left as an implicit gap a future reader has to reverse-engineer.
This matters because a guard that forces every true frequency statement out of the copy trades one inaccuracy for another: an under-informative page that hides real, verifiable facts to avoid tripping a pattern match. The public proof pages depend on frequency disclosure being accurate where it does appear, so the guard forbids the false claim class without forbidding the true one.
The companion check: copy cannot cite dead routes
The same test file carries a second claim class. CI fails when a marketing view quotes an API path that no longer routes anywhere in the application. That check walks marketing view text for path-shaped strings and confirms each one still resolves against the current route table.
The principle is identical even though the subject differs: copy describing product surface area has to track the surface area that exists. A dead route in marketing copy and a false cadence claim are both instances of description drifting away from implementation, checked by the same file, using the same pattern of fixture plus self-fire test.
Limitations
Several boundaries are worth stating plainly, because the value of a guard like this depends on not overselling it.
None of the three mechanisms refuses or blocks a deployment. Deployment runs as a separate scheduled process. The guard's only consequence is a failing CI test run, which someone has to see and act on. That is a meaningfully weaker intervention than a deploy-time gate, and this piece does not claim otherwise.
The mechanical guard covers two claim classes, audit-frequency cadence and dead API routes, and nothing else. It is not a general-purpose fact-checker across marketing claims, and no such checker exists here. Claims about pricing, performance, or outcomes are unguarded by code and rely entirely on the review norm.
The guard is a text pattern, so it catches the phrasings it enumerates. A genuinely novel way of implying a cadence, for instance a graphic or a phrase using none of the three subject words, would pass. Coverage grows only when someone notices a miss and adds it, which is why the fixtures matter more than the pattern.
Finally, this piece describes a decision and its stated reasoning as of 2026-08-06. We have no data on how the pricing copy change performs commercially, and none is claimed here. This is consistent with a standing position on this site that proof systems need current-state truth before they become marketing assets.
Why this is worth writing down
The transferable idea is release engineering applied to marketing copy. Not "marketing accuracy" in general, but one bounded, testable claim class at a time, made mechanically unsayable rather than merely discouraged. The copy from the incident that motivated the guard is checked into the test suite, so the class stays covered as the surrounding templates change.
We have written before about what is public, what is verified, and what stays gated in our own practice, and this sits in that pattern: a specific, falsifiable artifact rather than a general assurance. The test file itself, its pattern, its ten fixtures, its recorded exceptions, and its self-fire check, is the object a reader can reason about directly, independent of anything we say about it here. Readers who want to inspect the surrounding tooling philosophy can see it in Groundcrew skills and developer tooling.
Frequently asked questions
What is the marketing truth guard test?
It is a CI test file, test/lint/marketing_truth_guard_test.rb, that scans marketing view templates for unsubstantiated audit-cadence claims (daily, weekly, or monthly next to audit, monitoring, or refresh in either order, or the literal phrase "audit cadence") and for citations of dead API routes, failing the build if either pattern matches.
Does the marketing truth guard test block deployment?
No. It fails a CI test job. Deployment is a separate scheduled process and is not gated by this or any of the three mechanisms described here.
Why was the pricing copy deleted instead of corrected?
Because the underlying mechanism is a page budget plus a freshness window rather than a calendar cadence, no single corrected adverb could describe it accurately. Public pages now ladder the tiers by a coverage word derived from the page budget, and the two literal numbers appear on in-app surfaces where they describe what a customer already bought.
Does this guard check all marketing claims for accuracy?
No. It covers exactly two claim classes, audit-frequency cadence claims and dead API route citations, and makes no broader claim about marketing accuracy across the site.
How is this different from the in-product content review queue?
The review queue is a workflow inside the product requiring human approval before publishing content at medium or high claim risk. The guard is a CI test over marketing view templates. They run on different content at different points in the pipeline, and neither substitutes for the other.
How many strings were removed?
Ten, across plan cards, the pricing comparison table, the homepage, two feature pages, onboarding, the billing tab, and two JSON-LD blocks. Five of the ten used the word "audit"; the rest said "monitoring" or "refreshes."
Key takeaways
- On 2026-08-06 a routine review found ten marketing strings stating audit cadences the product does not run, spread across plan cards, the homepage, feature pages, structured data, and the billing tab. Only five used the word "audit."
- The fix removed the cadence claim and stated the real mechanism instead: a page budget plus a freshness window, laddered as a coverage word on public pages and given as both numbers on in-app surfaces.
- The marketing truth guard test now matches three cadence words against three subject words in either direction, plus the literal phrase "audit cadence," with all ten removed strings checked in as fixtures.
- A self-fire test guards against the matcher itself silently breaking over time.
- The guard, the in-product review queue, and the co-release governance rule are three distinct mechanisms with different scopes, and none of them gates deployment.
Know your site's real SEO score
Free GSC-verified audit, E-E-A-T scoring, and AI-powered content strategy.
Get Started Free