From d15c48a80d7517c2b4a91625fc2b6c0ab9551e2b Mon Sep 17 00:00:00 2001
From: Aurora Scharff
Date: Mon, 24 Aug 2026 18:51:16 +0200
Subject: [PATCH 01/10] [evals] Split instant and navigation-stage coverage
---
evals/evals/agent-040-instant/EVAL.ts | 73 +++++++----------
evals/evals/agent-040-instant/PROMPT.md | 2 +-
.../EVAL.ts | 80 +++++++++++++++++++
.../PROMPT.md | 1 +
.../app/layout.tsx | 18 +++++
.../app/page.tsx | 21 +++++
.../app/projects/[slug]/page.tsx | 33 ++++++++
.../lib/data.ts | 32 ++++++++
.../next.config.ts | 7 ++
.../package.json | 23 ++++++
.../tsconfig.json | 27 +++++++
11 files changed, 272 insertions(+), 45 deletions(-)
create mode 100644 evals/evals/agent-044-prefetch-until-navigation/EVAL.ts
create mode 100644 evals/evals/agent-044-prefetch-until-navigation/PROMPT.md
create mode 100644 evals/evals/agent-044-prefetch-until-navigation/app/layout.tsx
create mode 100644 evals/evals/agent-044-prefetch-until-navigation/app/page.tsx
create mode 100644 evals/evals/agent-044-prefetch-until-navigation/app/projects/[slug]/page.tsx
create mode 100644 evals/evals/agent-044-prefetch-until-navigation/lib/data.ts
create mode 100644 evals/evals/agent-044-prefetch-until-navigation/next.config.ts
create mode 100644 evals/evals/agent-044-prefetch-until-navigation/package.json
create mode 100644 evals/evals/agent-044-prefetch-until-navigation/tsconfig.json
diff --git a/evals/evals/agent-040-instant/EVAL.ts b/evals/evals/agent-040-instant/EVAL.ts
index 6764f178f0ba..6602df477af0 100644
--- a/evals/evals/agent-040-instant/EVAL.ts
+++ b/evals/evals/agent-040-instant/EVAL.ts
@@ -1,67 +1,52 @@
/**
- * Instant Navigations
+ * Instant Validation
*
- * Verifies that the agent enables instant navigation on the product route.
- *
- * The eval harness runs `next build` as a script — with `cacheComponents: true`,
- * the build validates that the caching structure produces an instant static shell.
- * This test checks the agent actually exported `instant` (the build would
- * pass without it, since Suspense alone satisfies the build on a static route).
+ * Verifies that the agent opts the product route into Instant Validation and
+ * produces a meaningful Cache Components shell: the stable title is available
+ * immediately while live inventory streams behind a Suspense boundary.
*/
import { expect, test } from 'vitest'
-import { readFileSync, existsSync, readdirSync, statSync } from 'fs'
+import { existsSync, readFileSync, readdirSync, statSync } from 'fs'
import { join } from 'path'
+import { environment } from '@vercel/agent-eval/eval'
-type SourceFile = { path: string; content: string }
-
-const IGNORE_DIRS = new Set([
- '.git',
- '.next',
- 'node_modules',
- 'dist',
- 'build',
- 'coverage',
-])
-
-const IGNORE_FILES = new Set(['EVAL.ts', 'PROMPT.md'])
+function stripComments(source: string): string {
+ return source.replace(/\/\*[\s\S]*?\*\//g, '').replace(/\/\/.*$/gm, '')
+}
-function readSourceFiles(dir: string): SourceFile[] {
+function readRouteSource(dir: string): string[] {
if (!existsSync(dir)) return []
- const files: SourceFile[] = []
+ const files: string[] = []
for (const entry of readdirSync(dir)) {
- if (IGNORE_DIRS.has(entry)) continue
-
const fullPath = join(dir, entry)
const stats = statSync(fullPath)
-
if (stats.isDirectory()) {
- files.push(...readSourceFiles(fullPath))
- continue
- }
-
- if (IGNORE_FILES.has(entry)) continue
-
- if (/\.(ts|tsx|js|jsx)$/.test(entry)) {
- files.push({
- path: fullPath,
- content: readFileSync(fullPath, 'utf-8'),
- })
+ files.push(...readRouteSource(fullPath))
+ } else if (/\.(ts|tsx|js|jsx)$/.test(entry)) {
+ files.push(stripComments(readFileSync(fullPath, 'utf-8')))
}
}
-
return files
}
-const sourceFiles = readSourceFiles(process.cwd())
+const productRouteSource = readRouteSource(
+ join(process.cwd(), 'app/product')
+).join('\n---FILE---\n')
-test('instant exported from the product route', () => {
- const productPage = sourceFiles.find(
- (f) => f.path.includes('product') && /page\.(tsx?|jsx?)$/.test(f.path)
+test('opts the product route into Instant Validation', () => {
+ expect(productRouteSource).toMatch(
+ /export\s+const\s+instant\s*=\s*(?:true|\{[\s\S]*?level\s*:\s*['"]warning['"][\s\S]*?\})/
)
+})
- expect(productPage).toBeDefined()
- expect(productPage!.content).toMatch(/export\s+(const|var|let)\s+instant\b/)
- expect(productPage!.content).toMatch(/prefetch\s*:\s*['"]static['"]/)
+test('keeps the title in the shell while live inventory streams', async () => {
+ await expect(environment).toSatisfyCriterion(
+ `The product route must produce meaningful instant UI with Cache Components, without relying on Partial Prefetching.
+
+The product title "Premium Widget" must render in the product page's static shell, outside the Suspense boundary that contains the live inventory. The inventory count and price must render from an async child beneath that Suspense boundary, so the page returns its title and fallback without waiting for getInventory(). The runtime boundary in getInventory(), such as connection(), must be preserved; do not cache the randomized inventory or replace it with static values.
+
+Accept equivalent component and file organization. Reject solutions where the page awaits inventory before returning, the title is hidden behind the inventory boundary, the live inventory is cached, or Partial Prefetching is used as a substitute for a valid instant shell.`
+ )
})
diff --git a/evals/evals/agent-040-instant/PROMPT.md b/evals/evals/agent-040-instant/PROMPT.md
index f8cf59cb0706..1cd2ea323df6 100644
--- a/evals/evals/agent-040-instant/PROMPT.md
+++ b/evals/evals/agent-040-instant/PROMPT.md
@@ -1 +1 @@
-Navigating from home to the product page is slow. The title should appear immediately.
+Navigating from home to the product page is slow. Make the product title appear immediately while the live inventory loads, and have Next.js keep validating that this navigation stays instant.
diff --git a/evals/evals/agent-044-prefetch-until-navigation/EVAL.ts b/evals/evals/agent-044-prefetch-until-navigation/EVAL.ts
new file mode 100644
index 000000000000..922e1394fa3c
--- /dev/null
+++ b/evals/evals/agent-044-prefetch-until-navigation/EVAL.ts
@@ -0,0 +1,80 @@
+/**
+ * Prefetch until navigation
+ *
+ * Verifies that the agent uses Partial Prefetching to include a selected
+ * project's title in a per-link prefetch while deferring the rest of the
+ * project page until navigation.
+ */
+
+import { expect, test } from 'vitest'
+import { existsSync, readFileSync, readdirSync, statSync } from 'fs'
+import { join } from 'path'
+import { environment } from '@vercel/agent-eval/eval'
+
+const IGNORE_DIRS = new Set([
+ '.git',
+ '.next',
+ 'node_modules',
+ 'dist',
+ 'build',
+ 'coverage',
+])
+
+const IGNORE_FILES = new Set(['EVAL.ts', 'PROMPT.md'])
+
+function stripComments(source: string): string {
+ return source.replace(/\/\*[\s\S]*?\*\//g, '').replace(/\/\/.*$/gm, '')
+}
+
+function readSourceFiles(dir: string): string[] {
+ if (!existsSync(dir)) return []
+
+ const files: string[] = []
+ for (const entry of readdirSync(dir)) {
+ if (IGNORE_DIRS.has(entry)) continue
+
+ const fullPath = join(dir, entry)
+ const stats = statSync(fullPath)
+ if (stats.isDirectory()) {
+ files.push(...readSourceFiles(fullPath))
+ } else if (!IGNORE_FILES.has(entry) && /\.(ts|tsx|js|jsx)$/.test(entry)) {
+ files.push(stripComments(readFileSync(fullPath, 'utf-8')))
+ }
+ }
+
+ return files
+}
+
+const source = readSourceFiles(process.cwd()).join('\n---FILE---\n')
+const config = stripComments(
+ readFileSync(join(process.cwd(), 'next.config.ts'), 'utf-8')
+)
+
+test('enables Partial Prefetching globally or for the project route', () => {
+ expect(
+ /partialPrefetching\s*:\s*true/.test(config) ||
+ /export\s+const\s+prefetch\s*=\s*['"]partial['"]/.test(source)
+ ).toBe(true)
+})
+
+test('uses the navigation cache stage', () => {
+ const navigationImport = source.match(
+ /\bunstable_navigation(?:\s+as\s+([A-Za-z_$][\w$]*))?/
+ )
+ expect(navigationImport).not.toBeNull()
+
+ const localName = navigationImport?.[1] ?? 'unstable_navigation'
+ expect(source).toMatch(new RegExp(`await\\s+${localName}\\s*\\(`))
+})
+
+test('the title is prefetched and project details wait for navigation', async () => {
+ await expect(environment).toSatisfyCriterion(
+ `The implementation must make the selected project's title available before the click without prefetching the rest of the project page.
+
+A correct solution uses Partial Prefetching globally or on the project destination, and opts the dashboard's project Link into a per-link prefetch with prefetch={true}. The project route keeps its params-dependent title inside Suspense so the reusable App Shell can show a fallback while the per-link prefetch resolves the title.
+
+The rendered project title must appear before a nested Suspense boundary. Inside that boundary, an async component must await unstable_navigation() before it loads or renders the project activity, deployments, description, or other detail content. The unstable_navigation() call must be outside any use cache scope; cached data functions may be called after it.
+
+Accept equivalent component and file organization. Reject solutions that put the title behind unstable_navigation(), fetch project details before reaching unstable_navigation(), replace unstable_navigation() with connection() or an uncached fetch, disable prefetching, or prefetch the entire page.`
+ )
+})
diff --git a/evals/evals/agent-044-prefetch-until-navigation/PROMPT.md b/evals/evals/agent-044-prefetch-until-navigation/PROMPT.md
new file mode 100644
index 000000000000..2aae89c2e3b1
--- /dev/null
+++ b/evals/evals/agent-044-prefetch-until-navigation/PROMPT.md
@@ -0,0 +1 @@
+When navigating from the dashboard to a project, I want the project's title to appear instantly, but I don't want to prefetch the rest of the project page.
diff --git a/evals/evals/agent-044-prefetch-until-navigation/app/layout.tsx b/evals/evals/agent-044-prefetch-until-navigation/app/layout.tsx
new file mode 100644
index 000000000000..7309bb5579ad
--- /dev/null
+++ b/evals/evals/agent-044-prefetch-until-navigation/app/layout.tsx
@@ -0,0 +1,18 @@
+import type { Metadata } from 'next'
+
+export const metadata: Metadata = {
+ title: 'Projects',
+ description: 'Project dashboard',
+}
+
+export default function RootLayout({
+ children,
+}: Readonly<{
+ children: React.ReactNode
+}>) {
+ return (
+
+ {children}
+
+ )
+}
diff --git a/evals/evals/agent-044-prefetch-until-navigation/app/page.tsx b/evals/evals/agent-044-prefetch-until-navigation/app/page.tsx
new file mode 100644
index 000000000000..8e4bcaee437c
--- /dev/null
+++ b/evals/evals/agent-044-prefetch-until-navigation/app/page.tsx
@@ -0,0 +1,21 @@
+import Link from 'next/link'
+
+const projects = [
+ { slug: 'acme', name: 'Acme Storefront' },
+ { slug: 'orbit', name: 'Orbit Analytics' },
+]
+
+export default function Dashboard() {
+ return (
+
+
}
diff --git a/evals/evals/agent-048-cache-components-config-semantics/app/preview/page.tsx b/evals/evals/agent-042-enable-ppr/app/preview/page.tsx
similarity index 100%
rename from evals/evals/agent-048-cache-components-config-semantics/app/preview/page.tsx
rename to evals/evals/agent-042-enable-ppr/app/preview/page.tsx
diff --git a/evals/evals/agent-042-enable-ppr/next.config.ts b/evals/evals/agent-042-enable-ppr/next.config.ts
index e4f5738a310b..5c906c55af96 100644
--- a/evals/evals/agent-042-enable-ppr/next.config.ts
+++ b/evals/evals/agent-042-enable-ppr/next.config.ts
@@ -1,5 +1,10 @@
import type { NextConfig } from 'next'
-const nextConfig: NextConfig = {}
+const nextConfig: NextConfig = {
+ experimental: {
+ // @ts-expect-error -- legacy config retained for the migration exercise
+ dynamicIO: true,
+ },
+}
export default nextConfig
diff --git a/evals/evals/agent-042-enable-ppr/tsconfig.json b/evals/evals/agent-042-enable-ppr/tsconfig.json
index 00978ef407fd..cc321ed0658b 100644
--- a/evals/evals/agent-042-enable-ppr/tsconfig.json
+++ b/evals/evals/agent-042-enable-ppr/tsconfig.json
@@ -23,5 +23,5 @@
}
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
- "exclude": ["node_modules"]
+ "exclude": ["node_modules", "EVAL.ts"]
}
diff --git a/evals/evals/agent-048-cache-components-config-semantics/EVAL.ts b/evals/evals/agent-048-cache-components-config-semantics/EVAL.ts
deleted file mode 100644
index 27879531129b..000000000000
--- a/evals/evals/agent-048-cache-components-config-semantics/EVAL.ts
+++ /dev/null
@@ -1,46 +0,0 @@
-/**
- * Cache Components: route config semantics
- *
- * Verifies that adoption translates legacy configuration instead of deleting
- * behavior or silencing validation.
- */
-
-import { expect, test } from 'vitest'
-import { existsSync, readFileSync, readdirSync, statSync } from 'fs'
-import { join } from 'path'
-import { environment } from '@vercel/agent-eval/eval'
-
-const IGNORE_DIRS = new Set(['.git', '.next', 'node_modules', 'dist', 'build'])
-
-function readSource(dir: string): string[] {
- if (!existsSync(dir)) return []
- return readdirSync(dir).flatMap((entry) => {
- if (IGNORE_DIRS.has(entry)) return []
- const path = join(dir, entry)
- if (statSync(path).isDirectory()) return readSource(path)
- if (entry === 'EVAL.ts' || !/\.(ts|tsx|js|jsx)$/.test(entry)) return []
- return readFileSync(path, 'utf8')
- })
-}
-
-const source = readSource(process.cwd()).join('\n')
-const config = readFileSync(join(process.cwd(), 'next.config.ts'), 'utf8')
-
-test('enables the current Cache Components config only', () => {
- expect(config).toMatch(/cacheComponents\s*:\s*true/)
- expect(config).not.toMatch(/dynamicIO\s*:/)
- expect(config).not.toMatch(/useCache\s*:/)
-})
-
-test('removes route opt-outs and incompatible segment config', () => {
- expect(source).not.toMatch(/export\s+(?:const|var|let)\s+instant\s*=\s*false/)
- expect(source).not.toMatch(
- /export\s+(?:const|var|let)\s+(?:dynamic|revalidate|fetchCache)\s*=/
- )
-})
-
-test('preserves the hourly feed and request-specific preview', async () => {
- await expect(environment).toSatisfyCriterion(
- `The newsroom feed is cached with an explicit approximately-hourly cache lifetime. A focused data-level cache is valid, and a page-level cache is also valid because the Newsroom page contains only the feed and stable framing with the same lifetime. The editor preview still reads its cookie at request time outside any public cache, is placed below Suspense or equivalent meaningful loading UI, and leaves useful stable preview framing in the static shell.`
- )
-})
diff --git a/evals/evals/agent-048-cache-components-config-semantics/PROMPT.md b/evals/evals/agent-048-cache-components-config-semantics/PROMPT.md
deleted file mode 100644
index 97820f8fcf1b..000000000000
--- a/evals/evals/agent-048-cache-components-config-semantics/PROMPT.md
+++ /dev/null
@@ -1 +0,0 @@
-Move this publishing app to Cache Components in one branch. Keep the newsroom feed on its hourly refresh policy and keep editor preview request-specific. Finish with a production build without leaving routes opted out.
diff --git a/evals/evals/agent-048-cache-components-config-semantics/app/layout.tsx b/evals/evals/agent-048-cache-components-config-semantics/app/layout.tsx
deleted file mode 100644
index 91cd6a8db4a9..000000000000
--- a/evals/evals/agent-048-cache-components-config-semantics/app/layout.tsx
+++ /dev/null
@@ -1,16 +0,0 @@
-import Link from 'next/link'
-import type { ReactNode } from 'react'
-
-export default function RootLayout({ children }: { children: ReactNode }) {
- return (
-
-
-
- {children}
-
-
- )
-}
diff --git a/evals/evals/agent-048-cache-components-config-semantics/app/page.tsx b/evals/evals/agent-048-cache-components-config-semantics/app/page.tsx
deleted file mode 100644
index 89fbd7e29342..000000000000
--- a/evals/evals/agent-048-cache-components-config-semantics/app/page.tsx
+++ /dev/null
@@ -1,3 +0,0 @@
-export default function HomePage() {
- return
Northstar Publishing
-}
diff --git a/evals/evals/agent-048-cache-components-config-semantics/next-env.d.ts b/evals/evals/agent-048-cache-components-config-semantics/next-env.d.ts
deleted file mode 100644
index 1b3be0840f3f..000000000000
--- a/evals/evals/agent-048-cache-components-config-semantics/next-env.d.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-///
-///
-
-// NOTE: This file should not be edited
-// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
diff --git a/evals/evals/agent-048-cache-components-config-semantics/next.config.ts b/evals/evals/agent-048-cache-components-config-semantics/next.config.ts
deleted file mode 100644
index 5c906c55af96..000000000000
--- a/evals/evals/agent-048-cache-components-config-semantics/next.config.ts
+++ /dev/null
@@ -1,10 +0,0 @@
-import type { NextConfig } from 'next'
-
-const nextConfig: NextConfig = {
- experimental: {
- // @ts-expect-error -- legacy config retained for the migration exercise
- dynamicIO: true,
- },
-}
-
-export default nextConfig
diff --git a/evals/evals/agent-048-cache-components-config-semantics/package.json b/evals/evals/agent-048-cache-components-config-semantics/package.json
deleted file mode 100644
index 7056dd9ed5f9..000000000000
--- a/evals/evals/agent-048-cache-components-config-semantics/package.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
- "private": true,
- "type": "module",
- "scripts": {
- "dev": "next dev",
- "build": "next build",
- "start": "next start"
- },
- "dependencies": {
- "next": "^16",
- "react": "19.1.0",
- "react-dom": "19.1.0"
- },
- "devDependencies": {
- "@types/node": "^20",
- "@types/react": "^19",
- "@types/react-dom": "^19",
- "typescript": "^5",
- "vitest": "^3.1.3",
- "@vitejs/plugin-react": "^4.4.1",
- "vite-tsconfig-paths": "^5.1.4"
- }
-}
diff --git a/evals/evals/agent-048-cache-components-config-semantics/tsconfig.json b/evals/evals/agent-048-cache-components-config-semantics/tsconfig.json
deleted file mode 100644
index e32fb699a1b0..000000000000
--- a/evals/evals/agent-048-cache-components-config-semantics/tsconfig.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
- "compilerOptions": {
- "target": "ES2017",
- "lib": ["dom", "dom.iterable", "esnext"],
- "allowJs": true,
- "skipLibCheck": true,
- "strict": true,
- "noEmit": true,
- "esModuleInterop": true,
- "module": "esnext",
- "moduleResolution": "bundler",
- "resolveJsonModule": true,
- "isolatedModules": true,
- "jsx": "react-jsx",
- "incremental": true,
- "plugins": [{ "name": "next" }],
- "paths": { "@/*": ["./*"] }
- },
- "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
- "exclude": ["node_modules", "EVAL.ts"]
-}
diff --git a/evals/evals/agent-051-cache-components-sync-io/EVAL.ts b/evals/evals/agent-051-cache-components-sync-io/EVAL.ts
deleted file mode 100644
index 45388a3d8e5a..000000000000
--- a/evals/evals/agent-051-cache-components-sync-io/EVAL.ts
+++ /dev/null
@@ -1,38 +0,0 @@
-/** Cache Components: synchronous request-time I/O in shared UI. */
-
-import { expect, test } from 'vitest'
-import { existsSync, readFileSync, readdirSync, statSync } from 'fs'
-import { join } from 'path'
-import { environment } from '@vercel/agent-eval/eval'
-
-const IGNORE_DIRS = new Set(['.git', '.next', 'node_modules', 'dist', 'build'])
-
-function readSource(dir: string): string[] {
- if (!existsSync(dir)) return []
- return readdirSync(dir).flatMap((entry) => {
- if (IGNORE_DIRS.has(entry)) return []
- const path = join(dir, entry)
- if (statSync(path).isDirectory()) return readSource(path)
- if (entry === 'EVAL.ts' || !/\.(ts|tsx|js|jsx)$/.test(entry)) return []
- return readFileSync(path, 'utf8')
- })
-}
-
-const source = readSource(process.cwd()).join('\n')
-const config = readFileSync(join(process.cwd(), 'next.config.ts'), 'utf8')
-
-test('enables Cache Components without opt-outs', () => {
- expect(config).toMatch(/cacheComponents\s*:\s*true/)
- expect(source).not.toMatch(/export\s+(?:const|var|let)\s+instant\s*=\s*false/)
-})
-
-test('uses an explicit synchronous I/O boundary', () => {
- expect(source).toMatch(/\b(?:io|connection)\s*\(/)
- expect(source).toMatch(/]/)
-})
-
-test('preserves fresh metadata without sacrificing the shared frame', async () => {
- await expect(environment).toSatisfyCriterion(
- `The stable Operations navigation and page frame remain outside the Suspense boundary. The request metadata is rendered in a focused async child that awaits io() or connection() before calling new Date or Date.now, Math.random, and randomUUID, so those values remain request-specific. The metadata subtree is not cached or evaluated at module scope, and it has meaningful loading UI. Prefer io() unless the implementation specifically needs to wait for a real user request.`
- )
-})
diff --git a/evals/evals/agent-051-cache-components-sync-io/PROMPT.md b/evals/evals/agent-051-cache-components-sync-io/PROMPT.md
deleted file mode 100644
index bfb437bc2894..000000000000
--- a/evals/evals/agent-051-cache-components-sync-io/PROMPT.md
+++ /dev/null
@@ -1 +0,0 @@
-Enable Cache Components for this operations console. The navigation must stay immediately useful, while the request identifier, current time, and sampling value must still be generated per request. Finish with a production build and do not leave routes opted out.
diff --git a/evals/evals/agent-051-cache-components-sync-io/app/layout.tsx b/evals/evals/agent-051-cache-components-sync-io/app/layout.tsx
deleted file mode 100644
index 03a7ce6ef914..000000000000
--- a/evals/evals/agent-051-cache-components-sync-io/app/layout.tsx
+++ /dev/null
@@ -1,14 +0,0 @@
-import type { ReactNode } from 'react'
-import { RequestMetadata } from '@/components/request-metadata'
-
-export default function RootLayout({ children }: { children: ReactNode }) {
- return (
-
-
-
-
- {children}
-
-
- )
-}
diff --git a/evals/evals/agent-051-cache-components-sync-io/app/page.tsx b/evals/evals/agent-051-cache-components-sync-io/app/page.tsx
deleted file mode 100644
index 20adbd86f3fd..000000000000
--- a/evals/evals/agent-051-cache-components-sync-io/app/page.tsx
+++ /dev/null
@@ -1,8 +0,0 @@
-export default function HomePage() {
- return (
-
-
Deployment health
-
All systems operational
-
- )
-}
diff --git a/evals/evals/agent-051-cache-components-sync-io/next-env.d.ts b/evals/evals/agent-051-cache-components-sync-io/next-env.d.ts
deleted file mode 100644
index 1b3be0840f3f..000000000000
--- a/evals/evals/agent-051-cache-components-sync-io/next-env.d.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-///
-///
-
-// NOTE: This file should not be edited
-// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
diff --git a/evals/evals/agent-051-cache-components-sync-io/next.config.ts b/evals/evals/agent-051-cache-components-sync-io/next.config.ts
deleted file mode 100644
index e4f5738a310b..000000000000
--- a/evals/evals/agent-051-cache-components-sync-io/next.config.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-import type { NextConfig } from 'next'
-
-const nextConfig: NextConfig = {}
-
-export default nextConfig
diff --git a/evals/evals/agent-051-cache-components-sync-io/package.json b/evals/evals/agent-051-cache-components-sync-io/package.json
deleted file mode 100644
index 7056dd9ed5f9..000000000000
--- a/evals/evals/agent-051-cache-components-sync-io/package.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
- "private": true,
- "type": "module",
- "scripts": {
- "dev": "next dev",
- "build": "next build",
- "start": "next start"
- },
- "dependencies": {
- "next": "^16",
- "react": "19.1.0",
- "react-dom": "19.1.0"
- },
- "devDependencies": {
- "@types/node": "^20",
- "@types/react": "^19",
- "@types/react-dom": "^19",
- "typescript": "^5",
- "vitest": "^3.1.3",
- "@vitejs/plugin-react": "^4.4.1",
- "vite-tsconfig-paths": "^5.1.4"
- }
-}
diff --git a/evals/evals/agent-051-cache-components-sync-io/tsconfig.json b/evals/evals/agent-051-cache-components-sync-io/tsconfig.json
deleted file mode 100644
index e32fb699a1b0..000000000000
--- a/evals/evals/agent-051-cache-components-sync-io/tsconfig.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
- "compilerOptions": {
- "target": "ES2017",
- "lib": ["dom", "dom.iterable", "esnext"],
- "allowJs": true,
- "skipLibCheck": true,
- "strict": true,
- "noEmit": true,
- "esModuleInterop": true,
- "module": "esnext",
- "moduleResolution": "bundler",
- "resolveJsonModule": true,
- "isolatedModules": true,
- "jsx": "react-jsx",
- "incremental": true,
- "plugins": [{ "name": "next" }],
- "paths": { "@/*": ["./*"] }
- },
- "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
- "exclude": ["node_modules", "EVAL.ts"]
-}
From d60f307f8a9b1f131b892fda654a93dacd8a7ae9 Mon Sep 17 00:00:00 2001
From: Aurora Scharff
Date: Mon, 31 Aug 2026 21:06:23 +0200
Subject: [PATCH 08/10] evals: split focused success criteria
---
.../agent-035-connection-dynamic/EVAL.ts | 16 +++++-
evals/evals/agent-040-instant/EVAL.ts | 30 +++++++++--
evals/evals/agent-042-enable-ppr/EVAL.ts | 10 +++-
.../EVAL.ts | 0
.../PROMPT.md | 0
.../app/catalog/page.tsx | 0
.../app/layout.tsx | 0
.../app/page.tsx | 0
.../lib/data.ts | 0
.../next.config.ts | 0
.../package.json | 0
.../tsconfig.json | 0
.../EVAL.ts | 14 +++--
.../PROMPT.md | 0
.../app/layout.tsx | 0
.../app/page.tsx | 0
.../app/product/page.tsx | 0
.../lib/data.ts | 0
.../next.config.ts | 0
.../package.json | 0
.../tsconfig.json | 0
.../EVAL.ts | 33 ------------
.../EVAL.ts | 18 +++++--
.../PROMPT.md | 0
.../app/layout.tsx | 0
.../app/page.tsx | 0
.../app/projects/[slug]/page.tsx | 0
.../lib/data.ts | 0
.../next.config.ts | 0
.../package.json | 0
.../tsconfig.json | 0
.../EVAL.ts | 16 +++++-
.../PROMPT.md | 0
.../app/layout.tsx | 0
.../app/page.tsx | 0
.../lib/projects.ts | 0
.../next-env.d.ts | 0
.../next.config.ts | 0
.../package.json | 0
.../tsconfig.json | 0
.../EVAL.ts | 51 +++++++++++++++++++
.../PROMPT.md | 0
.../app/layout.tsx | 0
.../app/page.tsx | 0
.../app/products/[slug]/page.tsx | 0
.../lib/products.ts | 0
.../next-env.d.ts | 0
.../next.config.ts | 0
.../package.json | 0
.../tsconfig.json | 0
50 files changed, 136 insertions(+), 52 deletions(-)
rename evals/evals/{agent-044-prefetch-url-data => agent-048-prefetch-url-data}/EVAL.ts (100%)
rename evals/evals/{agent-044-prefetch-url-data => agent-048-prefetch-url-data}/PROMPT.md (100%)
rename evals/evals/{agent-044-prefetch-url-data => agent-048-prefetch-url-data}/app/catalog/page.tsx (100%)
rename evals/evals/{agent-044-prefetch-url-data => agent-048-prefetch-url-data}/app/layout.tsx (100%)
rename evals/evals/{agent-044-prefetch-url-data => agent-048-prefetch-url-data}/app/page.tsx (100%)
rename evals/evals/{agent-044-prefetch-url-data => agent-048-prefetch-url-data}/lib/data.ts (100%)
rename evals/evals/{agent-044-prefetch-url-data => agent-048-prefetch-url-data}/next.config.ts (100%)
rename evals/evals/{agent-044-prefetch-url-data => agent-048-prefetch-url-data}/package.json (100%)
rename evals/evals/{agent-044-prefetch-url-data => agent-048-prefetch-url-data}/tsconfig.json (100%)
rename evals/evals/{agent-045-prefetch-stage => agent-049-prefetch-stage}/EVAL.ts (63%)
rename evals/evals/{agent-045-prefetch-stage => agent-049-prefetch-stage}/PROMPT.md (100%)
rename evals/evals/{agent-045-prefetch-stage => agent-049-prefetch-stage}/app/layout.tsx (100%)
rename evals/evals/{agent-045-prefetch-stage => agent-049-prefetch-stage}/app/page.tsx (100%)
rename evals/evals/{agent-045-prefetch-stage => agent-049-prefetch-stage}/app/product/page.tsx (100%)
rename evals/evals/{agent-045-prefetch-stage => agent-049-prefetch-stage}/lib/data.ts (100%)
rename evals/evals/{agent-045-prefetch-stage => agent-049-prefetch-stage}/next.config.ts (100%)
rename evals/evals/{agent-045-prefetch-stage => agent-049-prefetch-stage}/package.json (100%)
rename evals/evals/{agent-045-prefetch-stage => agent-049-prefetch-stage}/tsconfig.json (100%)
delete mode 100644 evals/evals/agent-050-cache-components-url-shell/EVAL.ts
rename evals/evals/{agent-046-prefetch-until-navigation => agent-051-prefetch-until-navigation}/EVAL.ts (59%)
rename evals/evals/{agent-046-prefetch-until-navigation => agent-051-prefetch-until-navigation}/PROMPT.md (100%)
rename evals/evals/{agent-046-prefetch-until-navigation => agent-051-prefetch-until-navigation}/app/layout.tsx (100%)
rename evals/evals/{agent-046-prefetch-until-navigation => agent-051-prefetch-until-navigation}/app/page.tsx (100%)
rename evals/evals/{agent-046-prefetch-until-navigation => agent-051-prefetch-until-navigation}/app/projects/[slug]/page.tsx (100%)
rename evals/evals/{agent-046-prefetch-until-navigation => agent-051-prefetch-until-navigation}/lib/data.ts (100%)
rename evals/evals/{agent-046-prefetch-until-navigation => agent-051-prefetch-until-navigation}/next.config.ts (100%)
rename evals/evals/{agent-046-prefetch-until-navigation => agent-051-prefetch-until-navigation}/package.json (100%)
rename evals/evals/{agent-046-prefetch-until-navigation => agent-051-prefetch-until-navigation}/tsconfig.json (100%)
rename evals/evals/{agent-049-cache-components-session-isolation => agent-052-cache-components-session-isolation}/EVAL.ts (50%)
rename evals/evals/{agent-049-cache-components-session-isolation => agent-052-cache-components-session-isolation}/PROMPT.md (100%)
rename evals/evals/{agent-049-cache-components-session-isolation => agent-052-cache-components-session-isolation}/app/layout.tsx (100%)
rename evals/evals/{agent-049-cache-components-session-isolation => agent-052-cache-components-session-isolation}/app/page.tsx (100%)
rename evals/evals/{agent-049-cache-components-session-isolation => agent-052-cache-components-session-isolation}/lib/projects.ts (100%)
rename evals/evals/{agent-049-cache-components-session-isolation => agent-052-cache-components-session-isolation}/next-env.d.ts (100%)
rename evals/evals/{agent-049-cache-components-session-isolation => agent-052-cache-components-session-isolation}/next.config.ts (100%)
rename evals/evals/{agent-049-cache-components-session-isolation => agent-052-cache-components-session-isolation}/package.json (100%)
rename evals/evals/{agent-049-cache-components-session-isolation => agent-052-cache-components-session-isolation}/tsconfig.json (100%)
create mode 100644 evals/evals/agent-053-cache-components-url-shell/EVAL.ts
rename evals/evals/{agent-050-cache-components-url-shell => agent-053-cache-components-url-shell}/PROMPT.md (100%)
rename evals/evals/{agent-050-cache-components-url-shell => agent-053-cache-components-url-shell}/app/layout.tsx (100%)
rename evals/evals/{agent-050-cache-components-url-shell => agent-053-cache-components-url-shell}/app/page.tsx (100%)
rename evals/evals/{agent-050-cache-components-url-shell => agent-053-cache-components-url-shell}/app/products/[slug]/page.tsx (100%)
rename evals/evals/{agent-050-cache-components-url-shell => agent-053-cache-components-url-shell}/lib/products.ts (100%)
rename evals/evals/{agent-050-cache-components-url-shell => agent-053-cache-components-url-shell}/next-env.d.ts (100%)
rename evals/evals/{agent-050-cache-components-url-shell => agent-053-cache-components-url-shell}/next.config.ts (100%)
rename evals/evals/{agent-050-cache-components-url-shell => agent-053-cache-components-url-shell}/package.json (100%)
rename evals/evals/{agent-050-cache-components-url-shell => agent-053-cache-components-url-shell}/tsconfig.json (100%)
diff --git a/evals/evals/agent-035-connection-dynamic/EVAL.ts b/evals/evals/agent-035-connection-dynamic/EVAL.ts
index 45388a3d8e5a..bce8d5893893 100644
--- a/evals/evals/agent-035-connection-dynamic/EVAL.ts
+++ b/evals/evals/agent-035-connection-dynamic/EVAL.ts
@@ -31,8 +31,20 @@ test('uses an explicit synchronous I/O boundary', () => {
expect(source).toMatch(/]/)
})
-test('preserves fresh metadata without sacrificing the shared frame', async () => {
+test('keeps the operations frame useful while metadata loads', async () => {
await expect(environment).toSatisfyCriterion(
- `The stable Operations navigation and page frame remain outside the Suspense boundary. The request metadata is rendered in a focused async child that awaits io() or connection() before calling new Date or Date.now, Math.random, and randomUUID, so those values remain request-specific. The metadata subtree is not cached or evaluated at module scope, and it has meaningful loading UI. Prefer io() unless the implementation specifically needs to wait for a real user request.`
+ `The stable Operations navigation and page frame must remain outside the Suspense boundary used for request metadata. The boundary must provide visible, meaningful loading UI rather than a null or empty fallback. Accept equivalent component and file organization.`
+ )
+})
+
+test('keeps request metadata fresh', async () => {
+ await expect(environment).toSatisfyCriterion(
+ `The request identifier, current time, and sampling value must remain request-specific. Render them in a focused async child that awaits io() or connection() before calling randomUUID, new Date or Date.now, and Math.random. Prefer io() unless the implementation specifically needs to wait for a real user request. Accept equivalent component and file organization.`
+ )
+})
+
+test('does not reuse request metadata', async () => {
+ await expect(environment).toSatisfyCriterion(
+ `The request identifier, current time, and sampling value must not be cached, evaluated at module scope, or replaced with static values. Reject any solution that can reuse those values across requests. Accept equivalent component and file organization.`
)
})
diff --git a/evals/evals/agent-040-instant/EVAL.ts b/evals/evals/agent-040-instant/EVAL.ts
index a6ca887659e3..aceef5bb71d6 100644
--- a/evals/evals/agent-040-instant/EVAL.ts
+++ b/evals/evals/agent-040-instant/EVAL.ts
@@ -10,12 +10,34 @@
import { expect, test } from 'vitest'
import { environment } from '@vercel/agent-eval/eval'
-test('keeps the title in the shell while live inventory streams', async () => {
+test('keeps the product title in the static shell', async () => {
await expect(environment).toSatisfyCriterion(
- `The product route must produce meaningful instant UI with Cache Components, without relying on Partial Prefetching.
+ `The product title "Premium Widget" must render in the product page's static shell. It must remain outside the Suspense boundary and async work used for the live inventory, so the title is available before the inventory resolves.
-The product title "Premium Widget" must render in the product page's static shell, outside the Suspense boundary that contains the live inventory. The inventory count and price must render from an async child beneath that Suspense boundary, so the page returns its title and fallback without waiting for getInventory(). The runtime boundary in getInventory(), such as connection(), must be preserved; do not cache the randomized inventory or replace it with static values. Keep the framework's default validation enabled; do not add instant = false to suppress the insight.
+Accept equivalent component and file organization. Reject solutions where the page awaits the inventory before returning or places the title behind the inventory boundary.`
+ )
+})
+
+test('streams inventory behind a meaningful fallback', async () => {
+ await expect(environment).toSatisfyCriterion(
+ `The inventory count and price must render from an async child beneath a Suspense boundary with a visible, meaningful fallback. The product page must be able to return its title and fallback without waiting for getInventory().
+
+Accept equivalent component and file organization. Reject a null or empty fallback, or a solution where the page awaits inventory before returning.`
+ )
+})
+
+test('keeps inventory live and uncached', async () => {
+ await expect(environment).toSatisfyCriterion(
+ `The randomized inventory must remain request-time data. Preserve the runtime boundary in getInventory(), such as connection(), and do not cache the inventory or replace its count and price with static values.
+
+Accept equivalent component and file organization. Reject any solution that makes the randomized inventory reusable across requests.`
+ )
+})
+
+test('keeps default instant validation enabled', async () => {
+ await expect(environment).toSatisfyCriterion(
+ `The solution must keep the framework's default instant validation enabled and solve the static-shell problem directly. It must not add instant = false, disable Cache Components, or use Partial Prefetching as a substitute for a valid product shell.
-Accept equivalent component and file organization. Reject solutions where the page awaits inventory before returning, the title is hidden behind the inventory boundary, the live inventory is cached, or Partial Prefetching is used as a substitute for a valid instant shell.`
+Accept equivalent component and file organization.`
)
})
diff --git a/evals/evals/agent-042-enable-ppr/EVAL.ts b/evals/evals/agent-042-enable-ppr/EVAL.ts
index 27879531129b..ff209bf284f9 100644
--- a/evals/evals/agent-042-enable-ppr/EVAL.ts
+++ b/evals/evals/agent-042-enable-ppr/EVAL.ts
@@ -39,8 +39,14 @@ test('removes route opt-outs and incompatible segment config', () => {
)
})
-test('preserves the hourly feed and request-specific preview', async () => {
+test('preserves the hourly newsroom feed', async () => {
await expect(environment).toSatisfyCriterion(
- `The newsroom feed is cached with an explicit approximately-hourly cache lifetime. A focused data-level cache is valid, and a page-level cache is also valid because the Newsroom page contains only the feed and stable framing with the same lifetime. The editor preview still reads its cookie at request time outside any public cache, is placed below Suspense or equivalent meaningful loading UI, and leaves useful stable preview framing in the static shell.`
+ `The newsroom feed must remain cached with an explicit approximately-hourly cache lifetime. A focused data-level cache is valid, and a page-level cache is also valid because the Newsroom page contains only the feed and stable framing with the same lifetime. Reject solutions that remove or materially change the feed's hourly refresh behavior.`
+ )
+})
+
+test('keeps editor preview request-specific', async () => {
+ await expect(environment).toSatisfyCriterion(
+ `The editor preview must still read its cookie at request time outside every public cache. Place the request-specific preview below Suspense or equivalent meaningful loading UI while leaving useful stable preview framing in the static shell. Reject solutions that cache the cookie value, hide the entire preview page behind one fallback, or remove the request-specific behavior.`
)
})
diff --git a/evals/evals/agent-044-prefetch-url-data/EVAL.ts b/evals/evals/agent-048-prefetch-url-data/EVAL.ts
similarity index 100%
rename from evals/evals/agent-044-prefetch-url-data/EVAL.ts
rename to evals/evals/agent-048-prefetch-url-data/EVAL.ts
diff --git a/evals/evals/agent-044-prefetch-url-data/PROMPT.md b/evals/evals/agent-048-prefetch-url-data/PROMPT.md
similarity index 100%
rename from evals/evals/agent-044-prefetch-url-data/PROMPT.md
rename to evals/evals/agent-048-prefetch-url-data/PROMPT.md
diff --git a/evals/evals/agent-044-prefetch-url-data/app/catalog/page.tsx b/evals/evals/agent-048-prefetch-url-data/app/catalog/page.tsx
similarity index 100%
rename from evals/evals/agent-044-prefetch-url-data/app/catalog/page.tsx
rename to evals/evals/agent-048-prefetch-url-data/app/catalog/page.tsx
diff --git a/evals/evals/agent-044-prefetch-url-data/app/layout.tsx b/evals/evals/agent-048-prefetch-url-data/app/layout.tsx
similarity index 100%
rename from evals/evals/agent-044-prefetch-url-data/app/layout.tsx
rename to evals/evals/agent-048-prefetch-url-data/app/layout.tsx
diff --git a/evals/evals/agent-044-prefetch-url-data/app/page.tsx b/evals/evals/agent-048-prefetch-url-data/app/page.tsx
similarity index 100%
rename from evals/evals/agent-044-prefetch-url-data/app/page.tsx
rename to evals/evals/agent-048-prefetch-url-data/app/page.tsx
diff --git a/evals/evals/agent-044-prefetch-url-data/lib/data.ts b/evals/evals/agent-048-prefetch-url-data/lib/data.ts
similarity index 100%
rename from evals/evals/agent-044-prefetch-url-data/lib/data.ts
rename to evals/evals/agent-048-prefetch-url-data/lib/data.ts
diff --git a/evals/evals/agent-044-prefetch-url-data/next.config.ts b/evals/evals/agent-048-prefetch-url-data/next.config.ts
similarity index 100%
rename from evals/evals/agent-044-prefetch-url-data/next.config.ts
rename to evals/evals/agent-048-prefetch-url-data/next.config.ts
diff --git a/evals/evals/agent-044-prefetch-url-data/package.json b/evals/evals/agent-048-prefetch-url-data/package.json
similarity index 100%
rename from evals/evals/agent-044-prefetch-url-data/package.json
rename to evals/evals/agent-048-prefetch-url-data/package.json
diff --git a/evals/evals/agent-044-prefetch-url-data/tsconfig.json b/evals/evals/agent-048-prefetch-url-data/tsconfig.json
similarity index 100%
rename from evals/evals/agent-044-prefetch-url-data/tsconfig.json
rename to evals/evals/agent-048-prefetch-url-data/tsconfig.json
diff --git a/evals/evals/agent-045-prefetch-stage/EVAL.ts b/evals/evals/agent-049-prefetch-stage/EVAL.ts
similarity index 63%
rename from evals/evals/agent-045-prefetch-stage/EVAL.ts
rename to evals/evals/agent-049-prefetch-stage/EVAL.ts
index 4cfa4e69eea1..e70d0d4a5018 100644
--- a/evals/evals/agent-045-prefetch-stage/EVAL.ts
+++ b/evals/evals/agent-049-prefetch-stage/EVAL.ts
@@ -70,12 +70,18 @@ test('uses the prefetch cache stage', () => {
expect(source).toMatch(new RegExp(`await\\s+${localName}\\s*\\(`))
})
-test('keeps related products out of the shell but in the selected prefetch', async () => {
+test('keeps stable product content in the reusable shell', async () => {
await expect(environment).toSatisfyCriterion(
- `The implementation must keep the related-products section out of the reusable product App Shell while making it available before navigation from the featured-product Link.
+ `The product title and description must remain in the reusable product App Shell. The related-products section must remain outside that shell, beneath its own Suspense boundary. Reject solutions that put the whole product page behind the prefetch stage or move related products into the App Shell. Accept equivalent component and file organization.`
+ )
+})
+
+test('includes related products only in the selected prefetch', async () => {
+ await expect(environment).toSatisfyCriterion(
+ `The related-products section must be available before navigation from the featured-product Link without joining the default product App Shell.
-A correct solution enables Partial Prefetching globally or on the product route and adds prefetch={true} to the featured-product Link. The product title and description stay in the reusable App Shell. The related-products section is inside Suspense and rendered by an async component that awaits unstable_prefetch() before calling the cached getRelatedProducts() function.
+Render related products through an async component that awaits unstable_prefetch() before calling the cached getRelatedProducts() function. The unstable_prefetch() call must be outside every use cache scope, while the existing cached data function stays below it.
-The unstable_prefetch() call must be outside every use cache scope; the existing cached data function belongs below it. Reject solutions that put the whole product page behind the stage, move related products into the App Shell, replace the stage with connection() or unstable_navigation(), make the related-products data uncached, or defer it until after navigation.`
+Reject solutions that replace the stage with connection() or unstable_navigation(), make the related-products data uncached, or defer it until after navigation. Accept equivalent component and file organization.`
)
})
diff --git a/evals/evals/agent-045-prefetch-stage/PROMPT.md b/evals/evals/agent-049-prefetch-stage/PROMPT.md
similarity index 100%
rename from evals/evals/agent-045-prefetch-stage/PROMPT.md
rename to evals/evals/agent-049-prefetch-stage/PROMPT.md
diff --git a/evals/evals/agent-045-prefetch-stage/app/layout.tsx b/evals/evals/agent-049-prefetch-stage/app/layout.tsx
similarity index 100%
rename from evals/evals/agent-045-prefetch-stage/app/layout.tsx
rename to evals/evals/agent-049-prefetch-stage/app/layout.tsx
diff --git a/evals/evals/agent-045-prefetch-stage/app/page.tsx b/evals/evals/agent-049-prefetch-stage/app/page.tsx
similarity index 100%
rename from evals/evals/agent-045-prefetch-stage/app/page.tsx
rename to evals/evals/agent-049-prefetch-stage/app/page.tsx
diff --git a/evals/evals/agent-045-prefetch-stage/app/product/page.tsx b/evals/evals/agent-049-prefetch-stage/app/product/page.tsx
similarity index 100%
rename from evals/evals/agent-045-prefetch-stage/app/product/page.tsx
rename to evals/evals/agent-049-prefetch-stage/app/product/page.tsx
diff --git a/evals/evals/agent-045-prefetch-stage/lib/data.ts b/evals/evals/agent-049-prefetch-stage/lib/data.ts
similarity index 100%
rename from evals/evals/agent-045-prefetch-stage/lib/data.ts
rename to evals/evals/agent-049-prefetch-stage/lib/data.ts
diff --git a/evals/evals/agent-045-prefetch-stage/next.config.ts b/evals/evals/agent-049-prefetch-stage/next.config.ts
similarity index 100%
rename from evals/evals/agent-045-prefetch-stage/next.config.ts
rename to evals/evals/agent-049-prefetch-stage/next.config.ts
diff --git a/evals/evals/agent-045-prefetch-stage/package.json b/evals/evals/agent-049-prefetch-stage/package.json
similarity index 100%
rename from evals/evals/agent-045-prefetch-stage/package.json
rename to evals/evals/agent-049-prefetch-stage/package.json
diff --git a/evals/evals/agent-045-prefetch-stage/tsconfig.json b/evals/evals/agent-049-prefetch-stage/tsconfig.json
similarity index 100%
rename from evals/evals/agent-045-prefetch-stage/tsconfig.json
rename to evals/evals/agent-049-prefetch-stage/tsconfig.json
diff --git a/evals/evals/agent-050-cache-components-url-shell/EVAL.ts b/evals/evals/agent-050-cache-components-url-shell/EVAL.ts
deleted file mode 100644
index 0ec0cd628412..000000000000
--- a/evals/evals/agent-050-cache-components-url-shell/EVAL.ts
+++ /dev/null
@@ -1,33 +0,0 @@
-/** Cache Components: URL data and shell boundaries. */
-
-import { expect, test } from 'vitest'
-import { existsSync, readFileSync, readdirSync, statSync } from 'fs'
-import { join } from 'path'
-import { environment } from '@vercel/agent-eval/eval'
-
-const IGNORE_DIRS = new Set(['.git', '.next', 'node_modules', 'dist', 'build'])
-
-function readSource(dir: string): string[] {
- if (!existsSync(dir)) return []
- return readdirSync(dir).flatMap((entry) => {
- if (IGNORE_DIRS.has(entry)) return []
- const path = join(dir, entry)
- if (statSync(path).isDirectory()) return readSource(path)
- if (entry === 'EVAL.ts' || !/\.(ts|tsx|js|jsx)$/.test(entry)) return []
- return readFileSync(path, 'utf8')
- })
-}
-
-const source = readSource(process.cwd()).join('\n')
-const config = readFileSync(join(process.cwd(), 'next.config.ts'), 'utf8')
-
-test('enables Cache Components without opt-outs', () => {
- expect(config).toMatch(/cacheComponents\s*:\s*true/)
- expect(source).not.toMatch(/export\s+(?:const|var|let)\s+instant\s*=\s*false/)
-})
-
-test('keeps URL-specific rendering below useful boundaries', async () => {
- await expect(environment).toSatisfyCriterion(
- `The product page returns useful route-independent shop framing before awaiting params or searchParams. The URL promises are forwarded into one or more children below meaningful Suspense fallbacks, where the slug and currency are resolved. Product lookup is cached in a small data function with every value that changes its output included in the cache key. Related products remain independently suspended and may stream. The solution does not hide the entire page behind one null or generic boundary.`
- )
-})
diff --git a/evals/evals/agent-046-prefetch-until-navigation/EVAL.ts b/evals/evals/agent-051-prefetch-until-navigation/EVAL.ts
similarity index 59%
rename from evals/evals/agent-046-prefetch-until-navigation/EVAL.ts
rename to evals/evals/agent-051-prefetch-until-navigation/EVAL.ts
index 922e1394fa3c..4b4937202f39 100644
--- a/evals/evals/agent-046-prefetch-until-navigation/EVAL.ts
+++ b/evals/evals/agent-051-prefetch-until-navigation/EVAL.ts
@@ -57,6 +57,10 @@ test('enables Partial Prefetching globally or for the project route', () => {
).toBe(true)
})
+test('opts the project link into per-link prefetching', () => {
+ expect(source).toMatch(/]*\bprefetch\s*=\s*\{true\}/)
+})
+
test('uses the navigation cache stage', () => {
const navigationImport = source.match(
/\bunstable_navigation(?:\s+as\s+([A-Za-z_$][\w$]*))?/
@@ -67,14 +71,18 @@ test('uses the navigation cache stage', () => {
expect(source).toMatch(new RegExp(`await\\s+${localName}\\s*\\(`))
})
-test('the title is prefetched and project details wait for navigation', async () => {
+test('includes the project title in the selected prefetch', async () => {
await expect(environment).toSatisfyCriterion(
- `The implementation must make the selected project's title available before the click without prefetching the rest of the project page.
+ `The selected project's title must be available before the click from the dashboard's per-link prefetch. Keep the params-dependent title inside Suspense so the reusable App Shell can show a fallback while the selected prefetch resolves the title. The title must render before the nested boundary that waits for navigation.
-A correct solution uses Partial Prefetching globally or on the project destination, and opts the dashboard's project Link into a per-link prefetch with prefetch={true}. The project route keeps its params-dependent title inside Suspense so the reusable App Shell can show a fallback while the per-link prefetch resolves the title.
+Accept equivalent component and file organization. Reject solutions that leave the title behind the reusable shell fallback, put it behind unstable_navigation(), disable prefetching, or prefetch the entire page.`
+ )
+})
-The rendered project title must appear before a nested Suspense boundary. Inside that boundary, an async component must await unstable_navigation() before it loads or renders the project activity, deployments, description, or other detail content. The unstable_navigation() call must be outside any use cache scope; cached data functions may be called after it.
+test('waits until navigation for project details', async () => {
+ await expect(environment).toSatisfyCriterion(
+ `Project activity, deployments, description, and other detail content must not join the prefetch. Render those details inside a nested Suspense boundary through an async component that awaits unstable_navigation() before loading or rendering them.
-Accept equivalent component and file organization. Reject solutions that put the title behind unstable_navigation(), fetch project details before reaching unstable_navigation(), replace unstable_navigation() with connection() or an uncached fetch, disable prefetching, or prefetch the entire page.`
+The unstable_navigation() call must remain outside every use cache scope; cached data functions may be called after it. Reject solutions that fetch project details before reaching unstable_navigation(), replace it with connection() or an uncached fetch, or prefetch the entire page. Accept equivalent component and file organization.`
)
})
diff --git a/evals/evals/agent-046-prefetch-until-navigation/PROMPT.md b/evals/evals/agent-051-prefetch-until-navigation/PROMPT.md
similarity index 100%
rename from evals/evals/agent-046-prefetch-until-navigation/PROMPT.md
rename to evals/evals/agent-051-prefetch-until-navigation/PROMPT.md
diff --git a/evals/evals/agent-046-prefetch-until-navigation/app/layout.tsx b/evals/evals/agent-051-prefetch-until-navigation/app/layout.tsx
similarity index 100%
rename from evals/evals/agent-046-prefetch-until-navigation/app/layout.tsx
rename to evals/evals/agent-051-prefetch-until-navigation/app/layout.tsx
diff --git a/evals/evals/agent-046-prefetch-until-navigation/app/page.tsx b/evals/evals/agent-051-prefetch-until-navigation/app/page.tsx
similarity index 100%
rename from evals/evals/agent-046-prefetch-until-navigation/app/page.tsx
rename to evals/evals/agent-051-prefetch-until-navigation/app/page.tsx
diff --git a/evals/evals/agent-046-prefetch-until-navigation/app/projects/[slug]/page.tsx b/evals/evals/agent-051-prefetch-until-navigation/app/projects/[slug]/page.tsx
similarity index 100%
rename from evals/evals/agent-046-prefetch-until-navigation/app/projects/[slug]/page.tsx
rename to evals/evals/agent-051-prefetch-until-navigation/app/projects/[slug]/page.tsx
diff --git a/evals/evals/agent-046-prefetch-until-navigation/lib/data.ts b/evals/evals/agent-051-prefetch-until-navigation/lib/data.ts
similarity index 100%
rename from evals/evals/agent-046-prefetch-until-navigation/lib/data.ts
rename to evals/evals/agent-051-prefetch-until-navigation/lib/data.ts
diff --git a/evals/evals/agent-046-prefetch-until-navigation/next.config.ts b/evals/evals/agent-051-prefetch-until-navigation/next.config.ts
similarity index 100%
rename from evals/evals/agent-046-prefetch-until-navigation/next.config.ts
rename to evals/evals/agent-051-prefetch-until-navigation/next.config.ts
diff --git a/evals/evals/agent-046-prefetch-until-navigation/package.json b/evals/evals/agent-051-prefetch-until-navigation/package.json
similarity index 100%
rename from evals/evals/agent-046-prefetch-until-navigation/package.json
rename to evals/evals/agent-051-prefetch-until-navigation/package.json
diff --git a/evals/evals/agent-046-prefetch-until-navigation/tsconfig.json b/evals/evals/agent-051-prefetch-until-navigation/tsconfig.json
similarity index 100%
rename from evals/evals/agent-046-prefetch-until-navigation/tsconfig.json
rename to evals/evals/agent-051-prefetch-until-navigation/tsconfig.json
diff --git a/evals/evals/agent-049-cache-components-session-isolation/EVAL.ts b/evals/evals/agent-052-cache-components-session-isolation/EVAL.ts
similarity index 50%
rename from evals/evals/agent-049-cache-components-session-isolation/EVAL.ts
rename to evals/evals/agent-052-cache-components-session-isolation/EVAL.ts
index c587888703cb..f86f4c850e14 100644
--- a/evals/evals/agent-049-cache-components-session-isolation/EVAL.ts
+++ b/evals/evals/agent-052-cache-components-session-isolation/EVAL.ts
@@ -31,8 +31,20 @@ test('introduces a bounded reusable cache', () => {
expect(source).toMatch(/\bcacheLife\s*\(/)
})
-test('keeps member data isolated and the shell meaningful', async () => {
+test('keeps a useful dashboard frame in the shell', async () => {
await expect(environment).toSatisfyCriterion(
- `The dashboard keeps a useful stable frame such as the Workspace heading outside a meaningful Suspense boundary. Member name, team cookie, and request-region header are read at request time in the suspended subtree and are not captured by a public cache. Shared project totals are cached in a small data function with an explicit lifetime. No page or broad request-specific component is publicly cached, so values cannot leak between members.`
+ `The dashboard must keep a useful stable frame, such as the Workspace heading, outside the Suspense boundary used for request-specific member content. The boundary must provide visible, meaningful loading UI rather than a null or empty fallback. Accept equivalent component and file organization.`
+ )
+})
+
+test('keeps member data isolated per request', async () => {
+ await expect(environment).toSatisfyCriterion(
+ `Member name, team cookie, and request-region header must be read at request time in the suspended subtree and must not be captured by a public cache. No page or broad request-specific component may be publicly cached. Reject any solution that can reuse one member's values for another member. Accept equivalent component and file organization.`
+ )
+})
+
+test('caches only the shared project totals', async () => {
+ await expect(environment).toSatisfyCriterion(
+ `Shared project totals must be cached in a focused reusable data function with an explicit cache lifetime. The cache must not include member name, cookies, headers, or other request-specific values. Accept equivalent component and file organization.`
)
})
diff --git a/evals/evals/agent-049-cache-components-session-isolation/PROMPT.md b/evals/evals/agent-052-cache-components-session-isolation/PROMPT.md
similarity index 100%
rename from evals/evals/agent-049-cache-components-session-isolation/PROMPT.md
rename to evals/evals/agent-052-cache-components-session-isolation/PROMPT.md
diff --git a/evals/evals/agent-049-cache-components-session-isolation/app/layout.tsx b/evals/evals/agent-052-cache-components-session-isolation/app/layout.tsx
similarity index 100%
rename from evals/evals/agent-049-cache-components-session-isolation/app/layout.tsx
rename to evals/evals/agent-052-cache-components-session-isolation/app/layout.tsx
diff --git a/evals/evals/agent-049-cache-components-session-isolation/app/page.tsx b/evals/evals/agent-052-cache-components-session-isolation/app/page.tsx
similarity index 100%
rename from evals/evals/agent-049-cache-components-session-isolation/app/page.tsx
rename to evals/evals/agent-052-cache-components-session-isolation/app/page.tsx
diff --git a/evals/evals/agent-049-cache-components-session-isolation/lib/projects.ts b/evals/evals/agent-052-cache-components-session-isolation/lib/projects.ts
similarity index 100%
rename from evals/evals/agent-049-cache-components-session-isolation/lib/projects.ts
rename to evals/evals/agent-052-cache-components-session-isolation/lib/projects.ts
diff --git a/evals/evals/agent-049-cache-components-session-isolation/next-env.d.ts b/evals/evals/agent-052-cache-components-session-isolation/next-env.d.ts
similarity index 100%
rename from evals/evals/agent-049-cache-components-session-isolation/next-env.d.ts
rename to evals/evals/agent-052-cache-components-session-isolation/next-env.d.ts
diff --git a/evals/evals/agent-049-cache-components-session-isolation/next.config.ts b/evals/evals/agent-052-cache-components-session-isolation/next.config.ts
similarity index 100%
rename from evals/evals/agent-049-cache-components-session-isolation/next.config.ts
rename to evals/evals/agent-052-cache-components-session-isolation/next.config.ts
diff --git a/evals/evals/agent-049-cache-components-session-isolation/package.json b/evals/evals/agent-052-cache-components-session-isolation/package.json
similarity index 100%
rename from evals/evals/agent-049-cache-components-session-isolation/package.json
rename to evals/evals/agent-052-cache-components-session-isolation/package.json
diff --git a/evals/evals/agent-049-cache-components-session-isolation/tsconfig.json b/evals/evals/agent-052-cache-components-session-isolation/tsconfig.json
similarity index 100%
rename from evals/evals/agent-049-cache-components-session-isolation/tsconfig.json
rename to evals/evals/agent-052-cache-components-session-isolation/tsconfig.json
diff --git a/evals/evals/agent-053-cache-components-url-shell/EVAL.ts b/evals/evals/agent-053-cache-components-url-shell/EVAL.ts
new file mode 100644
index 000000000000..0705e5c0e342
--- /dev/null
+++ b/evals/evals/agent-053-cache-components-url-shell/EVAL.ts
@@ -0,0 +1,51 @@
+/** Cache Components: URL data and shell boundaries. */
+
+import { expect, test } from 'vitest'
+import { existsSync, readFileSync, readdirSync, statSync } from 'fs'
+import { join } from 'path'
+import { environment } from '@vercel/agent-eval/eval'
+
+const IGNORE_DIRS = new Set(['.git', '.next', 'node_modules', 'dist', 'build'])
+
+function readSource(dir: string): string[] {
+ if (!existsSync(dir)) return []
+ return readdirSync(dir).flatMap((entry) => {
+ if (IGNORE_DIRS.has(entry)) return []
+ const path = join(dir, entry)
+ if (statSync(path).isDirectory()) return readSource(path)
+ if (entry === 'EVAL.ts' || !/\.(ts|tsx|js|jsx)$/.test(entry)) return []
+ return readFileSync(path, 'utf8')
+ })
+}
+
+const source = readSource(process.cwd()).join('\n')
+const config = readFileSync(join(process.cwd(), 'next.config.ts'), 'utf8')
+
+test('enables Cache Components without opt-outs', () => {
+ expect(config).toMatch(/cacheComponents\s*:\s*true/)
+ expect(source).not.toMatch(/export\s+(?:const|var|let)\s+instant\s*=\s*false/)
+})
+
+test('keeps a useful shop frame in the static shell', async () => {
+ await expect(environment).toSatisfyCriterion(
+ `The product page must return useful route-independent shop framing before awaiting params or searchParams. The solution must not hide the entire page behind one null, empty, or generic Suspense boundary. Accept equivalent component and file organization.`
+ )
+})
+
+test('resolves URL data below meaningful boundaries', async () => {
+ await expect(environment).toSatisfyCriterion(
+ `The product page must forward the params and searchParams promises into one or more children below meaningful Suspense fallbacks, where the product slug and currency are resolved. Reject solutions that await either URL promise before returning the useful shop frame. Accept equivalent component and file organization.`
+ )
+})
+
+test('keys reusable product details by every input', async () => {
+ await expect(environment).toSatisfyCriterion(
+ `Product lookup must be cached in a focused reusable data function. Every value that can change its output, including the product slug and currency, must be passed into the cached function so it participates in the cache key. Reject broad page caching or a cache that can return one product or currency for another. Accept equivalent component and file organization.`
+ )
+})
+
+test('streams related products independently', async () => {
+ await expect(environment).toSatisfyCriterion(
+ `Related products must remain behind their own meaningful Suspense boundary so they can stream independently after the primary product details. Reject solutions that block the primary details on related products or combine the whole page under one fallback. Accept equivalent component and file organization.`
+ )
+})
diff --git a/evals/evals/agent-050-cache-components-url-shell/PROMPT.md b/evals/evals/agent-053-cache-components-url-shell/PROMPT.md
similarity index 100%
rename from evals/evals/agent-050-cache-components-url-shell/PROMPT.md
rename to evals/evals/agent-053-cache-components-url-shell/PROMPT.md
diff --git a/evals/evals/agent-050-cache-components-url-shell/app/layout.tsx b/evals/evals/agent-053-cache-components-url-shell/app/layout.tsx
similarity index 100%
rename from evals/evals/agent-050-cache-components-url-shell/app/layout.tsx
rename to evals/evals/agent-053-cache-components-url-shell/app/layout.tsx
diff --git a/evals/evals/agent-050-cache-components-url-shell/app/page.tsx b/evals/evals/agent-053-cache-components-url-shell/app/page.tsx
similarity index 100%
rename from evals/evals/agent-050-cache-components-url-shell/app/page.tsx
rename to evals/evals/agent-053-cache-components-url-shell/app/page.tsx
diff --git a/evals/evals/agent-050-cache-components-url-shell/app/products/[slug]/page.tsx b/evals/evals/agent-053-cache-components-url-shell/app/products/[slug]/page.tsx
similarity index 100%
rename from evals/evals/agent-050-cache-components-url-shell/app/products/[slug]/page.tsx
rename to evals/evals/agent-053-cache-components-url-shell/app/products/[slug]/page.tsx
diff --git a/evals/evals/agent-050-cache-components-url-shell/lib/products.ts b/evals/evals/agent-053-cache-components-url-shell/lib/products.ts
similarity index 100%
rename from evals/evals/agent-050-cache-components-url-shell/lib/products.ts
rename to evals/evals/agent-053-cache-components-url-shell/lib/products.ts
diff --git a/evals/evals/agent-050-cache-components-url-shell/next-env.d.ts b/evals/evals/agent-053-cache-components-url-shell/next-env.d.ts
similarity index 100%
rename from evals/evals/agent-050-cache-components-url-shell/next-env.d.ts
rename to evals/evals/agent-053-cache-components-url-shell/next-env.d.ts
diff --git a/evals/evals/agent-050-cache-components-url-shell/next.config.ts b/evals/evals/agent-053-cache-components-url-shell/next.config.ts
similarity index 100%
rename from evals/evals/agent-050-cache-components-url-shell/next.config.ts
rename to evals/evals/agent-053-cache-components-url-shell/next.config.ts
diff --git a/evals/evals/agent-050-cache-components-url-shell/package.json b/evals/evals/agent-053-cache-components-url-shell/package.json
similarity index 100%
rename from evals/evals/agent-050-cache-components-url-shell/package.json
rename to evals/evals/agent-053-cache-components-url-shell/package.json
diff --git a/evals/evals/agent-050-cache-components-url-shell/tsconfig.json b/evals/evals/agent-053-cache-components-url-shell/tsconfig.json
similarity index 100%
rename from evals/evals/agent-050-cache-components-url-shell/tsconfig.json
rename to evals/evals/agent-053-cache-components-url-shell/tsconfig.json
From e65fdddca7ce5099c556031f4cd165fd9af6ea3e Mon Sep 17 00:00:00 2001
From: Aurora Scharff
Date: Wed, 9 Sep 2026 01:03:51 +0200
Subject: [PATCH 09/10] evals: refine prefetching comparisons
---
.../01-getting-started/04-linking-and-navigating.mdx | 3 ++-
evals/evals/agent-035-connection-dynamic/EVAL.ts | 2 +-
evals/evals/agent-048-prefetch-url-data/PROMPT.md | 2 +-
.../agent-052-cache-components-session-isolation/EVAL.ts | 7 +++----
evals/lib/setup.ts | 4 ++--
5 files changed, 9 insertions(+), 9 deletions(-)
diff --git a/docs/01-app/01-getting-started/04-linking-and-navigating.mdx b/docs/01-app/01-getting-started/04-linking-and-navigating.mdx
index 08a04ec62454..e94e7d965e2a 100644
--- a/docs/01-app/01-getting-started/04-linking-and-navigating.mdx
+++ b/docs/01-app/01-getting-started/04-linking-and-navigating.mdx
@@ -5,6 +5,7 @@ related:
links:
- app/api-reference/components/link
- app/api-reference/file-conventions/loading
+ - app/guides/optimizing-prefetching
- app/guides/prefetching
---
@@ -95,7 +96,7 @@ By skipping or partially prefetching dynamic routes, Next.js avoids unnecessary
height="748"
/>
-> **Good to know:** See the [Prefetching guide](/docs/app/guides/prefetching) for the full behavior, including how to control prefetching per link and how it changes when you adopt [Partial Prefetching](/docs/app/guides/adopting-partial-prefetching).
+> **Good to know:** See the [Prefetching guide](/docs/app/guides/prefetching) for the full behavior, including how to control prefetching per link and how it changes when you adopt [Partial Prefetching](/docs/app/guides/adopting-partial-prefetching). To include URL-dependent content in a link's prefetch, see [Optimizing prefetching](/docs/app/guides/optimizing-prefetching).
To improve the navigation experience to dynamic routes, you can use [streaming](#streaming).
diff --git a/evals/evals/agent-035-connection-dynamic/EVAL.ts b/evals/evals/agent-035-connection-dynamic/EVAL.ts
index bce8d5893893..d795003af2eb 100644
--- a/evals/evals/agent-035-connection-dynamic/EVAL.ts
+++ b/evals/evals/agent-035-connection-dynamic/EVAL.ts
@@ -33,7 +33,7 @@ test('uses an explicit synchronous I/O boundary', () => {
test('keeps the operations frame useful while metadata loads', async () => {
await expect(environment).toSatisfyCriterion(
- `The stable Operations navigation and page frame must remain outside the Suspense boundary used for request metadata. The boundary must provide visible, meaningful loading UI rather than a null or empty fallback. Accept equivalent component and file organization.`
+ `The stable Operations navigation and page frame must remain outside the Suspense boundary used for request metadata. Accept equivalent component and file organization.`
)
})
diff --git a/evals/evals/agent-048-prefetch-url-data/PROMPT.md b/evals/evals/agent-048-prefetch-url-data/PROMPT.md
index 6389e10ed201..6c8e5d0309c1 100644
--- a/evals/evals/agent-048-prefetch-url-data/PROMPT.md
+++ b/evals/evals/agent-048-prefetch-url-data/PROMPT.md
@@ -1 +1 @@
-Keep the existing `/catalog?category=...` URLs. When navigating from home to a product category, I want the selected category heading and its products to appear immediately instead of the loading state.
+Keep the existing `/catalog?category=...` URLs. Prepare each category link's URL-specific heading and products before the click so selecting it can navigate immediately without showing the loading state. Do not make the click wait for a full server render.
diff --git a/evals/evals/agent-052-cache-components-session-isolation/EVAL.ts b/evals/evals/agent-052-cache-components-session-isolation/EVAL.ts
index f86f4c850e14..93e0d33a1be6 100644
--- a/evals/evals/agent-052-cache-components-session-isolation/EVAL.ts
+++ b/evals/evals/agent-052-cache-components-session-isolation/EVAL.ts
@@ -26,9 +26,8 @@ test('enables Cache Components without opt-outs', () => {
expect(source).not.toMatch(/export\s+(?:const|var|let)\s+instant\s*=\s*false/)
})
-test('introduces a bounded reusable cache', () => {
+test('introduces a reusable cache', () => {
expect(source).toMatch(/['"]use cache['"]/)
- expect(source).toMatch(/\bcacheLife\s*\(/)
})
test('keeps a useful dashboard frame in the shell', async () => {
@@ -39,12 +38,12 @@ test('keeps a useful dashboard frame in the shell', async () => {
test('keeps member data isolated per request', async () => {
await expect(environment).toSatisfyCriterion(
- `Member name, team cookie, and request-region header must be read at request time in the suspended subtree and must not be captured by a public cache. No page or broad request-specific component may be publicly cached. Reject any solution that can reuse one member's values for another member. Accept equivalent component and file organization.`
+ `Member name, team cookie, and request-region header must be read at request time in the suspended subtree and must not be captured by a public cache. No page or broad request-specific component may be publicly cached. A component that directly calls cookies() or headers() without a use cache directive remains request-specific and needs no additional cache opt-out. Reject any solution that can reuse one member's values for another member. Accept equivalent component and file organization.`
)
})
test('caches only the shared project totals', async () => {
await expect(environment).toSatisfyCriterion(
- `Shared project totals must be cached in a focused reusable data function with an explicit cache lifetime. The cache must not include member name, cookies, headers, or other request-specific values. Accept equivalent component and file organization.`
+ `Shared project totals must be cached in a focused reusable data function. The cache must not include member name, cookies, headers, or other request-specific values. Accept equivalent component and file organization.`
)
})
diff --git a/evals/lib/setup.ts b/evals/lib/setup.ts
index a1b0759a2b2a..b2fed8ea214a 100644
--- a/evals/lib/setup.ts
+++ b/evals/lib/setup.ts
@@ -81,9 +81,9 @@ export async function writeAgentsMd(sandbox: Sandbox): Promise {
const body = `
-# Next.js: ALWAYS search and read docs before coding
+# Next.js: ALWAYS read docs before coding
-Before any Next.js work, search \`node_modules/next/dist/docs/\` using terms from the task and source code, then read the most relevant guides and API references. Your training data is outdated — the docs are the source of truth.
+Before any Next.js work, find and read the relevant doc in \`node_modules/next/dist/docs/\`. Your training data is outdated — the docs are the source of truth.
`
From b5231024c99e2bf6adfebbfa54c5f28c00167358 Mon Sep 17 00:00:00 2001
From: Aurora Scharff
Date: Wed, 9 Sep 2026 11:10:29 +0200
Subject: [PATCH 10/10] test: accept bare prefetch prop in navigation evals
---
evals/evals/agent-049-prefetch-stage/EVAL.ts | 2 +-
evals/evals/agent-051-prefetch-until-navigation/EVAL.ts | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/evals/evals/agent-049-prefetch-stage/EVAL.ts b/evals/evals/agent-049-prefetch-stage/EVAL.ts
index e70d0d4a5018..6ebb997222ff 100644
--- a/evals/evals/agent-049-prefetch-stage/EVAL.ts
+++ b/evals/evals/agent-049-prefetch-stage/EVAL.ts
@@ -57,7 +57,7 @@ test('enables Partial Prefetching globally or for the product route', () => {
})
test('opts the featured product link into per-link prefetching', () => {
- expect(source).toMatch(/]*\bprefetch\s*=\s*\{true\}/)
+ expect(source).toMatch(/]*\bprefetch(?:\s*=\s*\{true\})?(?:\s|>)/)
})
test('uses the prefetch cache stage', () => {
diff --git a/evals/evals/agent-051-prefetch-until-navigation/EVAL.ts b/evals/evals/agent-051-prefetch-until-navigation/EVAL.ts
index 4b4937202f39..1db0dec18e34 100644
--- a/evals/evals/agent-051-prefetch-until-navigation/EVAL.ts
+++ b/evals/evals/agent-051-prefetch-until-navigation/EVAL.ts
@@ -58,7 +58,7 @@ test('enables Partial Prefetching globally or for the project route', () => {
})
test('opts the project link into per-link prefetching', () => {
- expect(source).toMatch(/]*\bprefetch\s*=\s*\{true\}/)
+ expect(source).toMatch(/]*\bprefetch(?:\s*=\s*\{true\})?(?:\s|>)/)
})
test('uses the navigation cache stage', () => {