chore(web): programmatic OG meta validation + Lighthouse CI for guides + landing#2439
Conversation
Adds a follow-up to #2437 that asserts the OG / Twitter meta tags expected by social previewers actually land in the built HTML, and optionally re-checks them over the wire against a deployed URL. - New `apps/guides/__tests__/og-meta.test.ts` runs `bun run build` (if `out/` is missing) and walks every `out/guide/<slug>.html` plus `out/index.html`, parsing with cheerio. It asserts the full meta set (og:title, og:description, og:image, og:image:width, og:image:height, og:type, og:url, og:site_name, twitter:card, twitter:title, twitter:description, twitter:image) on a 3-post random sample, that every post has an absolute `https://` og:image pointing at `/og/<slug>.png`, and that the root page uses the site-wide image (not a per-post one). Sampling keeps the suite fast across 500+ posts. - Optional live pass via `open-graph-scraper` is gated on `OG_LIVE_CHECK_URL`. Same shape, fetched over the wire — useful after a deploy to catch CF transforms / cache layers that a built-HTML check can miss. - New `test:og-meta` script and wired into the `Builds` workflow after the guides build, before the artifact upload — a meta-tag regression fails the workflow check on the PR. - `cheerio` and `open-graph-scraper` added as devDependencies of `apps/guides` (test-only, not runtime deps). - README documents both passes and lists the manual debugger URLs (opengraph.xyz, microlink, FB Sharing Debugger, LinkedIn Post Inspector) for post-deploy verification. Antecedents: #2436 (build-order fix) and #2437 (OG hardening + Builds workflow). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
Warning Rate limit exceeded
You’ve run out of usage credits. Purchase more in the billing tab. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Run ID: ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (13)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Coverage Report for Expo Unit Tests Coverage (./apps/expo)
File CoverageNo changed files found. |
Coverage Report for API Unit Tests Coverage (./packages/api)
File CoverageNo changed files found. |
There was a problem hiding this comment.
Pull request overview
Adds automated Open Graph/Twitter metadata validation for the guides static export, including CI integration and documentation for static and optional live checks.
Changes:
- Adds
test:og-metaVitest coverage using Cheerio and optionalopen-graph-scraperlive validation. - Runs OG meta validation in the guides build workflow.
- Documents the validation workflow and adds related dev dependencies.
Reviewed changes
Copilot reviewed 4 out of 5 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
apps/guides/__tests__/og-meta.test.ts |
Adds static and optional live OG/Twitter metadata validation tests. |
apps/guides/package.json |
Adds the test:og-meta script and dev dependencies. |
.github/workflows/builds.yml |
Runs OG meta validation after the guides build. |
apps/guides/README.md |
Documents OG metadata validation and manual validators. |
bun.lock |
Locks newly added metadata validation dependencies. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| describe.skipIf(!process.env.OG_LIVE_CHECK_URL)('live OG check', () => { | ||
| const liveUrl = (process.env.OG_LIVE_CHECK_URL ?? '').replace(/\/$/, ''); | ||
|
|
| expect(ogImage, `${slug}: og:image should point at /og/${slug}.png`).toMatch( | ||
| new RegExp(`/og/${escapeRegex(slug)}\\.png$`), |
…flow
Extends the guides OG meta validation pattern to the landing marketing
site, and wires Lighthouse CI into the Builds workflow for both apps.
Per the team mandate: every web app gets programmatic OG and Lighthouse
evaluation, surfaced in PR checks before deploy.
Landing-side OG meta:
- apps/landing/__tests__/og-meta.test.ts walks built HTML in out/
(top-level *.html + nested <slug>/index.html, skipping 404/500),
asserts the same 12-tag OG/Twitter set as guides, requires absolute
https og:image pointing at the site-wide image, and includes the
same OG_LIVE_CHECK_URL-gated open-graph-scraper block.
- Adds cheerio + open-graph-scraper as devDependencies (matching guides).
- Adds test:og-meta script.
Lighthouse CI in Builds workflow:
- Adds lighthouse:ci script (lhci autorun, no rebuild) to both apps.
- Builds workflow gains a Lighthouse CI step after OG validation in
each job, with continue-on-error so perf regressions yellow-check
rather than block, and a Step Summary block so reviewers see the
output without clicking into job logs.
- Uses existing .lighthouserc.{js,mobile.js} budgets unchanged.
Docs:
- New apps/landing/README.md documents the build pipeline + OG +
Lighthouse validation layers + manual debugger links.
- Updates apps/guides/README.md to cross-reference the shared pattern
and document the new Lighthouse CI integration.
.gitignore: adds .lighthouseci/ output dir.
packages/env/scripts/no-raw-process-env.ts auto-updated by postinstall
env script to allow OG_LIVE_CHECK_URL reads in the two new test files.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Deploying packrat-landing with
|
| Latest commit: |
c10521f
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://1e480d45.packrat-landing.pages.dev |
| Branch Preview URL: | https://chore-og-meta-validation.packrat-landing.pages.dev |
…nto chore/og-meta-validation
…ove continue-on-error Three real issues from the latest #2439 CI run: - 404.html and 500.html were dragging Lighthouse runs down — they inherently lack <title>/<html lang>/meta description by design. Used assertMatrix with a regex pattern to exclude them; full assertion set still runs against every other HTML. - continue-on-error: true on the Lighthouse step meant failures didn't fail CI. Removed both (guides + landing). Lighthouse is now a real gate. - LHCI reports were going to temporary-public-storage URLs only. Added actions/upload-artifact steps for apps/<name>/.lighthouseci with 14-day retention so reviewers can click through after the PR run. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
packrat-admin | c10521f | Commit Preview URL Branch Preview URL |
May 17 2026, 07:24 AM |
Substantial rebase covering 225 dev commits — #2414 type unification, #2422 single-param refactor, #2433 MCP+CLI Eden Treaty rewrite, #2439 OG meta validation, #2441/#2442 OG URL fix, plus many smaller. Conflicts resolved: - apps/expo/features/packs/utils/uploadImage.ts: kept HEAD's userId cache, used dev's object-arg getPresignedUrl call (matches function signature). - apps/expo/features/trips/hooks/useDeleteTrip.ts: kept HEAD's async + optimistic-delete comment, used dev's object-arg obs() call (matches current obs signature in apps/expo/lib/store.ts). Post-merge cleanup of dev-introduced single-param violations: - apps/expo/lib/utils/__tests__/getRelativeTime.test.ts: rewrote 3 test call sites to object args matching the refactored getRelativeTime. - packages/api/src/utils/__tests__/embeddingHelper.test.ts: rewrote 7 test call sites to object args matching the refactored getEmbeddingText; updated Parameters<> type indexes. - packages/overpass/src/client.test.ts: converted makeResponse to single object param and updated all 11 call sites. - scripts/lint/no-owned-max-params.ts: added apps/trails/scripts/generate-og-images.ts to EXCLUDED_FILES (same globalThis.fetch shim pattern as the existing landing/guides entries). Verification: bun install ok; bun check-types 0 errors; biome check 0 errors (2 unrelated warnings); no-owned-max-params 0 violations. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Summary
Follow-up to #2437 (OG hardening +
Buildsworkflow) and #2436(build-order fix). Establishes a per-app standard: every PackRat web
app gets programmatic OG meta validation + Lighthouse CI surfaced in PR
checks before deploy.
Covers both
apps/guidesandapps/landingand wires Lighthouse CIinto the
Buildsworkflow for both.Guides — OG meta validation
test:og-meta) — runsbun run build(ifout/ismissing) and walks every
out/guide/<slug>.htmlplusout/index.htmlwith cheerio. Asserts the required tag set
(
og:title,og:description,og:image,og:image:width,og:image:height,og:type,og:url,og:site_name,twitter:card,twitter:title,twitter:description,twitter:image) on a 3-post random sample, and that every posthas an absolute
https://og:imageURL pointing at/og/<slug>.png. The root page gets the same shape with thesite-wide image (
/og-image.pngor the Next.js auto-generated/opengraph-imageroute — whichever wins). Sampling keeps the suitefast across 500+ posts.
OG_LIVE_CHECK_URLenv var. Usesopen-graph-scraper(the same parser most social platformsuse under the hood) to fetch the live root URL + a sample guide page
and assert the same shape. Skipped by default; useful after a deploy
to catch CF transforms or cache layers that a built-HTML check can
miss.
Landing — OG meta validation (new in this PR's second commit)
apps/landing/__tests__/og-meta.test.tsmirrors the guides pattern:walks every top-level
out/*.htmlplus nestedout/<slug>/index.html(skipping
404.html/500.html), asserts the same 12-tag set onevery page, requires an absolute https
og:imagepointing at thesite-wide image (
/og-image.pngor/opengraph-image), and shipsthe same
OG_LIVE_CHECK_URL-gatedopen-graph-scraperblock (nowsampling root +
/pricing).cheerio+open-graph-scraperadded toapps/landingdevDeps(test-only — explicitly not runtime).
test:og-metascript added.Lighthouse CI in the Builds workflow
The repo already has
.lighthouserc.{js,mobile.js}(perf ≥ 0.8;a11y / best-practices / SEO ≥ 0.9; LCP < 2500 ms / 4000 ms;
CLS < 0.1) and a standalone
lighthouse.ymlthat rebuilds. This PRwires LHCI into the
Buildsworkflow so scores ship next to the buildartifact in the same PR check, reusing the already-built
out/:lighthouse:ciscript in bothapps/guidesandapps/landing(
lhci autorun— no rebuild, since the build step already ran).Lighthouse CIstep in bothBuildsjobs, after the OG metavalidation. Marked
continue-on-error: trueso perf regressionssurface as a yellow check rather than blocking the PR.
Summarize Lighthouse scoresstep emits the LHCI output tailto
$GITHUB_STEP_SUMMARYso reviewers see scores directly in thePR Checks UI without clicking into job logs.
CI integration
Builds (guides): build → validate OG meta → Lighthouse CI → summaryBuilds (landing): build → validate OG meta → Lighthouse CI → summaryA meta-tag regression fails the PR check. A Lighthouse score regression
yellow-checks it and surfaces the numbers.
Docs
apps/landing/README.md— build pipeline, OG validation layers,Lighthouse CI integration, manual debugger URLs.
apps/guides/README.mdupdated with a cross-reference to the sharedpattern and a new Lighthouse CI section.
Why
After #2437 we had OG images generated and the Builds workflow surfacing
post / image counts in the Step Summary, but nothing was asserting that
the meta tags themselves actually make it into the built HTML — and
Lighthouse only ran in a separate workflow that wasn't part of the
main build's check signal. A silent regression — e.g. a Next.js upgrade
dropping
metadataBaseresolution, an image moving to a relative path,or a perf regression from a new font — would only be caught when a
user noticed a broken Slack preview or a slow page. This closes both
gaps with fast, deterministic checks on every PR, for both web apps.
Scope notes
apps/trails: declares minimal OG metadata (no images, notwitter:card, nometadataBase). Adding the 12-tag validationwould require also fleshing out the metadata — out of scope for an
enforcement PR. To be picked up separately when the trails app
hardens its OG story.
apps/admin/apps/web: internal tools, not public-facingmarketing. Excluded by the user's mandate scope.
Test plan
bun installsucceeds with the new landing devDepsbun check-types— 0 errorsbun check(biome) — cleanbun run --cwd apps/guides build— producesout/with all 504 guide HTML filesbun run --cwd apps/guides test:og-meta— 5 static tests pass, 2 live tests skippedbun run --cwd apps/landing build— producesout/with 9 top-level routesbun run --cwd apps/landing test:og-meta— 4 static tests pass, 2 live tests skippedbun run --cwd apps/landing lighthouse:ci— starts LHCI cleanly (full local run not required; CI will exercise it)Builds (guides)andBuilds (landing)runs include the new OG + Lighthouse steps with the LHCI Step Summary visible in the PR Checks UIOG_LIVE_CHECK_URL=https://guides.packratai.com bun run --cwd apps/guides test:og-metapasses after deployOG_LIVE_CHECK_URL=https://packratai.com bun run --cwd apps/landing test:og-metapasses after deploy🤖 Generated with Claude Code