Skip to content

fix(rag): reconcile Ollama's declared dimensions against the real vector - #1541

Merged
borisno2 merged 2 commits into
mainfrom
claude/jolly-turing-kqsdwv
Sep 13, 2026
Merged

borisno2 merged 2 commits into
mainfrom
claude/jolly-turing-kqsdwv

Conversation

@borisno2

Copy link
Copy Markdown
Member

Summary

  • OllamaEmbeddingProvider.embed() now compares the model's actual returned vector length against the declared dimensions and throws immediately if they differ, naming the model, the declared width, and the real one.
  • Previously the declared width was never reconciled against reality: a wrong OLLAMA_EMBEDDING_DIMENSIONS (or field dimensions) stamped a false column width at generation time, the index was written with that false width and "looked fine," and the mismatch only surfaced later — an opaque 500 at search time, or in embedBatch, silent zero-padding at the wrong width producing a ragged batch instead of a named failure.
  • This closes the related loose end noted in the issue comment about DEFAULT_OLLAMA_DIMENSIONS ignoring the model: once a mismatch is caught at embed() time, that gap now produces a named failure instead of ragged batch widths.
  • Documented (in docs/README.md) that the docs site's committed search index (.embeddings/docs.json) is tied to whichever embedding provider generated it (currently OpenAI, 1536 dimensions), and has to be regenerated with EMBEDDING_PROVIDER=ollama pnpm generate:embeddings before local Ollama-backed search works against it — this is the third item from the issue ("document the requirement where someone setting that variable will see it").

Test plan

  • Added tests in packages/rag/src/providers/providers.test.ts covering: a dimension mismatch failing with a message naming the model/declared/real widths, a matching width passing through unchanged, and embedBatch failing the whole batch with a named error rather than padding a ragged width.
  • pnpm build (core, ui, rag)
  • pnpm test in packages/rag — 255 passed
  • pnpm lint at repo root
  • pnpm format / pnpm manypkg fix

Closes #1288

🤖 Generated with Claude Code

https://claude.ai/code/session_01E5rczwjjc8CUDVQ4Z66ZQn


Generated by Claude Code

OllamaEmbeddingProvider.embed() now compares the model's actual returned
vector length against the declared `dimensions` and fails immediately,
naming the model, the declared width and the real one. Previously the
declaration was never checked against reality: a wrong width stamped a
false column size at generation time, and the mismatch only surfaced
later as an opaque 500 at search time (or, in embedBatch, as a ragged
batch of vectors padded to the wrong width).

Also documents (docs/README.md) that the docs site's committed search
index is tied to whichever provider generated it, and has to be
regenerated with EMBEDDING_PROVIDER=ollama before local Ollama search
works against it.

Closes #1288

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E5rczwjjc8CUDVQ4Z66ZQn
@changeset-bot

changeset-bot Bot commented Sep 13, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: f4ce487

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 9 packages
Name Type
@opensaas/stack-rag Patch
@opensaas/stack-cli Patch
@opensaas/stack-auth Patch
@opensaas/stack-core Patch
@opensaas/stack-storage-s3 Patch
@opensaas/stack-storage-vercel Patch
@opensaas/stack-storage Patch
@opensaas/stack-tiptap Patch
@opensaas/stack-ui Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@vercel

vercel Bot commented Sep 13, 2026

Copy link
Copy Markdown

Deployment failed for project stack-docs with the following error:

Resource is limited - try again in 24 hours (more than 100, code: "api-deployments-free-per-day").

Learn More: https://vercel.com/open-saas?upgradeToPro=build-rate-limit

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

Copy link
Copy Markdown
Member Author

The Vercel status check is failing with Deployment rate limited — retry in 24 hours (more than 100, code: "api-deployments-free-per-day"). That's the docs-site preview deployment hitting Vercel's free-tier daily deployment quota — an account-wide limit unrelated to this PR's diff (which doesn't touch docs/app build output beyond a README edit), and there's no fix to push for it; it clears on its own once the 24-hour window resets. The GitHub Actions checks (test, e2e (postgres), e2e (dev-database), example-gates) are the ones that actually exercise this change and are still running.


Generated by Claude Code

@borisno2 borisno2 left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Code review (effort: medium-high)

Reviewed the full diff plus the surrounding code the change interacts with (packages/rag/src/config/plugin.ts's autoGenerate hook, packages/rag/src/config/generation-failure.ts's error classification, and OpenAIEmbeddingProvider for comparison). The core fix — comparing response.embedding.length against this.dimensions and throwing a named error before embed() returns — is correct, matches issue #1288's description, and the error message correctly names the model, the declared width, and the actual width. The changeset and docs/README.md update are accurate and consistent with the code change; OpenAIEmbeddingProvider doesn't need an analogous check since it derives dimensions from a static per-model map rather than a user-declared value.

Three findings, in descending order of importance:

1. The new error isn't recognized by the generation-failure reporter (not inline — file untouched by this PR)

packages/rag/src/config/generation-failure.tscreateGenerationFailureReporter

In the one real runtime path that triggers this check (the autoGenerate hook, packages/rag/src/config/plugin.ts ~lines 296-319), the new dimension-mismatch error falls into the generic non-standing-defect bucket, which tells operators to "retry by writing the source field again." A dimension mismatch is a pure config defect — every row will fail identically until dimensions / OLLAMA_EMBEDDING_DIMENSIONS is corrected — so it deserves the same clean, deduplicated, config-focused diagnosis this reporter already gives for other permanent misconfigurations (unregistered provider type, refused write, missing writer), rather than a console.error-per-row wall of duplicate stack traces suggesting a fix that can never work.

2. Dimension check dereferences response.embedding.length outside the try/catch (inline comment on packages/rag/src/providers/ollama.ts:84)

A malformed 200 response missing embedding now throws a raw, unwrapped TypeError instead of the friendly Ollama embedding generation failed: ... message every other failure path in this method produces — regressing the previous (also wrong, but non-crashing) behavior of silently returning undefined. Suggest bringing the check inside the try, or wrapping it separately, so this failure mode gets the same clear diagnosis.

3. Manual vi.unstubAllGlobals() instead of afterEach (inline comment on packages/rag/src/providers/providers.test.ts:281)

The embedBatch dimension-mismatch test cleans up the fetch stub manually after its assertion, unlike the sibling describe block immediately above it which uses afterEach correctly. If the assertion ever fails, the stub leaks into later tests in the file, turning one clear failure into confusing cascading ones.

Other angles checked

  • embedBatch error-wrapping: confirmed it still surfaces the inner error's message usefully — embedBatch wraps failures from embed() in a way that preserves the named dimension-mismatch text, matching the PR's stated intent and the added test's assertion.
  • Test coverage of the new path: the stubbed-fetch tests do exercise the real embed()/embedBatch() code path (they don't stub makeRequest or the check itself), and cover both the mismatch and matching-width cases. Sound apart from finding #3 above.
  • Comment density (package CLAUDE.md rule): the new 7-line comment above the if check in ollama.ts carries real, non-obvious rationale (why the check lives here rather than elsewhere in the pipeline, and what silently breaks without it) rather than restating the code — consistent with the repo's comment guidance.
  • No simplification/efficiency issues found beyond the above; the happy-path logic is minimal and correct.

🤖 Generated with Claude Code

https://claude.ai/code/session_01E5rczwjjc8CUDVQ4Z66ZQn


Generated by Claude Code

Comment thread packages/rag/src/providers/ollama.ts Outdated
Comment thread packages/rag/src/providers/providers.test.ts Outdated
@borisno2
borisno2 enabled auto-merge (squash) September 13, 2026 11:24
- Move the dimension check inside embed()'s try block so a malformed
  response missing `embedding` gets the same wrapped
  "Ollama embedding generation failed: ..." diagnosis as every other
  failure path, instead of a raw unwrapped TypeError.
- Classify a dimension-mismatch error in generation-failure.ts's
  reporter as a standing configuration defect (like an unregistered
  provider type or a refused write), so the autoGenerate hook stops
  telling operators to "retry" a failure that can never clear on its
  own, and logs it once per field instead of once per row.
- Fix a test-hygiene issue: the new embedBatch test now unstubs
  `fetch` in `afterEach` instead of manually after its assertion, so a
  failing assertion can't leak the stub into later tests.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E5rczwjjc8CUDVQ4Z66ZQn

Copy link
Copy Markdown
Member Author

Pushed f4ce487 addressing all three review findings:

  1. generation-failure.ts classification — added isDimensionMismatch() and a reporter branch so the autoGenerate hook now reports a declared-dimensions mismatch as a standing configuration defect (like an unregistered provider type or a refused write), rather than the generic bucket that tells operators to "retry" a failure that can never clear. Added a test in plugin.test.ts covering it (a misdeclared fake provider that throws the same message shape OllamaEmbeddingProvider does).
  2. Dimension check outside the try/catch — moved inside embed()'s try block, so a malformed response gets the same wrapped Ollama embedding generation failed: ... diagnosis as every other failure path here, instead of a raw TypeError.
  3. Manual vi.unstubAllGlobals() — moved into an afterEach on the test's own nested describe, matching the sibling block above it.

All 256 tests pass (pnpm test in packages/rag), plus pnpm build, pnpm lint, and pnpm format at the repo root.


Generated by Claude Code

@borisno2
borisno2 merged commit e589b2c into main Sep 13, 2026
6 of 7 checks passed
@borisno2
borisno2 deleted the claude/jolly-turing-kqsdwv branch September 13, 2026 11:44
@github-actions

Copy link
Copy Markdown
Contributor

Coverage Report for Core Package Coverage (./packages/core)

Status Category Percentage Covered / Total
🟢 Lines 93.11% (🎯 81%) 3811 / 4093
🟢 Statements 91.1% (🎯 76%) 4300 / 4720
🟢 Functions 95.42% (🎯 78%) 834 / 874
🟢 Branches 85.77% (🎯 71%) 2894 / 3374
File CoverageNo changed files found.
Generated in workflow #2478 for commit f4ce487 by the Vitest Coverage Report Action

@github-actions

Copy link
Copy Markdown
Contributor

Coverage Report for UI Package Coverage (./packages/ui)

Status Category Percentage Covered / Total
🔵 Lines 78.7% 244 / 310
🔵 Statements 78.43% 251 / 320
🔵 Functions 69.81% 74 / 106
🔵 Branches 67.51% 160 / 237
File CoverageNo changed files found.
Generated in workflow #2478 for commit f4ce487 by the Vitest Coverage Report Action

@github-actions

Copy link
Copy Markdown
Contributor

Coverage Report for CLI Package Coverage (./packages/cli)

Status Category Percentage Covered / Total
🔵 Lines 82.28% 1992 / 2421
🔵 Statements 82% 2142 / 2612
🔵 Functions 87.91% 342 / 389
🔵 Branches 75.17% 1066 / 1418
File CoverageNo changed files found.
Generated in workflow #2478 for commit f4ce487 by the Vitest Coverage Report Action

@github-actions

Copy link
Copy Markdown
Contributor

Coverage Report for Auth Package Coverage (./packages/auth)

Status Category Percentage Covered / Total
🔵 Lines 91.2% 280 / 307
🔵 Statements 89.94% 313 / 348
🔵 Functions 96.05% 73 / 76
🔵 Branches 82.38% 262 / 318
File CoverageNo changed files found.
Generated in workflow #2478 for commit f4ce487 by the Vitest Coverage Report Action

@github-actions

Copy link
Copy Markdown
Contributor

Coverage Report for Storage Package Coverage (./packages/storage)

Status Category Percentage Covered / Total
🔵 Lines 90.11% 301 / 334
🔵 Statements 90.27% 334 / 370
🔵 Functions 96.9% 94 / 97
🔵 Branches 86.44% 319 / 369
File CoverageNo changed files found.
Generated in workflow #2478 for commit f4ce487 by the Vitest Coverage Report Action

@github-actions

Copy link
Copy Markdown
Contributor

Coverage Report for RAG Package Coverage (./packages/rag)

Status Category Percentage Covered / Total
🔵 Lines 91.98% 597 / 649
🔵 Statements 91.35% 655 / 717
🔵 Functions 97.54% 119 / 122
🔵 Branches 85.65% 424 / 495
File Coverage
File Stmts Branches Functions Lines Uncovered Lines
Changed Files
packages/rag/src/config/generation-failure.ts 100% 93.75% 100% 100%
packages/rag/src/providers/ollama.ts 96.07% 96.87% 100% 95.91% 49-50
Generated in workflow #2478 for commit f4ce487 by the Vitest Coverage Report Action

@github-actions

Copy link
Copy Markdown
Contributor

Coverage Report for Storage S3 Package Coverage (./packages/storage-s3)

Status Category Percentage Covered / Total
🔵 Lines 100% 40 / 40
🔵 Statements 100% 40 / 40
🔵 Functions 100% 9 / 9
🔵 Branches 100% 19 / 19
File CoverageNo changed files found.
Generated in workflow #2478 for commit f4ce487 by the Vitest Coverage Report Action

@github-actions

Copy link
Copy Markdown
Contributor

Coverage Report for Storage Vercel Package Coverage (./packages/storage-vercel)

Status Category Percentage Covered / Total
🔵 Lines 100% 68 / 68
🔵 Statements 100% 71 / 71
🔵 Functions 100% 15 / 15
🔵 Branches 97.87% 46 / 47
File CoverageNo changed files found.
Generated in workflow #2478 for commit f4ce487 by the Vitest Coverage Report Action

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

A provider's declared dimensions is never reconciled with the vectors it returns

2 participants