Skip to content

chore(web): apply weekly SEO and AEO research - #8392

Closed
lawrencecchen wants to merge 1 commit into
mainfrom
automation/weekly-seo-aeo
Closed

lawrencecchen wants to merge 1 commit into
mainfrom
automation/weekly-seo-aeo

Conversation

@lawrencecchen

@lawrencecchen lawrencecchen commented Jul 18, 2026 •

Copy link
Copy Markdown
Contributor

Automated weekly SEO and AEO research from cmuxterm-hq.

Codex researched current primary sources, audited the existing cmux web implementation, applied one scoped improvement, and passed the web typecheck and test suite.

Run: https://github.com/manaflow-ai/cmuxterm-hq/actions/runs/29641110288

Codex report

STATUS: changed

Opportunity: 18 of 20 live /wall-of-love locale routes emitted English metadata despite localized page copy. This can weaken locale relevance and produce mismatched search titles/snippets.

Mechanism: metadata, Open Graph, and Twitter fields now use each locale’s authored title and description through the existing bounded SEO helpers. Canonicals and hreflang remain unchanged; no visible copy or catalogs changed.

Tests and validation:

  • Added coverage iterating all 20 locales from web/i18n/routing.ts.
  • Asserted localized descriptions never inherit English metadata and titles/descriptions remain within snippet bounds.
  • bun test tests/seo.test.ts: 34 passed.
  • Web typecheck and targeted ESLint passed.
  • Parsed all 20 locale catalogs; git diff --check passed.
  • Three files changed, all under web/.

Primary sources accessed 2026-07-18:

Residual risk: search engines may independently rewrite titles or snippets; no implementation-specific risk was identified.

@lawrencecchen lawrencecchen self-assigned this Jul 18, 2026
@vercel

vercel Bot commented Jul 18, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
cmux Canceled Canceled Jul 18, 2026 5:50pm
cmux-staging Building Building Preview, Comment Jul 18, 2026 5:50pm

@coderabbitai

coderabbitai Bot commented Jul 18, 2026 •

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

The change adds validated Open Graph image routes for localized and default-locale URLs, bypasses middleware processing for the image endpoint, references localized images in Article JSON-LD, bundles rendering fonts, and adds route and rendering tests.

Changes

Localized Open Graph image delivery

Layer / File(s) Summary
Validated Open Graph response rendering
web/app/lib/open-graph-image.tsx, web/app/lib/open-graph-fonts/*, web/package.json
Rendering is exported separately from route handling, validates supported locales, returns 404 responses for invalid locales, loads bundled fonts, and renders locale-specific taglines.
Localized and default route wiring
web/app/[locale]/opengraph-image/route.ts, web/app/opengraph-image/route.ts, web/proxy.ts
Node.js route handlers invoke the shared response function, while middleware bypasses processing for /opengraph-image.
Structured data integration and route tests
web/app/[locale]/components/json-ld.tsx, web/tests/opengraph-image-route.test.ts
Article JSON-LD includes localized image URLs, with tests covering route discovery, successful PNG responses, invalid locales, middleware behavior, locale propagation, pixel output, screenshot consistency, and metadata output.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant Middleware
  participant OpenGraphRoute
  participant openGraphImageResponse
  participant renderOpenGraphImage
  Client->>Middleware: Request localized Open Graph image
  Middleware->>OpenGraphRoute: Continue image request
  OpenGraphRoute->>openGraphImageResponse: Pass locale
  openGraphImageResponse->>openGraphImageResponse: Validate locale
  openGraphImageResponse->>renderOpenGraphImage: Render valid locale
  renderOpenGraphImage-->>Client: Return image response
Loading
🚥 Pre-merge checks | ✅ 24 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 14.29% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (24 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Cmux Swift Actor Isolation ✅ Passed No Swift files are changed in the diff, so the Swift actor-isolation rule isn’t applicable; the only touched path is a web test.
Cmux Swift Blocking Runtime ✅ Passed PASS: The PR only changes web/TypeScript files; no Swift files or new blocking/timing primitives were introduced.
Cmux Browser Automation Off-Main ✅ Passed The diff only touches an Open Graph image test file; no browser.* commands, mainActor routing, or socket-worker browser automation code were added or changed.
Cmux Expensive Synchronous Load ✅ Passed PASS: merge-base diff only touches web/TS assets, fonts, tests, and a PNG; no production Swift files or Swift sync-load paths were added or moved.
Cmux Cache Substitution Correctness ✅ Passed PASS: Changes only add OG image routing/JSON-LD and bundled font reads; no persistence/history/undo/snapshot cache substitution or stale-cache trust is introduced.
Cmux No Hacky Sleeps ✅ Passed No changed runtime file adds sleeps, timers, polling, or wall-clock waits; the new code is async I/O and test scaffolding only.
Cmux Algorithmic Complexity ✅ Passed No scalable-collection complexity regressions: the new checks are fixed-size (20 locales, 5-file Promise.all) and the rest is routing/SEO wiring.
Cmux Swift Concurrency ✅ Passed PR diff contains no Swift files; only web/docs/assets changed, so the Swift concurrency rule is not applicable.
Cmux Swift @Concurrent ✅ Passed No Swift files changed in the PR diff, so the cmux Swift @concurrent review rule is not applicable.
Cmux Swift Package Boundaries ✅ Passed PR changes are only web/TypeScript files; no Swift sources or Package.swift changes, so the Swift package-boundary rule isn’t implicated.
Cmux Swiftpm Lockfiles ✅ Passed PR only changes web/tests/opengraph-image-route.test.ts; no SwiftPM, Xcode, .gitignore, or workflow files were touched.
Cmux Swift Logging ✅ Passed No Swift files or Swift runtime logging changes appear in the PR diff; the review rule only applies to production Swift code.
Cmux User-Facing Error Privacy ✅ Passed PASS: Production changes add only a blank 404 for invalid locales and no user-facing error text, vendor names, headers, or raw upstream details.
Cmux Full Internationalization ✅ Passed The new Article image URL and OG routes are locale-derived, and the rendered tagline already comes from a complete locale map covering every routing locale.
Cmux Swiftui State Layout ✅ Passed PASS: The commit only changes web/tests/opengraph-image-route.test.ts; no Swift/SwiftUI files or state/layout patterns are introduced, so the rule is not applicable.
Cmux Architecture Rethink ✅ Passed This PR only touches a web test; no Swift files or Swift architectural changes are present, so the Swift rethink rule is not applicable.
Cmux Swift Auxiliary Window Close Shortcuts ✅ Passed PR diff changes only web assets/JS/PNG/fonts; no Swift files or window code changed, so the auxiliary-window shortcut rule is not applicable.
Cmux Source Artifacts ✅ Passed Only changed path is a hand-written test file, and the diff merely removes a timeout; no local/generated artifacts or scratch dirs were added.
Cmux No Test Or Debug Seam In Production Source ✅ Passed PR only changes a web test file; no Swift production Sources/** files are touched, so the seam rule is not applicable.
Cmux No Ambient Global State ✅ Passed PASS: Diff vs origin/main contains only web/TS files and assets; no Swift files or new singleton/global state were introduced.
Title check ✅ Passed The title is concise and accurately reflects the weekly SEO/AEO research and implementation work in this PR.
Description check ✅ Passed The description covers the summary, rationale, tests, and validation details, though the demo video, review trigger, and checklist sections are omitted.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch automation/weekly-seo-aeo

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@greptile-apps

greptile-apps Bot commented Jul 18, 2026 •

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR fixes locale-aware metadata for the /wall-of-love page, which was previously emitting English titles and descriptions for all 19 non-English locales. The fix routes non-English locales through visible page copy (t("title") / t("description")) while preserving the existing authored metaTitle/metaDescription for English.

  • web/i18n/audited-seo.ts: Adds wallOfLoveSeoCopy, a locale-branching helper consistent with the existing audited-SEO pattern; non-English path constructs the title as ${t("title")} — cmux and passes both values through the existing seoTitle/seoDescription validators.
  • web/app/[locale]/(landing)/wall-of-love/page.tsx: Delegates metadata generation to the new helper; Open Graph and Twitter cards are updated via the same { title, description } pair.
  • web/tests/seo.test.ts: Adds a 20-locale test asserting correct content selection, ≤60/≤160 char bounds, and absence of English fallback copy in non-English descriptions.

Confidence Score: 5/5

Scoped metadata-only change with no impact on page rendering, routing, or data; all 20 locales validated by the new test suite.

The change touches only the server-side generateMetadata path — visible page copy, canonicals, hreflang alternates, and the sitemap are untouched. The new wallOfLoveSeoCopy helper follows the established pattern in audited-seo.ts and is backed by a comprehensive per-locale test that enforces content correctness and length bounds.

No files require special attention.

Important Files Changed

Filename Overview
web/app/[locale]/(landing)/wall-of-love/page.tsx Delegates metadata generation to wallOfLoveSeoCopy; removes direct seoDescription import; no logic changes to rendered page content.
web/i18n/audited-seo.ts Adds wallOfLoveSeoCopy: English path retains metaTitle/metaDescription, all other locales derive title from t("title") suffixed with "— cmux" and description from t("description"), both passed through existing seoTitle/seoDescription validators.
web/tests/seo.test.ts Adds behavioral coverage iterating all 20 locales, validates title and description content, enforces ≤60/≤160 char bounds, and asserts non-English descriptions do not fall back to English copy.

Reviews (8): Last reviewed commit: "chore(web): apply weekly SEO and AEO res..." | Re-trigger Greptile

Comment on lines 7 to 8
export const size = { width: 1200, height: 630 };
export const contentType = "image/png";

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 The size and contentType exports are left over from when this file was a Next.js file-convention metadata image (opengraph-image.tsx). Now that it is a plain utility module, neither export is consumed by any route handler or caller — they are dead code and will silently drift from the actual dimensions used by renderOpenGraphImage (width: 1200 * S, height: 630 * S).

Suggested change
export const size = { width: 1200, height: 630 };
export const contentType = "image/png";
// Retained for any callers that need the canonical dimensions without
// importing from seo.ts. The renderer uses width * S and height * S internally.
export const size = { width: 1200, height: 630 };
export const contentType = "image/png";

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Comment thread web/app/lib/open-graph-image.tsx Outdated
Comment on lines +56 to +67
type OpenGraphImageRenderer = (locale: string) => Response | Promise<Response>;

export async function openGraphImageResponse(
locale: string,
render: OpenGraphImageRenderer = renderOpenGraphImage,
): Promise<Response> {
if (!routing.locales.includes(locale as Locale)) {
return new Response(null, { status: 404 });
}

return render(locale);
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 renderOpenGraphImage exported without a caller outside this module

renderOpenGraphImage is only ever reached through the default-parameter path of openGraphImageResponse; no external file imports or calls it directly. Exporting it publicly means future callers can bypass the locale-validation guard in openGraphImageResponse and pass any arbitrary string straight to the renderer. If intentional (e.g., for future direct use), a doc comment clarifying that callers are responsible for their own validation would help; otherwise keeping it unexported (async function renderOpenGraphImage) is safer.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@web/proxy.ts`:
- Around line 64-68: Update the opengraph-image bypass condition in the
middleware to match both "/opengraph-image" and "/opengraph-image/". Preserve
the existing NextResponse.next() behavior for either pathname.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 372d1fd8-c847-4f6d-b475-9a7d15718faf

📥 Commits

Reviewing files that changed from the base of the PR and between ee2615e and 6a25ac2.

📒 Files selected for processing (6)
  • web/app/[locale]/components/json-ld.tsx
  • web/app/[locale]/opengraph-image/route.ts
  • web/app/lib/open-graph-image.tsx
  • web/app/opengraph-image/route.ts
  • web/proxy.ts
  • web/tests/opengraph-image-route.test.ts

Comment thread web/proxy.ts Outdated
@cursor

cursor Bot commented Jul 18, 2026

Copy link
Copy Markdown

Bugbot is paused — on-demand spend limit reached

Bugbot uses usage-based billing for this team and has hit its on-demand spend limit.

A team admin can raise the spend limit in the Cursor dashboard, or wait for the next billing cycle to continue.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@web/tests/opengraph-image-route.test.ts`:
- Around line 51-66: Update the tests around renderOpenGraphImage to mock
global.fetch or the underlying font-fetching layer with a local buffer,
preventing requests to live hosts such as fonts.gstatic.com. Remove the 15_000
timeout from the test definition while preserving the existing response status,
content type, and PNG signature assertions.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 0ef04c44-b27c-4449-bac1-a33ed24c60c1

📥 Commits

Reviewing files that changed from the base of the PR and between 6a25ac2 and dd9a693.

📒 Files selected for processing (1)
  • web/tests/opengraph-image-route.test.ts

Comment thread web/tests/opengraph-image-route.test.ts Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@web/app/lib/open-graph-image.tsx`:
- Around line 65-73: Update readBundledFont and the Next.js file-tracing
configuration so every file under app/lib/open-graph-fonts is explicitly
included in serverless and standalone bundles. Prefer adding the appropriate
outputFileTracingIncludes entry in next.config.ts while preserving the existing
dynamic filename lookup.
- Around line 65-72: Update the production packaging configuration in
next.config.ts to explicitly include the open-graph-fonts directory in
outputFileTracingIncludes for the route using readBundledFont(), ensuring
dynamically resolved font files are present in the serverless bundle;
alternatively, move those fonts to public and update readBundledFont
accordingly.

In `@web/tests/opengraph-image-route.test.ts`:
- Around line 16-25: Replace the manual globalThis.fetch reassignment in
withoutNetwork with the test framework’s built-in spy/mock utility, configuring
fetch to reject with the existing network-blocking error and relying on
framework-managed restoration. Update the affected tests or setup hook so the
mock is established per test context and remains safely isolated during
concurrent execution.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: ea49e2fd-404d-4dc3-ab0f-a22d31164e92

📥 Commits

Reviewing files that changed from the base of the PR and between f00fb86 and daf9f3b.

⛔ Files ignored due to path filters (12)
  • docs/assets/main-first-image.png is excluded by !**/*.png
  • web/app/lib/open-graph-fonts/geist-regular.ttf is excluded by !**/*.ttf
  • web/app/lib/open-graph-fonts/geist-semibold.ttf is excluded by !**/*.ttf
  • web/app/lib/open-graph-fonts/noto-cjk-jp.otf is excluded by !**/*.otf
  • web/app/lib/open-graph-fonts/noto-cjk-kr.otf is excluded by !**/*.otf
  • web/app/lib/open-graph-fonts/noto-cjk-sc.otf is excluded by !**/*.otf
  • web/app/lib/open-graph-fonts/noto-cjk-tc.otf is excluded by !**/*.otf
  • web/app/lib/open-graph-fonts/noto-khmer.ttf is excluded by !**/*.ttf
  • web/app/lib/open-graph-fonts/noto-sans-cyrillic.ttf is excluded by !**/*.ttf
  • web/app/lib/open-graph-fonts/noto-thai.ttf is excluded by !**/*.ttf
  • web/app/lib/open-graph-fonts/tajawal.ttf is excluded by !**/*.ttf
  • web/bun.lock is excluded by !**/*.lock
📒 Files selected for processing (5)
  • web/app/lib/open-graph-fonts/OFL.txt
  • web/app/lib/open-graph-fonts/SOURCES.md
  • web/app/lib/open-graph-image.tsx
  • web/package.json
  • web/tests/opengraph-image-route.test.ts

Comment thread web/app/lib/open-graph-image.tsx Outdated
Comment on lines +65 to +72
async function readBundledFont(filename: string): Promise<ArrayBuffer> {
const data = await readFile(
join(process.cwd(), "app", "lib", "open-graph-fonts", filename)
);
return data.buffer.slice(
data.byteOffset,
data.byteOffset + data.byteLength
) as ArrayBuffer;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Search for outputFileTracingIncludes covering the open-graph-fonts directory
rg 'outputFileTracingIncludes' next.config.ts next.config.js next.config.mjs

Repository: manaflow-ai/cmux

Length of output: 320


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== file list =="
git ls-files | rg '^(web/app/lib/open-graph-image\.tsx|.*next\.config\.(ts|js|mjs)|web/.*/open-graph-fonts/|app/lib/open-graph-fonts/)'

echo
echo "== open-graph-image.tsx outline =="
ast-grep outline web/app/lib/open-graph-image.tsx --view expanded || true

echo
echo "== relevant lines in open-graph-image.tsx =="
sed -n '1,220p' web/app/lib/open-graph-image.tsx | nl -ba | sed -n '1,220p'

echo
echo "== next.config files =="
for f in next.config.ts next.config.js next.config.mjs web/next.config.ts web/next.config.js web/next.config.mjs; do
  if [ -f "$f" ]; then
    echo "--- $f ---"
    nl -ba "$f" | sed -n '1,240p'
  fi
done

echo
echo "== search for outputFileTracingIncludes and open-graph-fonts =="
rg -n 'outputFileTracingIncludes|open-graph-fonts|open-graph-image' .

Repository: manaflow-ai/cmux

Length of output: 1320


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== web/app/lib/open-graph-image.tsx (selected lines) =="
sed -n '1,180p' web/app/lib/open-graph-image.tsx | cat -n

echo
echo "== web/next.config.ts =="
sed -n '1,260p' web/next.config.ts | cat -n

echo
echo "== search for tracing/include rules and open-graph-fonts =="
rg -n 'outputFileTracingIncludes|open-graph-fonts|openGraphImage|open-graph-image' web/next.config.ts web/app/lib/open-graph-image.tsx

Repository: manaflow-ai/cmux

Length of output: 12957


🌐 Web query:

Next.js output file tracing dynamic readFile join filename traced files serverless fonts outputFileTracingIncludes

💡 Result:

In Next.js, Output File Tracing (NFT) automatically detects dependencies for your server-side code to minimize deployment sizes [1]. When you use dynamic file system access—such as using fs.readFile with path.join(process.cwd(), ...)—the build system may fail to statically determine which files are required, often resulting in a warning that the "whole project" is being traced [2][3]. To manage these traces and ensure files like fonts or data assets are included in your serverless or standalone deployments, use the following strategies: 1. outputFileTracingIncludes: This configuration allows you to manually include files in your trace that the automatic analysis missed [1]. It is defined in your next.config.js as an object where keys are route globs and values are arrays of glob patterns [4]. Example: module.exports = { experimental: { outputFileTracingIncludes: { '/api/fonts-route': ['./public/fonts//*'], }, }, } Note that these paths are resolved relative to your project root [1][4]. 2. Handling "Whole Project" Tracing Warnings: If you see warnings about dynamic filesystem access causing the whole project to be traced, it is usually because Next.js cannot determine the scope of a file path [3]. - Scope paths: If possible, restrict the path to a specific subfolder (e.g., path.join(process.cwd, 'data', folder)) [3]. - Ignore annotations: You can use /* turbopackIgnore: true */ comments near the dynamic path usage to instruct the build system to skip tracing for that specific call [5][6][3]. Note that there are known limitations where these comments must be placed precisely on the variable argument passed to the fs function [6]. - Monorepos: If your files are outside the standard app directory, ensure your outputFileTracingRoot is correctly set (e.g., to the monorepo root) and combine it with outputFileTracingIncludes to pull in the necessary files [1][4]. 3. Deployment Considerations: These settings are critical when using output: "standalone" or deploying to serverless environments where only essential files are included [1][7]. If a file is missing at runtime (e.g., a font used in a library like canvas), verify its presence in the generated.nft.json file located in the.next/server/ directory [8][7].

Citations:


🌐 Web query:

@vercel/nft fs.readFile dynamic filename path.join directory traced included whole project omitted runtime ENOENT

💡 Result:

The ENOENT error occurs because @vercel/nft (Node File Trace) uses static analysis to determine which files to include in your deployment [1][2]. When you use dynamic paths—such as variables inside path.join—the static analyzer often cannot resolve the final file path at build time [3][2]. Consequently, it fails to include those files in the production bundle, resulting in the runtime ENOENT (Error NO ENTry) error [4][1]. To resolve this, you must explicitly tell Vercel to include these files in your build output. The method depends on your project structure: For Next.js projects, use the experimental outputFileTracingIncludes configuration in your next.config.js to ensure the files are bundled: module.exports = { experimental: { outputFileTracingIncludes: { '/api/your-route': ['./path/to/files//'], }, }, }; For standard Vercel Functions (outside of Next.js), you can specify includeFiles in your vercel.json: { "functions": { "api/your-route.js": { "includeFiles": "path/to/files//" } } } If you are working in a monorepo or need to access files outside the standard root directory, you may also need to configure outputFileTracingRoot in your Next.js config to allow the tracer to see files further up the directory tree [2][5]. Once these configurations are added, the files will be physically included in your deployment, allowing fs.readFile to access them successfully at runtime [1][2].

Citations:


Include web/app/lib/open-graph-fonts in the production trace
readBundledFont() resolves filename dynamically, and web/next.config.ts has no outputFileTracingIncludes rule for this route, so these font files can be dropped from the serverless bundle and fail with ENOENT. Trace that folder explicitly or move the fonts to public/.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@web/app/lib/open-graph-image.tsx` around lines 65 - 72, Update the production
packaging configuration in next.config.ts to explicitly include the
open-graph-fonts directory in outputFileTracingIncludes for the route using
readBundledFont(), ensuring dynamically resolved font files are present in the
serverless bundle; alternatively, move those fonts to public and update
readBundledFont accordingly.

Comment thread web/app/lib/open-graph-image.tsx Outdated
Comment thread web/tests/opengraph-image-route.test.ts Outdated
Comment on lines +16 to +25
async function withoutNetwork<T>(operation: () => Promise<T>): Promise<T> {
const fetchImplementation = globalThis.fetch;
globalThis.fetch = () =>
Promise.reject(new Error("Open Graph rendering must not use the network"));
try {
return await operation();
} finally {
globalThis.fetch = fetchImplementation;
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Race condition hazard in asynchronous global state mutation.

Temporarily replacing globalThis.fetch and restoring it after an await introduces a critical concurrency hazard. If withoutNetwork is executed concurrently by multiple tests (or overlapping microtasks), an inner execution will capture the already mocked fetch as its fetchImplementation. When it finishes, it will permanently restore the mock to globalThis.fetch, bricking network requests for the remainder of the test suite.

Please replace this manual override with your testing framework's built-in mocking utilities, which safely handle isolation and cleanup per test context.

For Vitest or Jest, you can establish the mock inside the test or in a beforeEach hook:

🛠 Proposed fix using test framework spies

For Vitest:

-async function withoutNetwork<T>(operation: () => Promise<T>): Promise<T> {
-  const fetchImplementation = globalThis.fetch;
-  globalThis.fetch = () =>
-    Promise.reject(new Error("Open Graph rendering must not use the network"));
-  try {
-    return await operation();
-  } finally {
-    globalThis.fetch = fetchImplementation;
-  }
-}

And in your test cases (or beforeEach), simply use:

vi.spyOn(globalThis, "fetch").mockRejectedValue(
  new Error("Open Graph rendering must not use the network")
);

(If you are using Jest, use jest.spyOn(globalThis, "fetch") instead).

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
async function withoutNetwork<T>(operation: () => Promise<T>): Promise<T> {
const fetchImplementation = globalThis.fetch;
globalThis.fetch = () =>
Promise.reject(new Error("Open Graph rendering must not use the network"));
try {
return await operation();
} finally {
globalThis.fetch = fetchImplementation;
}
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@web/tests/opengraph-image-route.test.ts` around lines 16 - 25, Replace the
manual globalThis.fetch reassignment in withoutNetwork with the test framework’s
built-in spy/mock utility, configuring fetch to reject with the existing
network-blocking error and relying on framework-managed restoration. Update the
affected tests or setup hook so the mock is established per test context and
remains safely isolated during concurrent execution.

@lawrencecchen
lawrencecchen force-pushed the automation/weekly-seo-aeo branch from bfc153c to b54c1d9 Compare July 18, 2026 09:54
@lawrencecchen lawrencecchen added the stale-revisit Closed after 30+ days without activity; preserved for possible revisit or reopening. label Sep 23, 2026
@github-project-automation github-project-automation Bot moved this from Todo to Done in cmux backlog Sep 23, 2026

This branch was successfully deployed

1 active deployment
Preview – cmux — b54c1d98 Deployed Jul 18, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

stale-revisit Closed after 30+ days without activity; preserved for possible revisit or reopening.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants