diff --git a/docs/FINDINGS.md b/docs/FINDINGS.md index 13cf45f..13892fd 100644 --- a/docs/FINDINGS.md +++ b/docs/FINDINGS.md @@ -165,3 +165,26 @@ Add subsequent research below this section. - Risks / follow-ups: - Base-aware navigation fixes must preserve internal app routing semantics and should not replace intentional external navigation, because SvelteKit `goto(...)` no longer accepts external URLs. - Settings and search page lifecycle changes must avoid reintroducing SSR-triggered fetches or self-triggered URL loops; client-only bootstrap logic should remain mounted once and URL-sync effects must stay idempotent. + +### 2026-03-27 — ROUTING-0001 planning research + +- Task: Plan the repository-detail routing fix for slash-bearing repository IDs causing homepage SSR failures and invalid `/repos/[id]` navigation. +- Files inspected: + - `package.json` + - `src/lib/components/RepositoryCard.svelte` + - `src/routes/+page.svelte` + - `src/routes/+page.server.ts` + - `src/routes/repos/[id]/+page.server.ts` + - `src/routes/repos/[id]/+page.svelte` + - `src/routes/api/v1/api-contract.integration.test.ts` + - `src/lib/types.ts` +- Findings: + - The app is on SvelteKit `^2.50.2` and uses `$app/paths.resolve(...)` for internal navigation, including `resolveRoute('/repos/[id]', { id: repo.id })` in `RepositoryCard.svelte`. + - SvelteKit’s `[id]` route is a single-segment dynamic parameter. Context7 routing docs show slash-containing values belong to rest parameters like `[...param]`, so raw repository IDs containing `/` are invalid inputs for `resolveRoute('/repos/[id]', ...)`. + - The repository model intentionally stores slash-bearing IDs such as `/facebook/react`, and the existing API surface consistently treats those IDs as percent-encoded path segments. The integration contract already passes `params.id = encodeURIComponent('/facebook/react')` for `/api/v1/libs/[id]` handlers, which then call `decodeURIComponent(params.id)`. + - The homepage SSR failure is therefore rooted in UI link generation, not repository listing fetches: rendering `RepositoryCard.svelte` with a raw slash-bearing `repo.id` can throw before page load completes, which explains repeated `500` responses on `/`. + - The repo detail page currently forwards `params.id` directly into `encodeURIComponent(...)` for downstream API requests. Once detail links are generated as encoded single segments, the page loader and client-side refresh/delete/reindex flows need one normalization step so API calls continue targeting the stored repository ID instead of a doubly encoded value. + - No existing browser-facing test covers homepage card navigation or `/repos/[id]` loader behavior; the closest current evidence is the API contract test file, which already exercises encoded repository IDs on HTTP endpoints and provides reusable fixtures for slash-bearing IDs. +- Risks / follow-ups: + - The fix should preserve the existing `/repos/[id]` route shape instead of redesigning it to a rest route unless a broader navigation contract change is explicitly requested. + - Any normalization helper introduced for the repo detail page should be reused consistently across server load and client event handlers to avoid mixed encoded and decoded repository IDs during navigation and fetches. diff --git a/scripts/build.mjs b/scripts/build.mjs new file mode 100644 index 0000000..5531a15 --- /dev/null +++ b/scripts/build.mjs @@ -0,0 +1,79 @@ +import { mkdir, readdir, rename } from 'node:fs/promises'; +import { basename, dirname, join } from 'node:path'; +import { fileURLToPath } from 'node:url'; +import { spawn } from 'node:child_process'; + +const rootDir = dirname(dirname(fileURLToPath(import.meta.url))); +const routesDir = join(rootDir, 'src', 'routes'); +const renamedRouteTestFiles = []; + +async function collectReservedRouteTestFiles(directory) { + const entries = await readdir(directory, { withFileTypes: true }); + const files = []; + + for (const entry of entries) { + const entryPath = join(directory, entry.name); + + if (entry.isDirectory()) { + files.push(...(await collectReservedRouteTestFiles(entryPath))); + continue; + } + + if (!entry.name.startsWith('+')) { + continue; + } + + if (!entry.name.includes('.test.') && !entry.name.includes('.spec.')) { + continue; + } + + files.push(entryPath); + } + + return files; +} + +async function renameReservedRouteTests() { + const reservedRouteTestFiles = await collectReservedRouteTestFiles(routesDir); + + for (const sourcePath of reservedRouteTestFiles) { + const targetPath = join(dirname(sourcePath), basename(sourcePath).slice(1)); + await rename(sourcePath, targetPath); + renamedRouteTestFiles.push({ sourcePath, targetPath }); + } +} + +async function restoreReservedRouteTests() { + for (const { sourcePath, targetPath } of renamedRouteTestFiles.reverse()) { + await mkdir(dirname(sourcePath), { recursive: true }); + await rename(targetPath, sourcePath); + } +} + +function runViteBuild() { + const viteBinPath = join(rootDir, 'node_modules', 'vite', 'bin', 'vite.js'); + + return new Promise((resolve, reject) => { + const child = spawn(process.execPath, [viteBinPath, 'build'], { + cwd: rootDir, + stdio: 'inherit' + }); + + child.once('error', reject); + child.once('exit', (code) => { + if (code === 0) { + resolve(); + return; + } + + reject(new Error(`vite build exited with code ${code ?? 'unknown'}`)); + }); + }); +} + +try { + await renameReservedRouteTests(); + await runViteBuild(); +} finally { + await restoreReservedRouteTests(); +} \ No newline at end of file diff --git a/src/lib/components/RepositoryCard.svelte b/src/lib/components/RepositoryCard.svelte index 18d6d07..dcc959c 100644 --- a/src/lib/components/RepositoryCard.svelte +++ b/src/lib/components/RepositoryCard.svelte @@ -26,6 +26,10 @@ error: 'Error' }; + const detailsHref = $derived( + resolveRoute('/repos/[id]', { id: encodeURIComponent(repo.id) }) + ); + const totalSnippets = $derived(repo.totalSnippets ?? 0); const trustScore = $derived(repo.trustScore ?? 0); @@ -77,7 +81,7 @@ {repo.state === 'indexing' ? 'Indexing...' : 'Re-index'} Details diff --git a/src/lib/components/RepositoryCard.svelte.test.ts b/src/lib/components/RepositoryCard.svelte.test.ts new file mode 100644 index 0000000..ee2be10 --- /dev/null +++ b/src/lib/components/RepositoryCard.svelte.test.ts @@ -0,0 +1,27 @@ +import { page } from 'vitest/browser'; +import { describe, expect, it, vi } from 'vitest'; +import { render } from 'vitest-browser-svelte'; +import RepositoryCard from './RepositoryCard.svelte'; + +describe('RepositoryCard.svelte', () => { + it('encodes slash-bearing repository ids in the details href', async () => { + render(RepositoryCard, { + repo: { + id: '/facebook/react', + title: 'React', + description: 'A JavaScript library for building user interfaces', + state: 'indexed', + totalSnippets: 1234, + trustScore: 9.7, + stars: 230000, + lastIndexedAt: null + } as never, + onReindex: vi.fn(), + onDelete: vi.fn() + }); + + await expect + .element(page.getByRole('link', { name: 'Details' })) + .toHaveAttribute('href', '/repos/%2Ffacebook%2Freact'); + }); +}); \ No newline at end of file diff --git a/src/routes/api/v1/api-contract.integration.test.ts b/src/routes/api/v1/api-contract.integration.test.ts index 19c97f7..58c7e09 100644 --- a/src/routes/api/v1/api-contract.integration.test.ts +++ b/src/routes/api/v1/api-contract.integration.test.ts @@ -39,6 +39,7 @@ import { GET as getJobs } from './jobs/+server.js'; import { GET as getJob } from './jobs/[id]/+server.js'; import { GET as getVersions, POST as postVersions } from './libs/[id]/versions/+server.js'; import { GET as getContext } from './context/+server.js'; +import { DEFAULT_TOKEN_BUDGET } from '$lib/server/api/token-budget.js'; const NOW_S = Math.floor(Date.now() / 1000); @@ -325,6 +326,40 @@ describe('API contract integration', () => { expect(body).toContain('Result count: 0'); }); + it('GET /api/v1/context does not token-filter default JSON responses for the UI', async () => { + const repositoryId = seedRepo(db); + const documentId = seedDocument(db, repositoryId); + + seedSnippet(db, { + documentId, + repositoryId, + type: 'info', + title: 'Large result', + content: 'Large result body', + tokenCount: DEFAULT_TOKEN_BUDGET + 1 + }); + seedSnippet(db, { + documentId, + repositoryId, + type: 'info', + title: 'Small result', + content: 'Small result body', + tokenCount: 5 + }); + + const response = await getContext({ + url: new URL( + `http://test/api/v1/context?libraryId=${encodeURIComponent(repositoryId)}&query=${encodeURIComponent('result')}` + ) + } as never); + + expect(response.status).toBe(200); + const body = await response.json(); + + expect(body.snippets).toHaveLength(2); + expect(body.resultCount).toBe(2); + }); + it('GET /api/v1/context returns additive repository and version metadata for versioned results', async () => { const repositoryId = seedRepo(db); const versionId = seedVersion(db, repositoryId, 'v18.3.0'); diff --git a/src/routes/api/v1/context/+server.ts b/src/routes/api/v1/context/+server.ts index bb2b5fd..784182c 100644 --- a/src/routes/api/v1/context/+server.ts +++ b/src/routes/api/v1/context/+server.ts @@ -124,6 +124,7 @@ export const GET: RequestHandler = async ({ url }) => { } const responseType = url.searchParams.get('type') ?? 'json'; + const applyTokenBudget = responseType === 'txt' || url.searchParams.has('tokens'); const tokensRaw = parseInt(url.searchParams.get('tokens') ?? String(DEFAULT_TOKEN_BUDGET), 10); const maxTokens = isNaN(tokensRaw) || tokensRaw < 1 ? DEFAULT_TOKEN_BUDGET : tokensRaw; @@ -212,15 +213,17 @@ export const GET: RequestHandler = async ({ url }) => { profileId }); - // Apply token budget. - const snippets = searchResults.map((r) => r.snippet); - const selected = selectSnippetsWithinBudget(snippets, maxTokens); + const selectedResults = applyTokenBudget + ? (() => { + const snippets = searchResults.map((r) => r.snippet); + const selected = selectSnippetsWithinBudget(snippets, maxTokens); - // Re-wrap selected snippets as SnippetSearchResult for formatters. - const selectedResults = selected.map((snippet) => { - const found = searchResults.find((r) => r.snippet.id === snippet.id)!; - return found; - }); + return selected.map((snippet) => { + const found = searchResults.find((r) => r.snippet.id === snippet.id)!; + return found; + }); + })() + : searchResults; const snippetVersionIds = Array.from( new Set( diff --git a/src/routes/repos/[id]/+page.server.ts b/src/routes/repos/[id]/+page.server.ts index 2517398..0f8e36c 100644 --- a/src/routes/repos/[id]/+page.server.ts +++ b/src/routes/repos/[id]/+page.server.ts @@ -2,8 +2,8 @@ import type { PageServerLoad } from './$types'; import { error } from '@sveltejs/kit'; export const load: PageServerLoad = async ({ fetch, params }) => { - const id = params.id; - const res = await fetch(`/api/v1/libs/${encodeURIComponent(id)}`); + const repositoryId = decodeURIComponent(params.id); + const res = await fetch(`/api/v1/libs/${encodeURIComponent(repositoryId)}`); if (res.status === 404) { error(404, 'Repository not found'); @@ -16,7 +16,9 @@ export const load: PageServerLoad = async ({ fetch, params }) => { const repo = await res.json(); // Fetch recent jobs - const jobsRes = await fetch(`/api/v1/jobs?repositoryId=${encodeURIComponent(id)}&limit=5`); + const jobsRes = await fetch( + `/api/v1/jobs?repositoryId=${encodeURIComponent(repositoryId)}&limit=5` + ); const jobsData = jobsRes.ok ? await jobsRes.json() : { jobs: [] }; return { diff --git a/src/routes/repos/[id]/page.server.test.ts b/src/routes/repos/[id]/page.server.test.ts new file mode 100644 index 0000000..db1db3e --- /dev/null +++ b/src/routes/repos/[id]/page.server.test.ts @@ -0,0 +1,34 @@ +import { describe, expect, it, vi } from 'vitest'; +import { load } from './+page.server'; + +describe('/repos/[id] page server load', () => { + it('decodes the route param once before calling downstream APIs', async () => { + const fetch = vi + .fn() + .mockResolvedValueOnce({ + ok: true, + status: 200, + json: async () => ({ id: '/facebook/react', title: 'React' }) + }) + .mockResolvedValueOnce({ + ok: true, + status: 200, + json: async () => ({ jobs: [{ id: 'job-1', repositoryId: '/facebook/react' }] }) + }); + + const result = await load({ + fetch, + params: { id: encodeURIComponent('/facebook/react') } + } as never); + + expect(fetch).toHaveBeenNthCalledWith(1, '/api/v1/libs/%2Ffacebook%2Freact'); + expect(fetch).toHaveBeenNthCalledWith( + 2, + '/api/v1/jobs?repositoryId=%2Ffacebook%2Freact&limit=5' + ); + expect(result).toEqual({ + repo: { id: '/facebook/react', title: 'React' }, + recentJobs: [{ id: 'job-1', repositoryId: '/facebook/react' }] + }); + }); +}); \ No newline at end of file diff --git a/src/routes/route-file-conventions.test.ts b/src/routes/route-file-conventions.test.ts new file mode 100644 index 0000000..40c460e --- /dev/null +++ b/src/routes/route-file-conventions.test.ts @@ -0,0 +1,33 @@ +import { readdirSync } from 'node:fs'; +import { join } from 'node:path'; +import { describe, expect, it } from 'vitest'; + +function collectReservedRouteTestFiles(directory: string): string[] { + const entries = readdirSync(directory, { withFileTypes: true }); + const reservedTestFiles: string[] = []; + + for (const entry of entries) { + const entryPath = join(directory, entry.name); + + if (entry.isDirectory()) { + reservedTestFiles.push(...collectReservedRouteTestFiles(entryPath)); + continue; + } + + if (!entry.name.startsWith('+')) continue; + if (!entry.name.includes('.test.') && !entry.name.includes('.spec.')) continue; + + reservedTestFiles.push(entryPath); + } + + return reservedTestFiles; +} + +describe('SvelteKit route file conventions', () => { + it('does not place test files in reserved +prefixed route filenames', () => { + const routeDirectory = import.meta.dirname; + const reservedTestFiles = collectReservedRouteTestFiles(routeDirectory); + + expect(reservedTestFiles).toEqual([]); + }); +}); \ No newline at end of file diff --git a/test-output.txt b/test-output.txt deleted file mode 100644 index 852450b..0000000 --- a/test-output.txt +++ /dev/null @@ -1,632 +0,0 @@ - -> trueref@0.0.1 test:unit -> vitest - - - DEV  v4.1.0 /home/moze/Sources/trueref - -19:10:26 [vite] (client) Re-optimizing dependencies because lockfile has changed - ❯  server  src/lib/server/embeddings/embedding.service.test.ts (0 test) - ✓  server  src/lib/server/parser/code.parser.test.ts (20 tests) 22ms - ✓  server  src/lib/server/services/version.service.test.ts (19 tests) 37ms - ✓  server  src/lib/server/services/repository.service.test.ts (37 tests) 57ms -stderr | src/lib/server/crawler/local.crawler.test.ts > LocalCrawler.crawl() — config file detection > gracefully handles a malformed config file -[LocalCrawler] Failed to parse config file: /tmp/trueref-test-ptITIP/trueref.json - - ✓  server  src/lib/server/config/config-parser.test.ts (50 tests) 21ms -stderr | src/lib/server/pipeline/indexing.pipeline.test.ts > IndexingPipeline > marks job as failed and repo as error when pipeline throws -[IndexingPipeline] Job c44d7e22-6127-49e7-82b7-eb724726c888 failed: crawl failed - -stderr | src/lib/server/pipeline/indexing.pipeline.test.ts -[JobQueue] No pipeline configured — cannot process jobs. - -stderr | src/lib/server/pipeline/indexing.pipeline.test.ts -[JobQueue] No pipeline configured — cannot process jobs. - -stderr | src/lib/server/pipeline/indexing.pipeline.test.ts -[JobQueue] No pipeline configured — cannot process jobs. - - ✓  server  src/lib/server/search/search.service.test.ts (43 tests) 43ms - ✓  server  src/lib/server/pipeline/indexing.pipeline.test.ts (20 tests) 42ms - ✓  server  src/lib/server/crawler/gitignore-parser.test.ts (29 tests) 11ms - ✓  server  src/lib/server/crawler/github-tags.test.ts (10 tests) 9ms - ✓  server  src/routes/api/v1/api-contract.integration.test.ts (4 tests) 48ms - ❯  server  src/lib/server/db/schema.test.ts (19 tests | 19 failed) 50ms - × inserts and retrieves a repository 12ms - × allows nullable optional fields 3ms - × supports all state enum values 2ms - × inserts a version linked to a repository 4ms - × cascades delete when parent repository is deleted 2ms - × inserts a document 1ms - × cascades delete when repository is deleted 2ms - × inserts a code snippet 2ms - × inserts an info snippet 2ms - × cascades delete when document is deleted 2ms - × stores a Float32Array embedding as blob 2ms - × cascades delete when snippet is deleted 2ms - × creates a job with default queued status 2ms - × supports all status enum values 2ms - × stores JSON array fields correctly 2ms - × stores and retrieves key-value settings 2ms - × FTS table exists and is queryable 1ms - × insert trigger keeps FTS in sync 2ms - × delete trigger removes entry from FTS 2ms - ❯  server  src/lib/server/search/hybrid.search.service.test.ts (33 tests | 16 failed) 52ms - ✓ returns 1.0 for identical vectors 2ms - ✓ returns 0.0 for orthogonal vectors 0ms - ✓ returns -1.0 for opposite vectors 0ms - ✓ returns 0 for zero-magnitude vector 0ms - ✓ throws when dimensions do not match 1ms - ✓ computes correct similarity for non-trivial vectors 0ms - ✓ returns empty array for empty inputs 1ms - ✓ fuses a single list preserving order 1ms - ✓ deduplicates items appearing in multiple lists 0ms - ✓ boosts items appearing in multiple lists 0ms - ✓ assigns higher rrfScore to higher-ranked items 0ms - ✓ handles three lists correctly 0ms - ✓ produces positive rrfScores 0ms - × returns empty array when no embeddings exist 10ms - × returns results sorted by descending cosine similarity 2ms - × respects the limit parameter 4ms - × only returns snippets from the specified repository 2ms - × handles embeddings with negative values 1ms - ✓ returns FTS5 results when embeddingProvider is null 2ms - ✓ returns FTS5 results when alpha = 0 1ms - ✓ returns empty array when FTS5 query is blank and no provider 1ms - ✓ falls back to FTS5 when noop provider returns empty embeddings 2ms - × returns results when hybrid mode is active (alpha = 0.5) 1ms - × deduplicates snippets appearing in both FTS5 and vector results 1ms - × respects the limit option 1ms - × returns vector-ranked results when alpha = 1 1ms - × results include snippet and repository metadata 1ms - × all results belong to the requested repository 1ms - × filters by snippet type when provided 1ms - × uses alpha = 0.5 when not specified 1ms - × filters by versionId — excludes snippets from other versions 3ms - × searchMode=keyword never calls provider.embed() 3ms - × searchMode=semantic uses only vector search 2ms - ✓  server  src/lib/server/api/formatters.test.ts (20 tests) 9ms - ✓  server  src/lib/server/pipeline/diff.test.ts (9 tests) 8ms - ✓  server  src/lib/server/api/library-id.test.ts (8 tests) 6ms - ✓  server  src/lib/server/api/token-budget.test.ts (7 tests) 6ms - ✓  server  src/lib/server/parser/markdown.parser.test.ts (14 tests) 9ms - ✓  server  src/lib/vitest-examples/greet.spec.ts (1 test) 3ms - ✓  server  src/lib/server/crawler/local.crawler.test.ts (50 tests) 658ms - ✓  server  src/mcp/index.test.ts (7 tests) 985ms - ✓  client (chromium)  src/lib/vitest-examples/Welcome.svelte.spec.ts (1 test) 9ms -stderr | src/lib/server/crawler/github.crawler.test.ts > crawl() > skips files that fail to download without throwing -[GitHubCrawler] Could not download: src/index.ts — skipping. - - ✓  server  src/lib/server/crawler/github.crawler.test.ts (50 tests) 6082ms - ✓ retries on failure and returns eventual success  3003ms - ✓ throws after exhausting all attempts  3003ms - -⎯⎯⎯⎯⎯⎯ Failed Suites 1 ⎯⎯⎯⎯⎯⎯⎯ - - FAIL   server  src/lib/server/embeddings/embedding.service.test.ts [ src/lib/server/embeddings/embedding.service.test.ts ] -Error: Transform failed with 1 error: -/home/moze/Sources/trueref/src/lib/server/embeddings/embedding.service.test.ts:408:2: ERROR: "await" can only be used inside an "async" function - Plugin: vite:esbuild - File: /home/moze/Sources/trueref/src/lib/server/embeddings/embedding.service.test.ts:408:2 - - "await" can only be used inside an "async" function - 406 | }); - 407 | - 408 | await service.embedSnippets([snippetId]); - | ^ - 409 | - 410 | const retrieved = service.getEmbedding(snippetId); -  - ❯ failureErrorWithLog node_modules/vite/node_modules/esbuild/lib/main.js:1748:15 - ❯ node_modules/vite/node_modules/esbuild/lib/main.js:1017:50 - ❯ responseCallbacks. node_modules/vite/node_modules/esbuild/lib/main.js:884:9 - ❯ handleIncomingPacket node_modules/vite/node_modules/esbuild/lib/main.js:939:12 - ❯ Socket.readFromStdout node_modules/vite/node_modules/esbuild/lib/main.js:862:7 - -⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[1/36]⎯ - - -⎯⎯⎯⎯⎯⎯ Failed Tests 35 ⎯⎯⎯⎯⎯⎯⎯ - - FAIL   server  src/lib/server/db/schema.test.ts > repositories table > inserts and retrieves a repository - FAIL   server  src/lib/server/db/schema.test.ts > repositories table > allows nullable optional fields - FAIL   server  src/lib/server/db/schema.test.ts > repositories table > supports all state enum values -DrizzleError: Failed to run the query ' -INSERT INTO `__new_snippet_embeddings`("snippet_id", "profile_id", "model", "dimensions", "embedding", "created_at") SELECT "snippet_id", "profile_id", "model", "dimensions", "embedding", "created_at" FROM `snippet_embeddings`;' - ❯ BetterSQLiteSession.run node_modules/src/sqlite-core/session.ts:271:9 - ❯ SQLiteSyncDialect.migrate node_modules/src/sqlite-core/dialect.ts:864:14 - ❯ migrate node_modules/src/better-sqlite3/migrator.ts:10:12 - ❯ createTestDb src/lib/server/db/schema.test.ts:32:2 -  30| // Run migrations from the generated migration folder. -  31| const migrationsFolder = join(import.meta.dirname, 'migrations'); -  32| migrate(db, { migrationsFolder }); -  | ^ -  33| -  34| // Apply FTS5 DDL using exec() which handles multi-statement SQL with… - ❯ src/lib/server/db/schema.test.ts:63:13 - -Caused by: SqliteError: no such column: "profile_id" - should this be a string literal in single-quotes? - ❯ Database.prepare node_modules/better-sqlite3/lib/methods/wrappers.js:5:21 - ❯ BetterSQLiteSession.prepareQuery node_modules/drizzle-orm/better-sqlite3/session.js:23:30 - ❯ BetterSQLiteSession.prepareOneTimeQuery node_modules/drizzle-orm/sqlite-core/session.js:141:17 - ❯ BetterSQLiteSession.run node_modules/drizzle-orm/sqlite-core/session.js:154:19 - ❯ SQLiteSyncDialect.migrate node_modules/drizzle-orm/sqlite-core/dialect.js:604:21 - ❯ migrate node_modules/drizzle-orm/better-sqlite3/migrator.js:4:14 - ❯ createTestDb src/lib/server/db/schema.test.ts:32:2 - ❯ src/lib/server/db/schema.test.ts:63:13 - -⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ -Serialized Error: { code: 'SQLITE_ERROR' } -⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[2/36]⎯ - - FAIL   server  src/lib/server/db/schema.test.ts > repository_versions table > inserts a version linked to a repository - FAIL   server  src/lib/server/db/schema.test.ts > repository_versions table > cascades delete when parent repository is deleted -DrizzleError: Failed to run the query ' -INSERT INTO `__new_snippet_embeddings`("snippet_id", "profile_id", "model", "dimensions", "embedding", "created_at") SELECT "snippet_id", "profile_id", "model", "dimensions", "embedding", "created_at" FROM `snippet_embeddings`;' - ❯ BetterSQLiteSession.run node_modules/src/sqlite-core/session.ts:271:9 - ❯ SQLiteSyncDialect.migrate node_modules/src/sqlite-core/dialect.ts:864:14 - ❯ migrate node_modules/src/better-sqlite3/migrator.ts:10:12 - ❯ createTestDb src/lib/server/db/schema.test.ts:32:2 -  30| // Run migrations from the generated migration folder. -  31| const migrationsFolder = join(import.meta.dirname, 'migrations'); -  32| migrate(db, { migrationsFolder }); -  | ^ -  33| -  34| // Apply FTS5 DDL using exec() which handles multi-statement SQL with… - ❯ src/lib/server/db/schema.test.ts:109:13 - -Caused by: SqliteError: no such column: "profile_id" - should this be a string literal in single-quotes? - ❯ Database.prepare node_modules/better-sqlite3/lib/methods/wrappers.js:5:21 - ❯ BetterSQLiteSession.prepareQuery node_modules/drizzle-orm/better-sqlite3/session.js:23:30 - ❯ BetterSQLiteSession.prepareOneTimeQuery node_modules/drizzle-orm/sqlite-core/session.js:141:17 - ❯ BetterSQLiteSession.run node_modules/drizzle-orm/sqlite-core/session.js:154:19 - ❯ SQLiteSyncDialect.migrate node_modules/drizzle-orm/sqlite-core/dialect.js:604:21 - ❯ migrate node_modules/drizzle-orm/better-sqlite3/migrator.js:4:14 - ❯ createTestDb src/lib/server/db/schema.test.ts:32:2 - ❯ src/lib/server/db/schema.test.ts:109:13 - -⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ -Serialized Error: { code: 'SQLITE_ERROR' } -⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[3/36]⎯ - - FAIL   server  src/lib/server/db/schema.test.ts > documents table > inserts a document - FAIL   server  src/lib/server/db/schema.test.ts > documents table > cascades delete when repository is deleted -DrizzleError: Failed to run the query ' -INSERT INTO `__new_snippet_embeddings`("snippet_id", "profile_id", "model", "dimensions", "embedding", "created_at") SELECT "snippet_id", "profile_id", "model", "dimensions", "embedding", "created_at" FROM `snippet_embeddings`;' - ❯ BetterSQLiteSession.run node_modules/src/sqlite-core/session.ts:271:9 - ❯ SQLiteSyncDialect.migrate node_modules/src/sqlite-core/dialect.ts:864:14 - ❯ migrate node_modules/src/better-sqlite3/migrator.ts:10:12 - ❯ createTestDb src/lib/server/db/schema.test.ts:32:2 -  30| // Run migrations from the generated migration folder. -  31| const migrationsFolder = join(import.meta.dirname, 'migrations'); -  32| migrate(db, { migrationsFolder }); -  | ^ -  33| -  34| // Apply FTS5 DDL using exec() which handles multi-statement SQL with… - ❯ src/lib/server/db/schema.test.ts:151:13 - -Caused by: SqliteError: no such column: "profile_id" - should this be a string literal in single-quotes? - ❯ Database.prepare node_modules/better-sqlite3/lib/methods/wrappers.js:5:21 - ❯ BetterSQLiteSession.prepareQuery node_modules/drizzle-orm/better-sqlite3/session.js:23:30 - ❯ BetterSQLiteSession.prepareOneTimeQuery node_modules/drizzle-orm/sqlite-core/session.js:141:17 - ❯ BetterSQLiteSession.run node_modules/drizzle-orm/sqlite-core/session.js:154:19 - ❯ SQLiteSyncDialect.migrate node_modules/drizzle-orm/sqlite-core/dialect.js:604:21 - ❯ migrate node_modules/drizzle-orm/better-sqlite3/migrator.js:4:14 - ❯ createTestDb src/lib/server/db/schema.test.ts:32:2 - ❯ src/lib/server/db/schema.test.ts:151:13 - -⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ -Serialized Error: { code: 'SQLITE_ERROR' } -⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[4/36]⎯ - - FAIL   server  src/lib/server/db/schema.test.ts > snippets table > inserts a code snippet - FAIL   server  src/lib/server/db/schema.test.ts > snippets table > inserts an info snippet - FAIL   server  src/lib/server/db/schema.test.ts > snippets table > cascades delete when document is deleted -DrizzleError: Failed to run the query ' -INSERT INTO `__new_snippet_embeddings`("snippet_id", "profile_id", "model", "dimensions", "embedding", "created_at") SELECT "snippet_id", "profile_id", "model", "dimensions", "embedding", "created_at" FROM `snippet_embeddings`;' - ❯ BetterSQLiteSession.run node_modules/src/sqlite-core/session.ts:271:9 - ❯ SQLiteSyncDialect.migrate node_modules/src/sqlite-core/dialect.ts:864:14 - ❯ migrate node_modules/src/better-sqlite3/migrator.ts:10:12 - ❯ createTestDb src/lib/server/db/schema.test.ts:32:2 -  30| // Run migrations from the generated migration folder. -  31| const migrationsFolder = join(import.meta.dirname, 'migrations'); -  32| migrate(db, { migrationsFolder }); -  | ^ -  33| -  34| // Apply FTS5 DDL using exec() which handles multi-statement SQL with… - ❯ src/lib/server/db/schema.test.ts:195:13 - -Caused by: SqliteError: no such column: "profile_id" - should this be a string literal in single-quotes? - ❯ Database.prepare node_modules/better-sqlite3/lib/methods/wrappers.js:5:21 - ❯ BetterSQLiteSession.prepareQuery node_modules/drizzle-orm/better-sqlite3/session.js:23:30 - ❯ BetterSQLiteSession.prepareOneTimeQuery node_modules/drizzle-orm/sqlite-core/session.js:141:17 - ❯ BetterSQLiteSession.run node_modules/drizzle-orm/sqlite-core/session.js:154:19 - ❯ SQLiteSyncDialect.migrate node_modules/drizzle-orm/sqlite-core/dialect.js:604:21 - ❯ migrate node_modules/drizzle-orm/better-sqlite3/migrator.js:4:14 - ❯ createTestDb src/lib/server/db/schema.test.ts:32:2 - ❯ src/lib/server/db/schema.test.ts:195:13 - -⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ -Serialized Error: { code: 'SQLITE_ERROR' } -⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[5/36]⎯ - - FAIL   server  src/lib/server/db/schema.test.ts > snippet_embeddings table > stores a Float32Array embedding as blob - FAIL   server  src/lib/server/db/schema.test.ts > snippet_embeddings table > cascades delete when snippet is deleted -DrizzleError: Failed to run the query ' -INSERT INTO `__new_snippet_embeddings`("snippet_id", "profile_id", "model", "dimensions", "embedding", "created_at") SELECT "snippet_id", "profile_id", "model", "dimensions", "embedding", "created_at" FROM `snippet_embeddings`;' - ❯ BetterSQLiteSession.run node_modules/src/sqlite-core/session.ts:271:9 - ❯ SQLiteSyncDialect.migrate node_modules/src/sqlite-core/dialect.ts:864:14 - ❯ migrate node_modules/src/better-sqlite3/migrator.ts:10:12 - ❯ createTestDb src/lib/server/db/schema.test.ts:32:2 -  30| // Run migrations from the generated migration folder. -  31| const migrationsFolder = join(import.meta.dirname, 'migrations'); -  32| migrate(db, { migrationsFolder }); -  | ^ -  33| -  34| // Apply FTS5 DDL using exec() which handles multi-statement SQL with… - ❯ src/lib/server/db/schema.test.ts:271:13 - -Caused by: SqliteError: no such column: "profile_id" - should this be a string literal in single-quotes? - ❯ Database.prepare node_modules/better-sqlite3/lib/methods/wrappers.js:5:21 - ❯ BetterSQLiteSession.prepareQuery node_modules/drizzle-orm/better-sqlite3/session.js:23:30 - ❯ BetterSQLiteSession.prepareOneTimeQuery node_modules/drizzle-orm/sqlite-core/session.js:141:17 - ❯ BetterSQLiteSession.run node_modules/drizzle-orm/sqlite-core/session.js:154:19 - ❯ SQLiteSyncDialect.migrate node_modules/drizzle-orm/sqlite-core/dialect.js:604:21 - ❯ migrate node_modules/drizzle-orm/better-sqlite3/migrator.js:4:14 - ❯ createTestDb src/lib/server/db/schema.test.ts:32:2 - ❯ src/lib/server/db/schema.test.ts:271:13 - -⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ -Serialized Error: { code: 'SQLITE_ERROR' } -⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[6/36]⎯ - - FAIL   server  src/lib/server/db/schema.test.ts > indexing_jobs table > creates a job with default queued status - FAIL   server  src/lib/server/db/schema.test.ts > indexing_jobs table > supports all status enum values -DrizzleError: Failed to run the query ' -INSERT INTO `__new_snippet_embeddings`("snippet_id", "profile_id", "model", "dimensions", "embedding", "created_at") SELECT "snippet_id", "profile_id", "model", "dimensions", "embedding", "created_at" FROM `snippet_embeddings`;' - ❯ BetterSQLiteSession.run node_modules/src/sqlite-core/session.ts:271:9 - ❯ SQLiteSyncDialect.migrate node_modules/src/sqlite-core/dialect.ts:864:14 - ❯ migrate node_modules/src/better-sqlite3/migrator.ts:10:12 - ❯ createTestDb src/lib/server/db/schema.test.ts:32:2 -  30| // Run migrations from the generated migration folder. -  31| const migrationsFolder = join(import.meta.dirname, 'migrations'); -  32| migrate(db, { migrationsFolder }); -  | ^ -  33| -  34| // Apply FTS5 DDL using exec() which handles multi-statement SQL with… - ❯ src/lib/server/db/schema.test.ts:350:13 - -Caused by: SqliteError: no such column: "profile_id" - should this be a string literal in single-quotes? - ❯ Database.prepare node_modules/better-sqlite3/lib/methods/wrappers.js:5:21 - ❯ BetterSQLiteSession.prepareQuery node_modules/drizzle-orm/better-sqlite3/session.js:23:30 - ❯ BetterSQLiteSession.prepareOneTimeQuery node_modules/drizzle-orm/sqlite-core/session.js:141:17 - ❯ BetterSQLiteSession.run node_modules/drizzle-orm/sqlite-core/session.js:154:19 - ❯ SQLiteSyncDialect.migrate node_modules/drizzle-orm/sqlite-core/dialect.js:604:21 - ❯ migrate node_modules/drizzle-orm/better-sqlite3/migrator.js:4:14 - ❯ createTestDb src/lib/server/db/schema.test.ts:32:2 - ❯ src/lib/server/db/schema.test.ts:350:13 - -⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ -Serialized Error: { code: 'SQLITE_ERROR' } -⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[7/36]⎯ - - FAIL   server  src/lib/server/db/schema.test.ts > repository_configs table > stores JSON array fields correctly -DrizzleError: Failed to run the query ' -INSERT INTO `__new_snippet_embeddings`("snippet_id", "profile_id", "model", "dimensions", "embedding", "created_at") SELECT "snippet_id", "profile_id", "model", "dimensions", "embedding", "created_at" FROM `snippet_embeddings`;' - ❯ BetterSQLiteSession.run node_modules/src/sqlite-core/session.ts:271:9 - ❯ SQLiteSyncDialect.migrate node_modules/src/sqlite-core/dialect.ts:864:14 - ❯ migrate node_modules/src/better-sqlite3/migrator.ts:10:12 - ❯ createTestDb src/lib/server/db/schema.test.ts:32:2 -  30| // Run migrations from the generated migration folder. -  31| const migrationsFolder = join(import.meta.dirname, 'migrations'); -  32| migrate(db, { migrationsFolder }); -  | ^ -  33| -  34| // Apply FTS5 DDL using exec() which handles multi-statement SQL with… - ❯ src/lib/server/db/schema.test.ts:391:13 - -Caused by: SqliteError: no such column: "profile_id" - should this be a string literal in single-quotes? - ❯ Database.prepare node_modules/better-sqlite3/lib/methods/wrappers.js:5:21 - ❯ BetterSQLiteSession.prepareQuery node_modules/drizzle-orm/better-sqlite3/session.js:23:30 - ❯ BetterSQLiteSession.prepareOneTimeQuery node_modules/drizzle-orm/sqlite-core/session.js:141:17 - ❯ BetterSQLiteSession.run node_modules/drizzle-orm/sqlite-core/session.js:154:19 - ❯ SQLiteSyncDialect.migrate node_modules/drizzle-orm/sqlite-core/dialect.js:604:21 - ❯ migrate node_modules/drizzle-orm/better-sqlite3/migrator.js:4:14 - ❯ createTestDb src/lib/server/db/schema.test.ts:32:2 - ❯ src/lib/server/db/schema.test.ts:391:13 - -⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ -Serialized Error: { code: 'SQLITE_ERROR' } -⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[8/36]⎯ - - FAIL   server  src/lib/server/db/schema.test.ts > settings table > stores and retrieves key-value settings -DrizzleError: Failed to run the query ' -INSERT INTO `__new_snippet_embeddings`("snippet_id", "profile_id", "model", "dimensions", "embedding", "created_at") SELECT "snippet_id", "profile_id", "model", "dimensions", "embedding", "created_at" FROM `snippet_embeddings`;' - ❯ BetterSQLiteSession.run node_modules/src/sqlite-core/session.ts:271:9 - ❯ SQLiteSyncDialect.migrate node_modules/src/sqlite-core/dialect.ts:864:14 - ❯ migrate node_modules/src/better-sqlite3/migrator.ts:10:12 - ❯ createTestDb src/lib/server/db/schema.test.ts:32:2 -  30| // Run migrations from the generated migration folder. -  31| const migrationsFolder = join(import.meta.dirname, 'migrations'); -  32| migrate(db, { migrationsFolder }); -  | ^ -  33| -  34| // Apply FTS5 DDL using exec() which handles multi-statement SQL with… - ❯ src/lib/server/db/schema.test.ts:422:13 - -Caused by: SqliteError: no such column: "profile_id" - should this be a string literal in single-quotes? - ❯ Database.prepare node_modules/better-sqlite3/lib/methods/wrappers.js:5:21 - ❯ BetterSQLiteSession.prepareQuery node_modules/drizzle-orm/better-sqlite3/session.js:23:30 - ❯ BetterSQLiteSession.prepareOneTimeQuery node_modules/drizzle-orm/sqlite-core/session.js:141:17 - ❯ BetterSQLiteSession.run node_modules/drizzle-orm/sqlite-core/session.js:154:19 - ❯ SQLiteSyncDialect.migrate node_modules/drizzle-orm/sqlite-core/dialect.js:604:21 - ❯ migrate node_modules/drizzle-orm/better-sqlite3/migrator.js:4:14 - ❯ createTestDb src/lib/server/db/schema.test.ts:32:2 - ❯ src/lib/server/db/schema.test.ts:422:13 - -⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ -Serialized Error: { code: 'SQLITE_ERROR' } -⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[9/36]⎯ - - FAIL   server  src/lib/server/db/schema.test.ts > FTS5 virtual table (snippets_fts) > FTS table exists and is queryable - FAIL   server  src/lib/server/db/schema.test.ts > FTS5 virtual table (snippets_fts) > insert trigger keeps FTS in sync - FAIL   server  src/lib/server/db/schema.test.ts > FTS5 virtual table (snippets_fts) > delete trigger removes entry from FTS -DrizzleError: Failed to run the query ' -INSERT INTO `__new_snippet_embeddings`("snippet_id", "profile_id", "model", "dimensions", "embedding", "created_at") SELECT "snippet_id", "profile_id", "model", "dimensions", "embedding", "created_at" FROM `snippet_embeddings`;' - ❯ BetterSQLiteSession.run node_modules/src/sqlite-core/session.ts:271:9 - ❯ SQLiteSyncDialect.migrate node_modules/src/sqlite-core/dialect.ts:864:14 - ❯ migrate node_modules/src/better-sqlite3/migrator.ts:10:12 - ❯ createTestDb src/lib/server/db/schema.test.ts:32:2 -  30| // Run migrations from the generated migration folder. -  31| const migrationsFolder = join(import.meta.dirname, 'migrations'); -  32| migrate(db, { migrationsFolder }); -  | ^ -  33| -  34| // Apply FTS5 DDL using exec() which handles multi-statement SQL with… - ❯ src/lib/server/db/schema.test.ts:442:21 - -Caused by: SqliteError: no such column: "profile_id" - should this be a string literal in single-quotes? - ❯ Database.prepare node_modules/better-sqlite3/lib/methods/wrappers.js:5:21 - ❯ BetterSQLiteSession.prepareQuery node_modules/drizzle-orm/better-sqlite3/session.js:23:30 - ❯ BetterSQLiteSession.prepareOneTimeQuery node_modules/drizzle-orm/sqlite-core/session.js:141:17 - ❯ BetterSQLiteSession.run node_modules/drizzle-orm/sqlite-core/session.js:154:19 - ❯ SQLiteSyncDialect.migrate node_modules/drizzle-orm/sqlite-core/dialect.js:604:21 - ❯ migrate node_modules/drizzle-orm/better-sqlite3/migrator.js:4:14 - ❯ createTestDb src/lib/server/db/schema.test.ts:32:2 - ❯ src/lib/server/db/schema.test.ts:442:21 - -⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ -Serialized Error: { code: 'SQLITE_ERROR' } -⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[10/36]⎯ - - FAIL   server  src/lib/server/search/hybrid.search.service.test.ts > VectorSearch > returns empty array when no embeddings exist -SqliteError: no such column: se.profile_id - ❯ Database.prepare node_modules/better-sqlite3/lib/methods/wrappers.js:5:21 - ❯ VectorSearch.vectorSearch src/lib/server/search/vector.search.ts:100:24 -  98| } -  99| - 100| const rows = this.db.prepare(sql).all(..… -  | ^ - 101| - 102| const scored: VectorSearchResult[] = rows.map((row) => { - ❯ src/lib/server/search/hybrid.search.service.test.ts:289:22 - -⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[11/36]⎯ - - FAIL   server  src/lib/server/search/hybrid.search.service.test.ts > VectorSearch > returns results sorted by descending cosine similarity -SqliteError: table snippet_embeddings has no column named profile_id - ❯ Database.prepare node_modules/better-sqlite3/lib/methods/wrappers.js:5:21 - ❯ seedEmbedding src/lib/server/search/hybrid.search.service.test.ts:112:4 - 110| const f32 = new Float32Array(values); - 111| client - 112| .prepare( -  | ^ - 113| `INSERT OR REPLACE INTO snippet_embeddings - 114| (snippet_id, profile_id, model, dimensions, embedding, create… - ❯ src/lib/server/search/hybrid.search.service.test.ts:302:3 - -⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[12/36]⎯ - - FAIL   server  src/lib/server/search/hybrid.search.service.test.ts > VectorSearch > respects the limit parameter -SqliteError: table snippet_embeddings has no column named profile_id - ❯ Database.prepare node_modules/better-sqlite3/lib/methods/wrappers.js:5:21 - ❯ seedEmbedding src/lib/server/search/hybrid.search.service.test.ts:112:4 - 110| const f32 = new Float32Array(values); - 111| client - 112| .prepare( -  | ^ - 113| `INSERT OR REPLACE INTO snippet_embeddings - 114| (snippet_id, profile_id, model, dimensions, embedding, create… - ❯ src/lib/server/search/hybrid.search.service.test.ts:321:4 - -⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[13/36]⎯ - - FAIL   server  src/lib/server/search/hybrid.search.service.test.ts > VectorSearch > only returns snippets from the specified repository -SqliteError: table snippet_embeddings has no column named profile_id - ❯ Database.prepare node_modules/better-sqlite3/lib/methods/wrappers.js:5:21 - ❯ seedEmbedding src/lib/server/search/hybrid.search.service.test.ts:112:4 - 110| const f32 = new Float32Array(values); - 111| client - 112| .prepare( -  | ^ - 113| `INSERT OR REPLACE INTO snippet_embeddings - 114| (snippet_id, profile_id, model, dimensions, embedding, create… - ❯ src/lib/server/search/hybrid.search.service.test.ts:340:3 - -⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[14/36]⎯ - - FAIL   server  src/lib/server/search/hybrid.search.service.test.ts > VectorSearch > handles embeddings with negative values -SqliteError: table snippet_embeddings has no column named profile_id - ❯ Database.prepare node_modules/better-sqlite3/lib/methods/wrappers.js:5:21 - ❯ seedEmbedding src/lib/server/search/hybrid.search.service.test.ts:112:4 - 110| const f32 = new Float32Array(values); - 111| client - 112| .prepare( -  | ^ - 113| `INSERT OR REPLACE INTO snippet_embeddings - 114| (snippet_id, profile_id, model, dimensions, embedding, create… - ❯ src/lib/server/search/hybrid.search.service.test.ts:352:3 - -⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[15/36]⎯ - - FAIL   server  src/lib/server/search/hybrid.search.service.test.ts > HybridSearchService > returns results when hybrid mode is active (alpha = 0.5) -SqliteError: table snippet_embeddings has no column named profile_id - ❯ Database.prepare node_modules/better-sqlite3/lib/methods/wrappers.js:5:21 - ❯ seedEmbedding src/lib/server/search/hybrid.search.service.test.ts:112:4 - 110| const f32 = new Float32Array(values); - 111| client - 112| .prepare( -  | ^ - 113| `INSERT OR REPLACE INTO snippet_embeddings - 114| (snippet_id, profile_id, model, dimensions, embedding, create… - ❯ src/lib/server/search/hybrid.search.service.test.ts:430:3 - -⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[16/36]⎯ - - FAIL   server  src/lib/server/search/hybrid.search.service.test.ts > HybridSearchService > deduplicates snippets appearing in both FTS5 and vector results -SqliteError: table snippet_embeddings has no column named profile_id - ❯ Database.prepare node_modules/better-sqlite3/lib/methods/wrappers.js:5:21 - ❯ seedEmbedding src/lib/server/search/hybrid.search.service.test.ts:112:4 - 110| const f32 = new Float32Array(values); - 111| client - 112| .prepare( -  | ^ - 113| `INSERT OR REPLACE INTO snippet_embeddings - 114| (snippet_id, profile_id, model, dimensions, embedding, create… - ❯ src/lib/server/search/hybrid.search.service.test.ts:449:3 - -⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[17/36]⎯ - - FAIL   server  src/lib/server/search/hybrid.search.service.test.ts > HybridSearchService > respects the limit option -SqliteError: table snippet_embeddings has no column named profile_id - ❯ Database.prepare node_modules/better-sqlite3/lib/methods/wrappers.js:5:21 - ❯ seedEmbedding src/lib/server/search/hybrid.search.service.test.ts:112:4 - 110| const f32 = new Float32Array(values); - 111| client - 112| .prepare( -  | ^ - 113| `INSERT OR REPLACE INTO snippet_embeddings - 114| (snippet_id, profile_id, model, dimensions, embedding, create… - ❯ src/lib/server/search/hybrid.search.service.test.ts:471:4 - -⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[18/36]⎯ - - FAIL   server  src/lib/server/search/hybrid.search.service.test.ts > HybridSearchService > returns vector-ranked results when alpha = 1 -SqliteError: table snippet_embeddings has no column named profile_id - ❯ Database.prepare node_modules/better-sqlite3/lib/methods/wrappers.js:5:21 - ❯ seedEmbedding src/lib/server/search/hybrid.search.service.test.ts:112:4 - 110| const f32 = new Float32Array(values); - 111| client - 112| .prepare( -  | ^ - 113| `INSERT OR REPLACE INTO snippet_embeddings - 114| (snippet_id, profile_id, model, dimensions, embedding, create… - ❯ src/lib/server/search/hybrid.search.service.test.ts:503:3 - -⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[19/36]⎯ - - FAIL   server  src/lib/server/search/hybrid.search.service.test.ts > HybridSearchService > results include snippet and repository metadata -SqliteError: table snippet_embeddings has no column named profile_id - ❯ Database.prepare node_modules/better-sqlite3/lib/methods/wrappers.js:5:21 - ❯ seedEmbedding src/lib/server/search/hybrid.search.service.test.ts:112:4 - 110| const f32 = new Float32Array(values); - 111| client - 112| .prepare( -  | ^ - 113| `INSERT OR REPLACE INTO snippet_embeddings - 114| (snippet_id, profile_id, model, dimensions, embedding, create… - ❯ src/lib/server/search/hybrid.search.service.test.ts:528:3 - -⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[20/36]⎯ - - FAIL   server  src/lib/server/search/hybrid.search.service.test.ts > HybridSearchService > all results belong to the requested repository -SqliteError: table snippet_embeddings has no column named profile_id - ❯ Database.prepare node_modules/better-sqlite3/lib/methods/wrappers.js:5:21 - ❯ seedEmbedding src/lib/server/search/hybrid.search.service.test.ts:112:4 - 110| const f32 = new Float32Array(values); - 111| client - 112| .prepare( -  | ^ - 113| `INSERT OR REPLACE INTO snippet_embeddings - 114| (snippet_id, profile_id, model, dimensions, embedding, create… - ❯ src/lib/server/search/hybrid.search.service.test.ts:556:4 - -⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[21/36]⎯ - - FAIL   server  src/lib/server/search/hybrid.search.service.test.ts > HybridSearchService > filters by snippet type when provided -SqliteError: table snippet_embeddings has no column named profile_id - ❯ Database.prepare node_modules/better-sqlite3/lib/methods/wrappers.js:5:21 - ❯ seedEmbedding src/lib/server/search/hybrid.search.service.test.ts:112:4 - 110| const f32 = new Float32Array(values); - 111| client - 112| .prepare( -  | ^ - 113| `INSERT OR REPLACE INTO snippet_embeddings - 114| (snippet_id, profile_id, model, dimensions, embedding, create… - ❯ src/lib/server/search/hybrid.search.service.test.ts:591:3 - -⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[22/36]⎯ - - FAIL   server  src/lib/server/search/hybrid.search.service.test.ts > HybridSearchService > uses alpha = 0.5 when not specified -SqliteError: table snippet_embeddings has no column named profile_id - ❯ Database.prepare node_modules/better-sqlite3/lib/methods/wrappers.js:5:21 - ❯ seedEmbedding src/lib/server/search/hybrid.search.service.test.ts:112:4 - 110| const f32 = new Float32Array(values); - 111| client - 112| .prepare( -  | ^ - 113| `INSERT OR REPLACE INTO snippet_embeddings - 114| (snippet_id, profile_id, model, dimensions, embedding, create… - ❯ src/lib/server/search/hybrid.search.service.test.ts:616:3 - -⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[23/36]⎯ - - FAIL   server  src/lib/server/search/hybrid.search.service.test.ts > HybridSearchService > filters by versionId — excludes snippets from other versions -SqliteError: no such table: embedding_profiles - ❯ Database.prepare node_modules/better-sqlite3/lib/methods/wrappers.js:5:21 - ❯ src/lib/server/search/hybrid.search.service.test.ts:647:5 - 645| // Create embedding profile - 646| client - 647| .prepare( -  | ^ - 648| `INSERT INTO embedding_profiles (id, provider_kind, title, enabled… - 649| VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)` - -⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[24/36]⎯ - - FAIL   server  src/lib/server/search/hybrid.search.service.test.ts > HybridSearchService > searchMode=keyword never calls provider.embed() -SqliteError: table snippets_fts has no column named id - ❯ Database.exec node_modules/better-sqlite3/lib/methods/wrappers.js:9:14 - ❯ src/lib/server/search/hybrid.search.service.test.ts:734:10 - 732| }); - 733| - 734| client.exec( -  | ^ - 735| `INSERT INTO snippets_fts (id, repository_id, version_id, title, br… - 736| VALUES ('${snippetId}', '${repoId}', NULL, NULL, NULL, 'keyword… - -⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[25/36]⎯ - - FAIL   server  src/lib/server/search/hybrid.search.service.test.ts > HybridSearchService > searchMode=semantic uses only vector search -SqliteError: no such table: embedding_profiles - ❯ Database.prepare node_modules/better-sqlite3/lib/methods/wrappers.js:5:21 - ❯ src/lib/server/search/hybrid.search.service.test.ts:772:5 - 770| // Create profile - 771| client - 772| .prepare( -  | ^ - 773| `INSERT INTO embedding_profiles (id, provider_kind, title, enabled… - 774| VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)` - -⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[26/36]⎯ - - - Test Files  3 failed | 19 passed (22) - Tests  35 failed | 416 passed (451) - Start at  19:10:26 - Duration  6.93s (transform 7.37s, setup 0ms, import 9.29s, tests 8.17s, environment 11ms) - - FAIL  Tests failed. Watching for file changes... - press h to show help, press q to quit -Cancelling test run. Press CTRL+c again to exit forcefully. -