From 1a3a2423e1c6ec48c4c126e47f341b2666627e50 Mon Sep 17 00:00:00 2001 From: Sarthak Agrawal Date: Sat, 15 Aug 2026 02:27:25 +0530 Subject: [PATCH 1/2] chore: reduce measured code-health debt MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Consolidate exact clone groups and lower duplication/complexity baselines for issue #78. Behavior-preserving refactors only; all 213 tests pass. - Extract shared PageSkeleton (stars + discover) — 64-line clone removed - Extract shared ErrorActions (root + discover + stars error.tsx) - Extract buildEmbeddingFromRow helper (embed-pending + seed-embeddings + seed-popular) — 3 identical row-to-text mappings consolidated - Extract GitHubRepoResponse interface + upsertRepoFromGitHub helper (repos/[repoId] route + resolve.ts) — interface + upsert SQL deduped - Lower duplication baseline: 34->27 clones, 532->369 lines, 2.70%->1.88% - Lower complexity baseline: 35->34 violations Progress on #78 --- scripts/check-code-health.mjs | 8 +-- scripts/seed-popular.ts | 19 +----- src/app/api/internal/embed-pending/route.ts | 19 +----- src/app/api/repos/[repoId]/route.ts | 45 +------------- src/app/api/repos/resolve.ts | 66 ++++++++++++--------- src/app/discover/discover-client.tsx | 60 +------------------ src/app/discover/error.tsx | 14 +---- src/app/error.tsx | 14 +---- src/app/stars/error.tsx | 14 +---- src/app/stars/page.tsx | 60 +------------------ src/components/error-actions.tsx | 29 +++++++++ src/components/page-skeleton.tsx | 64 ++++++++++++++++++++ src/db/seed-embeddings.ts | 19 +----- src/lib/embeddings.ts | 28 +++++++++ 14 files changed, 179 insertions(+), 280 deletions(-) create mode 100644 src/components/error-actions.tsx create mode 100644 src/components/page-skeleton.tsx diff --git a/scripts/check-code-health.mjs b/scripts/check-code-health.mjs index 512f4a6..ce3890f 100644 --- a/scripts/check-code-health.mjs +++ b/scripts/check-code-health.mjs @@ -28,11 +28,11 @@ const baselines = { unlisted: 0, unresolved: 0, }, - complexity: { violations: 35, maxCcn: 56, maxLength: 397, maxParams: 17 }, + complexity: { violations: 34, maxCcn: 56, maxLength: 397, maxParams: 17 }, duplication: { - clones: 34, - duplicatedLines: 532, - percentage: 2.698452954603094, + clones: 27, + duplicatedLines: 369, + percentage: 1.8774, }, suppressions: 8, dependencies: { critical: 0, highIds: 0, highFindings: 0 }, diff --git a/scripts/seed-popular.ts b/scripts/seed-popular.ts index 5385a83..e3870e2 100644 --- a/scripts/seed-popular.ts +++ b/scripts/seed-popular.ts @@ -36,7 +36,7 @@ import type { DbClient as Client, InStatement } from '../src/db/client'; import { createD1RestClientFromEnv } from '../src/db/rest-client'; import { isRetryableDbError } from '../src/lib/db-retry'; -import { buildRepoEmbeddingText, generateEmbeddings, textHash } from '../src/lib/embeddings'; +import { buildEmbeddingFromRow, generateEmbeddings } from '../src/lib/embeddings'; import { enumeratePopularCatalog, GITHUB_SEARCH_PAGE_SIZE, @@ -277,22 +277,7 @@ async function embedPending(db: Client, limit: number): Promise { const toEmbed: { id: number; text: string; hash: string }[] = []; for (const row of pending.rows) { - const text = buildRepoEmbeddingText({ - full_name: row.full_name as string, - description: row.description as string | null, - language: row.language as string | null, - topics: row.topics as string, - ai: row.summary - ? { - summary: row.summary as string, - category: row.category as string, - subcategories: row.subcategories as string, - use_cases: row.use_cases as string, - keywords: row.keywords as string, - } - : null, - }); - const hash = textHash(text); + const { text, hash } = buildEmbeddingFromRow(row); if (row.text_hash !== hash) { toEmbed.push({ id: row.id as number, text, hash }); } diff --git a/src/app/api/internal/embed-pending/route.ts b/src/app/api/internal/embed-pending/route.ts index 0acb523..9d99b35 100644 --- a/src/app/api/internal/embed-pending/route.ts +++ b/src/app/api/internal/embed-pending/route.ts @@ -2,7 +2,7 @@ import type { InStatement } from '@/db/client'; import { NextResponse } from 'next/server'; import { db } from '@/db'; -import { buildRepoEmbeddingText, generateEmbeddings, textHash } from '@/lib/embeddings'; +import { buildEmbeddingFromRow, generateEmbeddings } from '@/lib/embeddings'; import { hasValidOperatorToken } from '@/lib/operator-auth'; import { repoVectors } from '@/lib/repo-vectors'; @@ -77,22 +77,7 @@ export async function POST(request: Request) { const pending: { id: number; text: string; hash: string }[] = []; for (const row of repos.rows) { - const text = buildRepoEmbeddingText({ - full_name: row.full_name as string, - description: row.description as string | null, - language: row.language as string | null, - topics: row.topics as string, - ai: row.summary - ? { - summary: row.summary as string, - category: row.category as string, - subcategories: row.subcategories as string, - use_cases: row.use_cases as string, - keywords: row.keywords as string, - } - : null, - }); - const hash = textHash(text); + const { text, hash } = buildEmbeddingFromRow(row); if (row.text_hash !== hash) { pending.push({ id: row.id as number, text, hash }); } diff --git a/src/app/api/repos/[repoId]/route.ts b/src/app/api/repos/[repoId]/route.ts index d2f741d..be21201 100644 --- a/src/app/api/repos/[repoId]/route.ts +++ b/src/app/api/repos/[repoId]/route.ts @@ -2,22 +2,7 @@ import { type NextRequest, NextResponse } from 'next/server'; import { db } from '@/db'; -import { resolveRepoId } from '../resolve'; - -interface GitHubRepoResponse { - id: number; - name: string; - full_name: string; - owner: { login: string; avatar_url: string }; - html_url: string; - description: string | null; - language: string | null; - stargazers_count: number; - archived?: boolean; - topics?: string[]; - created_at: string; - updated_at: string; -} +import { type GitHubRepoResponse, resolveRepoId, upsertRepoFromGitHub } from '../resolve'; export async function GET( request: NextRequest, @@ -82,33 +67,7 @@ export async function GET( const gh = (await ghRes.json()) as GitHubRepoResponse; - await db.execute({ - sql: `INSERT INTO repos (id, name, full_name, owner_login, owner_avatar, html_url, - description, language, stargazers_count, archived, topics, repo_created_at, repo_updated_at) - VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) - ON CONFLICT(id) DO UPDATE SET - name = excluded.name, full_name = excluded.full_name, - owner_login = excluded.owner_login, owner_avatar = excluded.owner_avatar, - html_url = excluded.html_url, description = excluded.description, - language = excluded.language, stargazers_count = excluded.stargazers_count, - archived = excluded.archived, topics = excluded.topics, repo_created_at = excluded.repo_created_at, - repo_updated_at = excluded.repo_updated_at`, - args: [ - gh.id, - gh.name, - gh.full_name, - gh.owner.login, - gh.owner.avatar_url, - gh.html_url, - gh.description ?? null, - gh.language ?? null, - gh.stargazers_count, - gh.archived ? 1 : 0, - JSON.stringify(gh.topics ?? []), - gh.created_at, - gh.updated_at, - ], - }); + await upsertRepoFromGitHub(gh); repoResult = await db.execute({ sql: 'SELECT * FROM repos WHERE id = ?', diff --git a/src/app/api/repos/resolve.ts b/src/app/api/repos/resolve.ts index 6cb1fcc..1b32903 100644 --- a/src/app/api/repos/resolve.ts +++ b/src/app/api/repos/resolve.ts @@ -1,6 +1,6 @@ import { db } from '@/db'; -interface GitHubRepoResponse { +export interface GitHubRepoResponse { id: number; name: string; full_name: string; @@ -15,6 +15,42 @@ interface GitHubRepoResponse { updated_at: string; } +const REPO_UPSERT_SQL = `INSERT INTO repos (id, name, full_name, owner_login, owner_avatar, html_url, + description, language, stargazers_count, archived, topics, repo_created_at, repo_updated_at) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) + ON CONFLICT(id) DO UPDATE SET + name = excluded.name, full_name = excluded.full_name, + owner_login = excluded.owner_login, owner_avatar = excluded.owner_avatar, + html_url = excluded.html_url, description = excluded.description, + language = excluded.language, stargazers_count = excluded.stargazers_count, + archived = excluded.archived, topics = excluded.topics, repo_created_at = excluded.repo_created_at, + repo_updated_at = excluded.repo_updated_at`; + +/** + * Upsert a GitHub repo row into D1. Shared by resolveRepoId and the + * [repoId] GET route so the INSERT/ON CONFLICT shape stays in one place. + */ +export async function upsertRepoFromGitHub(gh: GitHubRepoResponse): Promise { + await db.execute({ + sql: REPO_UPSERT_SQL, + args: [ + gh.id, + gh.name, + gh.full_name, + gh.owner.login, + gh.owner.avatar_url, + gh.html_url, + gh.description ?? null, + gh.language ?? null, + gh.stargazers_count, + gh.archived ? 1 : 0, + JSON.stringify(gh.topics ?? []), + gh.created_at, + gh.updated_at, + ], + }); +} + /** * Resolve owner/repo slug to a numeric repo ID. * If the repo isn't in our DB yet, fetches from GitHub and inserts it. @@ -42,33 +78,7 @@ export async function resolveRepoId(owner: string, repo: string): Promise -
- - - - -
- -
- - -
-
- {Array.from({ length: 6 }).map((_, i) => ( -
-
- - -
- - -
-
- - -
-
-
- ))} -
-
-
- - ); -} - export default function DiscoverClient({ initialData, initialUrl, diff --git a/src/app/discover/error.tsx b/src/app/discover/error.tsx index 6ebb9ba..ca6519c 100644 --- a/src/app/discover/error.tsx +++ b/src/app/discover/error.tsx @@ -2,6 +2,7 @@ import { useEffect } from 'react'; +import { ErrorActions } from '@/components/error-actions'; import { captureError } from '@/lib/foundry-monitoring'; export default function DiscoverError({ @@ -23,18 +24,7 @@ export default function DiscoverError({

Something went wrong while loading the discover feed — try again.

-
- - -
- {error.digest ?

Reference: {error.digest}

: null} + ); diff --git a/src/app/error.tsx b/src/app/error.tsx index 1c9c424..7613112 100644 --- a/src/app/error.tsx +++ b/src/app/error.tsx @@ -2,6 +2,7 @@ import { useEffect } from 'react'; +import { ErrorActions } from '@/components/error-actions'; import { captureError } from '@/lib/foundry-monitoring'; export default function Error({ @@ -25,18 +26,7 @@ export default function Error({ An unexpected error occurred on our end. Your data is safe — try again, and if it keeps happening, come back in a few minutes.

-
- - -
- {error.digest ?

Reference: {error.digest}

: null} + ); diff --git a/src/app/stars/error.tsx b/src/app/stars/error.tsx index d7091d8..185d4bd 100644 --- a/src/app/stars/error.tsx +++ b/src/app/stars/error.tsx @@ -2,6 +2,7 @@ import { useEffect } from 'react'; +import { ErrorActions } from '@/components/error-actions'; import { captureError } from '@/lib/foundry-monitoring'; export default function StarsError({ @@ -23,18 +24,7 @@ export default function StarsError({

Something went wrong while loading your starred repos. Your data is safe — try again.

-
- - -
- {error.digest ?

Reference: {error.digest}

: null} + ); diff --git a/src/app/stars/page.tsx b/src/app/stars/page.tsx index 4f71358..5d02614 100644 --- a/src/app/stars/page.tsx +++ b/src/app/stars/page.tsx @@ -10,13 +10,13 @@ import { Suspense, useCallback, useEffect, useMemo, useState } from 'react'; import { ActiveFilterChips } from '@/components/active-filter-chips'; import { BulkActionBar } from '@/components/bulk-action-bar'; import { CompareSheet } from '@/components/compare-sheet'; +import { PageSkeleton } from '@/components/page-skeleton'; import { RepoGrid } from '@/components/repo-grid'; import { Sidebar } from '@/components/sidebar'; import { SyncAnimation, SyncProgressBar } from '@/components/sync-animation'; import { TopBar } from '@/components/top-bar'; import { ScrollArea } from '@/components/ui/scroll-area'; import { Sheet, SheetContent, SheetDescription, SheetTitle } from '@/components/ui/sheet'; -import { Skeleton } from '@/components/ui/skeleton'; import { useLists } from '@/hooks/use-lists'; import { useStarredRepos } from '@/hooks/use-starred-repos'; import { summarizeSyncRepoNames } from '@/lib/sync-performance'; @@ -29,64 +29,6 @@ const sortOptions = [ 'name-az', ] as const; -function PageSkeleton() { - return ( - <> -
- - - - -
- -
- - -
-
- {Array.from({ length: 6 }).map((_, i) => ( -
-
- - -
- - -
-
- - -
-
-
- ))} -
-
-
- - ); -} - export default function StarsPage() { const { status } = useSession(); const router = useRouter(); diff --git a/src/components/error-actions.tsx b/src/components/error-actions.tsx new file mode 100644 index 0000000..8bede0d --- /dev/null +++ b/src/components/error-actions.tsx @@ -0,0 +1,29 @@ +/** + * Shared error-recovery actions rendered by the per-route `error.tsx` + * boundaries. The "Try again" + "Home" button row and optional digest + * reference are identical across every error surface. + */ +export function ErrorActions({ + error, + reset, +}: { + error: Error & { digest?: string }; + reset: () => void; +}) { + return ( + <> +
+ + +
+ {error.digest ?

Reference: {error.digest}

: null} + + ); +} diff --git a/src/components/page-skeleton.tsx b/src/components/page-skeleton.tsx new file mode 100644 index 0000000..7452f92 --- /dev/null +++ b/src/components/page-skeleton.tsx @@ -0,0 +1,64 @@ +import { Skeleton } from '@/components/ui/skeleton'; + +/** + * Shared loading skeleton for the stars and discover list surfaces. + * Both pages render an identical header + sidebar + card grid placeholder + * while session or data is resolving. + */ +export function PageSkeleton() { + return ( + <> +
+ + + + +
+ +
+ + +
+
+ {Array.from({ length: 6 }).map((_, i) => ( +
+
+ + +
+ + +
+
+ + +
+
+
+ ))} +
+
+
+ + ); +} diff --git a/src/db/seed-embeddings.ts b/src/db/seed-embeddings.ts index 9fbd9a4..9bc78a7 100644 --- a/src/db/seed-embeddings.ts +++ b/src/db/seed-embeddings.ts @@ -1,6 +1,6 @@ import type { InStatement } from './client'; import { createD1RestClientFromEnv } from './rest-client'; -import { buildRepoEmbeddingText, generateEmbeddings, textHash } from '../lib/embeddings'; +import { buildEmbeddingFromRow, generateEmbeddings } from '../lib/embeddings'; import { createVectorizeRestWriterFromEnv } from '../lib/repo-vectors-rest'; const BATCH_SIZE = 50; @@ -44,22 +44,7 @@ async function seed() { const toEmbed: { id: number; text: string; hash: string }[] = []; for (const row of repos.rows) { - const text = buildRepoEmbeddingText({ - full_name: row.full_name as string, - description: row.description as string | null, - language: row.language as string | null, - topics: row.topics as string, - ai: row.summary - ? { - summary: row.summary as string, - category: row.category as string, - subcategories: row.subcategories as string, - use_cases: row.use_cases as string, - keywords: row.keywords as string, - } - : null, - }); - const hash = textHash(text); + const { text, hash } = buildEmbeddingFromRow(row); if (existingHashes.get(row.id as number) !== hash) { toEmbed.push({ id: row.id as number, text, hash }); } diff --git a/src/lib/embeddings.ts b/src/lib/embeddings.ts index fc4892b..70b688f 100644 --- a/src/lib/embeddings.ts +++ b/src/lib/embeddings.ts @@ -185,6 +185,34 @@ function parseStringList(value: string | string[] | null | undefined): string[] } } +/** + * Build embedding text + hash from a D1 repo row. Consolidates the identical + * row-to-text mapping used by the embed-pending route, seed-embeddings, and + * seed-popular jobs. The row is `Record` because D1 returns + * untyped rows; casts happen once inside the helper. + */ +export function buildEmbeddingFromRow(row: Record): { + text: string; + hash: string; +} { + const text = buildRepoEmbeddingText({ + full_name: row.full_name as string, + description: row.description as string | null, + language: row.language as string | null, + topics: row.topics as string, + ai: row.summary + ? { + summary: row.summary as string, + category: row.category as string, + subcategories: row.subcategories as string, + use_cases: row.use_cases as string, + keywords: row.keywords as string, + } + : null, + }); + return { text, hash: textHash(text) }; +} + /** Simple hash to detect when repo text changes. */ export function textHash(text: string): string { let h = 0; From 8ff1450f9fca16b8aaa3fcf3ae823ba52bb3b114 Mon Sep 17 00:00:00 2001 From: Sarthak Agrawal Date: Sat, 15 Aug 2026 04:43:16 +0530 Subject: [PATCH 2/2] fix: correct homepage structured-data identity --- src/app/layout.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 2fcb9ff..f4fb1d6 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -72,8 +72,9 @@ export default function RootLayout({ {/* fleet-jsonld:start (generated by apply-agent-surfaces; edit registry, not this) */}