Skip to content

fix(copy): truthful catalog figures and privacy/Honey wording (claim integrity) - #233

Open
BSalaeddin wants to merge 1 commit into
mainfrom
seo/claim-integrity
Open

BSalaeddin wants to merge 1 commit into
mainfrom
seo/claim-integrity

Conversation

@BSalaeddin

Copy link
Copy Markdown
Collaborator

Claim integrity — truthful catalog figures, privacy and Honey wording

Executes the claim inventory at C:\Users\alaed\Documents\Github\caramel-artifact\seo-2026-09-11\claim-inventory.md (109 claims: 66 TRUE / 13 FALSE / 9 STALE / 21 UNVERIFIABLE, live data pulled 2026-09-11 UTC). Fleet rule as in BioFlow #216: text-only, layout-preserving edits — no component restructuring, no new sections, no design changes, no new dependencies. Each edit is the smallest wording change that makes the sentence true; the FAQ data structure and the FAQPage JSON-LD generation are untouched (strings only, so visible text and JSON-LD stay verbatim-equal — pinned by tests/unit/faq-section.test.tsx).

The two catalog figures now used everywhere: 4,000+ stores (floor 4,314 /coupons/<store> URLs in the prod sitemap) and 100,000+ coupon codes (floor 107,827 = GET /api/coupons?limit=1total). Both rounded DOWN. The 2,954 auto-apply configs are never called "3,000+". /api/coupons/stats (11,328, a valid-only trust census) is never used as a catalog size.

Edits (app copy + metadata)

# File Old → New Inventory evidence
Q6 src/components/FaqSection.tsx "over 139,000 active coupon codes across more than 3,000 online stores" → "over 100,000 coupon codes across more than 4,000 online stores" (+ header comment now cites the 2026-09-11 sources) FALSE — 139,340 came from /api/coupons/stats on 2026-07-28 before the census became valid-only; live visible total 107,827 / 4,314 stores
Q3 src/components/FaqSection.tsx data answer: "…when you reach checkout on a supported store it fetches coupon codes for that store's domain…and reports whether a code worked…" → "…as you browse, it asks whether Caramel has codes for the current site's domain so the toolbar badge can show a count; when you reach checkout on a supported store it fetches those codes…and reports whether a code worked (linked to your account only if you're signed in)…" STALE (incomplete) — wxt.config.ts:83-85 badge sends every visited https domain on tab switch; background.js:84-86 bearer on every call; report/route.ts:142-143 stores userId
W1 src/components/WhyNot.tsx VIDEO_TITLE "The Truth About Honey" → "Exposing the Honey Influencer Scam" (aria-label "Play video: …") STALE — YouTube oembed title for vc4yL3YTwWk (MegaLag)
W2 src/components/WhyNot.tsx "Honey secretly replaces creators' affiliate links with their own, stealing commissions…" → "Honey was documented replacing creators' affiliate links with its own (MegaLag, December 2024), taking commissions…" STALE (present tense) — Wikipedia: Dec-2024 MegaLag video; Honey modified the extension after Google's March-2025 policy; PayPal admission 2026-01-12
W3 src/components/WhyNot.tsx "…is collected and sold to third parties without clear disclosure" → "…is reportedly collected without clear disclosure" (one-phrase cut: no source says "sold") UNVERIFIABLE — Wikipedia records only an allegation of collection beyond shopping activity; Honey's privacy page is JS-rendered
W4 src/components/WhyNot.tsx "lose millions in rightful earnings when Honey overrides their referral links" → "lost rightful earnings when Honey overrode their referral links" (unsourced figure dropped, past tense) UNVERIFIABLE — no figure sourced; class actions pending
W5 src/components/WhyNot.tsx "their code is completely hidden from public scrutiny" → "their code is closed source, with nothing published for independent audit" STALE/overclaim — shipped JS was inspected (third MegaLag video, acknowledged by PayPal)
W7 src/components/WhyNot.tsx "we never sell or share your personal information" → "we never sell your personal information or share it with advertisers" FALSE ("share") — PrivacyPolicy.tsx:70-71 discloses GA / Hotjar / Sentry
W8 src/components/WhyNot.tsx "Every line of code is public and auditable under the AGPL-3.0 license" → "The extension and web app are public and auditable under the AGPL-3.0 license" STALE/overclaim — coupon ingestion pipeline is external and unpublished (README.md:98)
O1 src/components/OpenSourceSection.tsx "Every change is peer-reviewed in public" → "Every change is publicly reviewable" UNVERIFIABLE — no evidence of independent community review
O3 src/components/OpenSourceSection.tsx "We never sell or share your personal information" → "We never sell your personal information or share it with advertisers" FALSE ("share") — as W7
O5 src/components/OpenSourceSection.tsx "Every line of code is open, auditable, and community-driven." → "The extension and web app are open, auditable, and community-driven." STALE/overclaim — as W8
F2 src/components/FeaturesSection.tsx "across 3,000+ stores" → "across 4,000+ stores" consistency (4,314 live)
F8 src/components/FeaturesSection.tsx card "Lightning Fast" → "Fast & Lightweight"; "Instant coupon discovery…" → "Automatic coupon discovery…"; "search and apply coupons in seconds" → "…at checkout" UNVERIFIABLE — no benchmark; codes tried sequentially, Shopify path reloads per code; "lightweight" backed by the size gate
F10 src/components/FeaturesSection.tsx "One extension, all browsers." → "One extension for Chrome, Firefox, Edge, and Safari." UNVERIFIABLE (overclaim) — only four browsers shipped
F11 src/components/FeaturesSection.tsx "Opaque data practices" → "Often opaque data practices" UNVERIFIABLE generalization
F12 src/components/FeaturesSection.tsx "Tracks your browsing habits" → "May track your browsing habits" UNVERIFIABLE — allegation only
F13 src/components/FeaturesSection.tsx "Hijacks affiliate commissions" → "Hijacked affiliate commissions" TRUE for Honey, STALE as present tense (PayPal disabled the code 2026-01-12)
F15 src/components/FeaturesSection.tsx "Fully open source & peer-reviewed" → "Fully open source & publicly reviewable" UNVERIFIABLE ("peer-reviewed")
F16 src/components/FeaturesSection.tsx "Slow and resource-heavy" → "Often resource-heavy" UNVERIFIABLE — no measurement
F17 src/components/FeaturesSection.tsx "Lightning fast & lightweight" → "Fast & lightweight" UNVERIFIABLE ("lightning fast")
P1/P9 src/components/PricingSection.tsx "Works on 3,000+ supported stores" / stat card "3,000+" → "4,000+" consistency
P5 src/components/PricingSection.tsx "Lightning fast performance" → "Fast, lightweight performance" UNVERIFIABLE
P11 src/components/PricingSection.tsx "Caramel is built by the community, for the community." → "Caramel is built in the open, for the community." UNVERIFIABLE (overclaim) — FAQ says maintained by Devino Solutions with contributors
H5 src/lib/heroStats.ts (+ comments in HeroTicketScene.tsx) hero stat 30004000 ("4,000+ Supported Stores", DOM fallback + 3D scene; same digit count so the scene's dynamic offsets are unaffected) consistency
S1/S2 src/components/SupportedSection.tsx H2 "3,000+ Supported Stores" → "4,000+ …"; "Caramel works everywhere you shop online." → "Caramel works at thousands of stores." FALSE (puffery) — 36 % of sampled catalog stores have no auto-apply config (store-detect.js:414-426)
C4/C6 src/components/coupons/coupons-section.tsx default subtitle and sidebar "verified coupon codes" → "coupon codes"; sidebar "3,000+" → "4,000+"; "works everywhere you shop online" → "works at thousands of stores" FALSE — listing uses visibleCouponsWhere which includes pending/retry ("Unverified" per coupons.ts:113-114); per-coupon badge kept
C1–C3 src/app/(marketing)/coupons/page.tsx meta description "Browse verified coupon codes…" → "Browse coupon codes…"; ItemList name "Verified coupon codes and promo codes" → "Coupon codes and promo codes"; H1 "Today's Verified Coupon Codes" → "Today's Coupon Codes"; subtitle drops "verified" FALSE — 107,827 visible vs 11,328 status='valid'
C7 src/app/(marketing)/coupons/[store]/page.tsx description literal "Find verified ${base} coupon codes, promo codes, and discounts. Updated daily." → "Find ${base} coupon codes, promo codes, and discounts — refreshed as new codes are found." (only the string literal; robots: lines untouched for seo/index-policy) FALSE ("verified") + UNVERIFIABLE ("Updated daily" — no stated ingest cadence)
C11 src/app/(marketing)/coupons/[store]/page.tsx "it reports back only whether a code worked — with no account information attached —" → "it reports back whether a code worked (linked to your account only when you're signed in)" FALSE — report/route.ts:75,142-143 persists userId
SRC1 src/app/(marketing)/sources/page.tsx meta description "See every source Caramel pulls coupon codes from, how many codes each one contributes, and its success rate — or request a new source." → "Where Caramel's coupon codes come from: the sources feeding the catalog, with the code count and success rate of each one as it is published — or request a new source." FALSE today — /api/sourcesdata: [], page renders "No sources found."
SS4 src/app/llms.txt/route.ts "which stores Caramel can auto-apply codes on" → "which stores Caramel holds coupon codes for" STALE (mismatch) — page lists catalog stores (4,314), not auto-apply configs (2,954)
SRC2 src/app/llms.txt/route.ts "the transparency page listing where Caramel's coupon codes come from" → "where Caramel's coupon codes come from, and where to request a new source" STALE — as SRC1 (kept the link; the request form is live)

Edits (repo docs)

# File Old → New Evidence
X3 README.md "more than 5 000 stores" → "more than 4,000 stores" FALSE — 4,314 stores with live codes
X5 README.md "the extension only asks for tab access while you shop, nothing more" → "the extension asks only for the permissions it needs to find the store you're on, read the checkout page and apply codes (tabs, storage, sign-in) – no ads, no third-party trackers" FALSE — built manifest: tabs, activeTab, storage, identity, alarms + host_permissions https://*/*
X6 README.md "see exactly how much a coupon saves you before you commit" → "see exactly how much each code saved as it is tested" TRUE (partial) — saving shown after codes are tested (coupon-runner.js:1024)

Not changed (checked, no figures present): src/app/layout.tsx, public/manifest.json, apps/caramel-extension/wxt.config.ts manifest name/description, .github workflow comments (internal, historical user counts). apps/caramel-extension/background.js:63 "2670 stores" is a stale payload-size comment, not public copy — left alone.

Tests

Updated to the new wording:

  • tests/unit/faq-section.test.tsx — number pin now over 100,000 coupon codes / more than 4,000 online stores
  • e2e/pages.spec.ts — /coupons H1 regex /today's coupon codes/i
  • e2e/home.spec.ts — feature card heading Fast & Lightweight

Added:

  • e2e/seo-regression.spec.ts — new test "home raw HTML quotes only the reconciled catalog figures": raw server HTML must contain 4,000+ and over 100,000 coupon codes across more than 4,000 online stores, and must NOT contain 139,000 or 3,000+. Deployment-safe (static copy, holds in both e2e contexts).

tests/unit/coupons-index-page.test.ts, coupons-store-page.test.ts, coupons-section.test.tsx and the extension suites pin none of the changed strings — verified by grep, no changes needed.

Verification (local, turbo --force, fresh worktree C:\wt-caramel-claims)

pnpm lint --force                       → Tasks: 2 successful, 2 total (extension: 0 errors, 3 pre-existing warnings)  exit 0
pnpm lint:oxlint                        → exit 0 (pre-existing no-underscore-dangle warnings only)
pnpm prettier-check --force             → app: "All matched files use Prettier code style!" after --write on the 4 reflowed files; root: exit 0
pnpm --filter caramel-app knip          → exit 0
pnpm -r run type-check                  → caramel-ui Done / caramel-app Done / caramel-extension Done  exit 0
                                          (needed `prisma generate` first in the fresh worktree — no code change)
pnpm --filter caramel-app test          → Test Files 78 passed (78) · Tests 719 passed (719)
pnpm test --force (extension)           → 887/894 on the first run with 3 gates in parallel; the 7 failures were 5 s timeouts in
                                          untouched files (ext-probe-extension-required, popup-coupon-paging, popup-email-login);
                                          isolated reruns: 27/28 then 8/8 → all green. No extension source touched in this PR.

CI covers: checks-app.yml (lint / oxlint / prettier / knip / type-check / unit / e2e-pr hermetic incl. the new seo-regression pin) and checks-extension.yml (extension unit suite). The e2e-push deployed context will run the same pin against dev.grabcaramel.com after merge.

Owner questions (outside this PR)

  1. App Store Connect listing (not in repo): "coupon and cashback extension" (no cashback code anywhere — grep 0 hits), "first fully open-source", "security pros audit every release", "iCloud sync for preferences" — all unsupported; only editable in ASC. Suggested: "open-source coupon extension for Safari" / "the code is public for anyone to audit" / drop "iCloud".
  2. /sources is empty on prod (/api/sources[], renders "No sources found."). The copy is now softened, but decide: populate the sources table from the ingest pipeline, or noindex /sources until it has rows.
  3. User-count claim "Join thousands of users" rests on CWS 2,000 + AMO 823 ADU + Edge 152 ≈ 2,975; App Store installs unknown. Confirm the iOS/macOS count so the claim has a full-fleet floor (left as-is: TRUE, thin).
  4. Privacy policy (PrivacyPolicy.tsx, effective date 2026-07-28): PR1 collection list omits the badge domain lookup, checkout page/cart text, coupon outcomes, sign-in details and optional savings sync (all declared to Mozilla); PR5 Sentry replay runs with maskAllText: false. Legal doc with an effective date — not edited here; decide on disclosure wording vs. a badge toggle / masking, then bump the date.
  5. @CaramelOfficial twitter site/creator in pricing/page.tsx and coupons/page.tsx — does the X account exist? Not in brandLinks.ts; remove the fields if not.
  6. "Trusted" in the site title / store listing name — kept as brand tagline (L1/X1).
  7. Support SLA "our team reads every message" (support/page.tsx) — kept; confirm someone watches the feedback inbox.
  8. F6 "Reviewed in the open by contributors and the community." (FeaturesSection.tsx) — kept; the inventory's rewrite ("Every change lands through a public pull request on GitHub") is more than a one-phrase change. Say the word and it goes in.
  9. W3/W4 full rewrites (Honey data-collection and creator-loss claims) — only the unsourced words ("sold", "millions") were cut here; the inventory's fuller rewrites with citations are available if preferred.
  10. Coupon pipeline: copy is now scoped to "extension and web app" everywhere; if the Python ingestion service is ever published, the broader claims can return.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant