OpenCode 1: covered — schema, identity, provider body, width check and routing fallback live in packages/plugin (shared core); doctor-opencode probe sends dimensions.
OpenCode 2: covered — same shared core (packages/plugin) and the same doctor-opencode probe.
Pi: covered — pi-plugin parses config with the core MagicContextConfigSchema and boots embeddings through the core resolveEmbeddingRouting / project registry; doctor-pi probe sends dimensions.
OMP: covered — runs through pi-plugin, same path as Pi.
Rust module: not applicable — surface does not exist there (the Rust crates store embedding rows but never call an embeddings endpoint). The dashboard's Rust Test Connection probe (packages/dashboard/src-tauri) is covered.
What this does
Adds embedding.dimensions for openai-compatible providers (Matryoshka output width, e.g. Qwen3-Embedding, text-embedding-3-*).
Area
Change
Schema
dimensions (positive int) on the openai-compatible block; carried through the transform, including the synapse block so an openai-compatible fallback keeps the width (the same P1 raised in #406). Local provider: not applicable.
Identity
Included only when set, in both identity computations (getEmbeddingProviderIdentity and the provider's own constructor). Unset configs hash byte-for-byte as before — the pinned legacy-hash test in project-embedding-registry.test.ts still passes, so no existing user is re-embedded. Chunk ids inherit it via the provider identity.
Config rebuilds
resolveEmbeddingConfig (registry), embedding.ts, embedding-routing.tsfallbackConfig, and EMBEDDING_AFFECTING_KEYS all pass it through.
Runtime
Request body carries dimensions. A batch whose returned width ≠ dimensions is rejected as a non-retryable failure instead of storing mixed-width vectors (which cosineSimilarity would silently score as 0).
Probe
doctor (OpenCode/Pi) and dashboard Test Connection (Rust embedding_probe.rs + ConfigEditor field) send dimensions and report a width mismatch rather than success.
Synapse
Deliberately not given a static dimensions: synapse pins its width from the first response (validateResponse).
Remaining local failures reproduce identically on a clean master checkout and are environmental: 4 plugin and 6 cli tests (identical failing-test set on master), local-pooling integration (needs HF model cache), content-language golden (Intl data of the local bun), gate.test (macOS bash 3.2 lacks mapfile).
Known follow-ups (not in this PR)
A local provider with dimensions set silently ignores it — could warn on load like other dropped keys.
A width mismatch surfaces to users as the generic MC-E04; the actionable reason ("remove dimensions or use a model that supports it") is only in logs and doctor.
Setting dimensions for the first time — even to the model's native width — changes identity and re-embeds once. Intentional; documented in the field description only as "changing the width re-embeds".
Summary by cubic
Adds embedding.dimensions for openai-compatible providers so a configured Matryoshka output width (e.g., Qwen3-Embedding-8B 768/1024/2048/4096, text-embedding-3-*) is sent on every embedding request and folded into the provider identity.
Optional positive integer (max 8192); sent only when set, so unset configs keep the same identity and are not re-embedded.
When set, a batch whose returned width differs is rejected as a non-retryable error instead of storing mixed-width vectors.
The synapse fallback config carries the width; the local provider does not support it.
dimensions is now a user-tier field, stripped from project config so a repository cannot override the width or its re-embed behavior.
doctor (OpenCode/Pi) and the dashboard Test Connection send dimensions within the runtime's 1–8192 bounds and flag a width mismatch rather than pass.
Confidence Score: 5/5
The PR appears safe to merge, with the existing non-blocking dashboard probe issue still outstanding.
Adds optional embedding.dimensions for OpenAI-compatible providers.
Embedding requests can use a chosen output width.
Embedding connection checks verify the requested vector width.
yiyi-wei lists three known follow-ups: local providers ignore the field, runtime errors use generic MC-E04 messaging, and first setting a width changes identity even when it matches the model’s default. These were not reported again.
Diagram
%%{init: {'theme': 'neutral'}}%%
flowchart TD
C[User embedding config] --> R{Selected provider}
R -->|OpenAI-compatible| O[Keep configured dimensions]
R -->|Synapse unavailable| F[Build fallback config]
F -->|OpenAI-compatible| O
O --> I[Include width in provider identity]
O --> Q[Send width with embedding request]
Q --> W{Returned width matches?}
W -->|Yes| V[Return vectors]
W -->|No| E[Reject batch]