Repository navigation
Conversation
… for the Ask box ondocs index with OPENAI_API_KEY and no --embedding built text-embedding-3-small at its full 1,536 dimensions, while the plugins build it at 512 and the docs assume 512. The README's Next.js line and the commands init prints pass no --dimensions, so they shipped the larger index: 3,073,665 bytes against 1,614,214 for docusaurus.io's 1,070 chunks. The CLI's default model, with OpenAI or through AI Gateway, is now built at 512 unless --dimensions gives a size; a model named with --embedding keeps its own size, as in the plugins. An index built at 1,536 keeps working, since the endpoint reads the size from it, and the next build embeds every chunk again once. A plugin build without a model key now adds a second warning line: the Ask box then answers only questions that use enough of the docs' own words, and the key belongs where the site builds as well as where the endpoint runs. The first line stays as troubleshooting.md quotes it. Over a mock index, a similarity counts only from a chunk that shares two of the question's words, not one. On docusaurus.io's docs, 15 off-topic Stack Overflow titles got 6 quoted answers instead of 10; on the ondocs docs, 4 instead of 7. similarityNeedsKeyword takes the number of words; true is still one. The docs present embeddings as the default for the Ask box (OpenAI with a key, Workers AI's BGE-small for the Worker), keyword-only as what the MCP endpoint uses and the no-key fallback, and say that mock mode's gate is permissive. The Worker template's README embeds with Workers AI in its commands and plugin snippets.
The paragraph this branch added to getting-started.md pushed the Next.js example's /docs/getting-started to 180.1 KB of JavaScript against its 180 KB budget, since Next.js serializes the page into its inline RSC script. It is gone: cli.md, retrieval.md and deployment.md already say the same. The four getting-started pages match main again. The changeset is minor: the CLI's default index changes size, so the next build of every CLI user with a key embeds every chunk again, and similarityNeedsKeyword takes a number. On the ondocs docs this branch ships, the two-word mock gate lets 5 of the 15 off-topic titles through, not 4 (one word: 7). The README names the Workers AI Worker's index command, with its Cloudflare variables, or -e none, in the "Any other site" block. The Worker template's README says beside its plugin snippets that the embedding line needs CLOUDFLARE_ACCOUNT_ID and CLOUDFLARE_API_TOKEN where the site builds. The mock gate counts shared words from the BM25 postings the search already walks (Bm25Result.matchedTerms) instead of tokenizing each candidate chunk again. Results are the same; on docusaurus.io's 1,070 chunk mock index, retrieve() p95 goes from 1.73 ms back to 0.62 ms.
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Roadmap item: od-embed-defaults (OD2-34 + OD2-40, wave 3).
What was wrong
OD2-34. With
OPENAI_API_KEYset and no--embedding,ondocs indexbuilttext-embedding-3-smallat its full 1,536 dimensions (src/cli/main.tspassed no size), while the plugins build it at 512 (DEFAULT_DIMENSIONSinsrc/integration/build.ts) and the docs assume 512. The README's Next.js line and the index commandsondocs initprints pass no--dimensions, so a site that followed them shipped the larger index. On main, against the local OpenAI stub (scripts/openai-stub.mjs), docusaurus.io's docs at the pinned commit (1,070 chunks):ondocs indexon docusaurus.io's docsretrieve()p50--dimensions 512(this branch's default)-e none(keyword-only), for scaleThe p50 is 500 searches with a random query vector, two runs each, on a shared 10-core Mac (1-minute load average about 16 when it ran), so read it as a ratio.
OD2-40. The docs and the Worker template presented keyword-only as the default for the Ask box: the README's static-site command and the Worker template's README both said
-e none. The plugins' "No embedding model" warning said nothing about what a keyword-only index means for the Ask box, or that the key has to be where the site builds and not only where the endpoint runs. And the mock gate (-e mock, the README's "Try it without a key") counted a similarity from any chunk that shared one word with the question, so on main a mock index of docusaurus.io's docs answered 10 of 15 off-topic Stack Overflow titles (git, Bash, SQL, Java) by quoting unrelated pages, and a mock index of the ondocs docs answered 7.What changed
src/cli/main.ts: without--embeddingor a config model, the default model (OpenAI, or the same model through AI Gateway) is built atDEFAULT_DIMENSIONS(512), imported fromsrc/integration/build.ts, unless--dimensionsgives a size. A model named with--embeddingkeeps its own size, as the plugins'embeddingoption does (their test says so). The help says it. Check mode is unchanged:--checkwithout flags still names no model.src/integration/build.ts: a build without a model key prints a second warning line: the Ask box then answers only questions that use enough of the docs' own words, the MCP endpointondocs initwrites searches by keywords either way, and the key belongs where the site builds as well as where the endpoint runs (orembedding: 'none'to silence it). The first line is unchanged becausetroubleshooting.mdquotes it andtest/troubleshooting.test.tsxpins the quote, and neither file is in this bundle. No refusal percentage goes into the warning, as the brief's priority check advised.src/search/retrieve.ts,src/mock/index.ts: over a mock index, a similarity counts only from a chunk that shares two of the question's words (it was one).similarityNeedsKeywordnow also takes a number;truestill means one andfalsenone, so the type is only widened. Real-embedding indexes are unchanged (defaultfalse). The count comes from the BM25 search the gate already runs:Bm25Index.searchnow also returnsmatchedTerms, how many of the query's distinct terms each chunk contains, so no chunk is tokenized again. On docusaurus.io's 1,070-chunk mock index (430 questions, two runs),retrieve()takes p50 0.55 ms and p95 0.62 to 0.65 ms with two words, the same as with one; an earlier version of this branch, which tokenized each candidate chunk, took p95 1.73 to 1.76 ms.cli.md,deployment.md,local-development.md,retrieval.md,workers-ai.md, synced to the three examples), the README and the Worker template's README: embeddings are the documented default for the Ask box, with OpenAI'stext-embedding-3-smallwhen there is a key and Workers AI's BGE-small for the Worker (asinit --host github-pagesalready sets up). Keyword-only is what the MCP endpoint uses and the no-key fallback.cli.mdgives the 512 default and the upgrade path, andlocal-development.mdsays that mock mode's gate is permissive. The README's "Any other site" block names the index command for the Workers AI Worker thatinit --host github-pageswrites (-e workers-ai:@cf/baai/bge-small-en-v1.5withCLOUDFLARE_ACCOUNT_IDandCLOUDFLARE_API_TOKEN, or-e none), as code comments, because the README's prose is at its word limit (test/readme-claims.test.ts). The Worker template's README says beside its plugin snippets that theembeddingline needs those two variables where the site builds.getting-started.mdis unchanged. A paragraph there took the Next.js example's/docs/getting-startedto 180.1 KB of JavaScript against its 180 KB budget in CI (Next.js serializes the page into its inline RSC script, whichscripts/js-weight.mjscounts), andcli.md,retrieval.mdanddeployment.mdalready say the same.similarityNeedsKeywordandBm25Resultare widened. The plugins' move to 512 shipped as a minor too (0.6.0).Why two shared words, not keyword coverage of 0.3
The finding offered both. I measured both on the same sets:
Coverage ≥ 0.3 filters more, but it refuses "How much does the plan cost?" on a one-page site whose page says "The plan costs ten dollars a month." (coverage 0.29, because IDF over one page is flat). That is the case
test/astro-route.test.tscovers, and a small folder is how people try mock mode. Coverage thresholds also change the CJK counts thatlimits.mdquotes andtest/docs-claims.test.tschecks, which are outside this bundle. Two words pass the whole suite unchanged. On the audit's 22 questions, two words refuse one: "How do I add a tip or warning callout box?". Main answered it from/docs/migration/v3, a page that does not answer it. The six off-topic titles two words still let through on docusaurus.io cover half their keyword weight on a page (four, the same rule every embedded index uses) or share two words with it ("git" and "branch"). So the gate now lets through as many as a keyword-only index does.The 15 off-topic questions
Well-known Stack Overflow question titles, picked for this check as off-topic for both sites (not labelled by a person): How do I delete a Git branch locally and remotely? / How do I undo the most recent local commits in Git? / How do I check if a directory exists or not in a Bash shell script? / How do I tell if a file does not exist in Bash? / How do I return the response from an asynchronous call? / How can I remove a specific item from an array in JavaScript? / What does the "yield" keyword do in Python? / How do I make a time delay in Python? / How do I UPDATE from a SELECT in SQL Server? / How do I import an SQL file using the command line in MySQL? / How do I horizontally center an element? / How do I change the URI (URL) for a remote Git repository? / How do I efficiently iterate over each entry in a Java Map? / How do I check whether a checkbox is checked in jQuery? / Why is processing a sorted array faster than processing an unsorted array?
The docusaurus.io runs are
ondocs evalontest/eval/docusaurus.io.yamlplus these 15, againstondocs index <docs> --framework docusaurus --base-url /docs -e mock. The ondocs-docs runs callretrieve()withhashEmbeddingandMOCK_MIN_SIMILARITY, asondocs devdoes, on a-e mockindex ofexamples/nextjs/content/docs. The ondocs-docs columns of the table were measured on main's docs. On the docs this branch ships, one word lets 7 of the 15 through and two words 5, and the 5 suggested questions are all answered; the changeset quotes 5 instead of 7.What existing indexes must do
Nothing. I checked this on docusaurus.io's docs with this branch's CLI against the stub, starting from main's 1,536-dimension index:
ondocs index --checkwithout flags:is up to date (1070 chunks).ondocs index:1070 chunks, 1070 embedded, 0 reused, at 512 dimensions, 1,614,214 B. The build after that:0 embedded, 1070 reused.--dimensions 1536keeps the full size, and that build also embeds every chunk once (1070 embedded, 0 reused, 3,073,695 B), because the index now records the size as a setting.The endpoints,
ondocs devandondocs evalread the size from the index (queryProviderOptionsinsrc/server/shared.ts), so either size is served without a config change. Only an endpoint that setsdimensionsinembeddingProviderOptionsby hand has to match the index it serves. The changeset says all of this.How it was tested
New test files, so the shared
test/cli.test.tsandtest/mock.test.tsstay untouched (per the wave rules):test/embedding-defaults.test.ts: the CLI's default at 512 through the real HTTP stub,--dimensions 1536and a named model at its own size, the help, the upgrade path above (check passes, one full re-embed, then full reuse), AI Gateway at 512 when only its key is set, and the plugins' second warning line.test/mock-gate.test.ts: a one-shared-word off-topic question is refused on a mock index, two-word and whole-question matches still answer,similarityNeedsKeywordtakestrue, a number orfalse,Bm25Index.searchcounts each distinct query word once inmatchedTerms, and real-embedding indexes are unaffected.On main, 8 of these 11 tests fail, for the reasons above: 1,536 in the index, no 512 in the help,
0 embedded, 3 reusedon the rebuild, noproviderOptionsto AI Gateway, no second warning line, the off-topic question answered, and nomatchedTerms. The 3 guards pass on main and on this branch.Commands, all passing on this branch as it is now.
js-weightran from a copy of the script that startsnext starton a free port in 4100 to 4999 (the script picks one from 3100 to 3599 at random); nothing else differs. Locally the Next.js page measures 180 KB and main's 179.9 KB: the external scripts are byte-identical (159,536 B gzipped), and the 61 B of inline script between them is the page's "Last updated" line, which main's copy, exported without git history, does not render.Left out, and follow-ups
retrieval.md, which already has the measured keyword-only rates. OD2-39 (real-question evals and the proof page) is where numbers for embeddings versus keyword-only belong.src/cli/init.tsis unchanged. Its index commands get 512 from the new default, and its GitHub Pages flow already sets up BGE-small. Rewording its output would movetest/__snapshots__/init.test.ts.snap, which is outside this bundle.nextjs.mdis unchanged: it already passes--dimensions 512.troubleshooting.md(outside this bundle) quotes only the first warning line. It could quote the second.docusaurus.md(outside this bundle) gives the plugin'sdimensionsdefault as "the model's", but the plugin builds its default model at 512./docs/getting-startedsits at 179.9 KB in main's CI against 180 KB, so about 100 B of gzipped prose on that page fails CI. Raising the budget inscripts/js-weight.mjsis for the owner to decide, with a measured reason.