Repository navigation
fix(mcp-server): inject the adapter factory in tests, so CI cannot bypass the seam - #35
Merged
Merged
Conversation
…pass the seam Two embedder-wiring tests failed on every CI run since 2026-09-25: the mock recorded zero calls where one was expected. The lexical assertions in the same tests passed, so recall worked and only the mock count was wrong. The cause is not timing. createMemoFSMcpRuntimeFromConfig delegates the lazy adapter load to @memofs/core, which is consumed as a built dist and so sits outside vitest's module graph — vi.mock never intercepts the dynamic import there. CI builds core before testing (test:run depends on ^build), so the real adapter was constructed. Local runs only passed because resolution happened to differ. Three tests asserted the mock was *not* called, which passed trivially in CI and asserted nothing. All five now inject adapterFactory, the seam local-embedder already documented for exactly this purpose, so the assertions hold regardless of externalisation or install state. Threaded adapterFactory through RuntimeFactoryOptions. It is optional and production callers omit it, so the adapter remains an optional peer dependency and behaviour is unchanged. Verified: typecheck clean, biome clean, 48/48 in the mcp-server suite. Not reproducible locally, so the CI run is the real confirmation.
christophersesugh
added a commit
that referenced
this pull request
Oct 18, 2026
…nd warrants (#36) ## Two deterministic failures on main Both predate the mcp-server fix in #35 — they were masked by it short-circuiting the job. ### 1. `doctor` / `validate` failed on a freshly-initialised workspace ``` missing_file .memofs/trials/assignments.jsonl missing_file .memofs/trials/outcomes.jsonl missing_file .memofs/warrants/history.jsonl ``` `REQUIRED_FILES` was `CANONICAL_MEMOFS_FILES` — the *full* canonical set. The trials-ledger work added `BOOTSTRAP_FILE_PATHS` precisely because those paths are created lazily on first append so `init` output stays unchanged (its doc comment says so explicitly), but nothing repointed the CLI at it. `REQUIRED_DIRS` was already correct, so the two were inconsistent. - `REQUIRED_FILES` → `BOOTSTRAP_FILE_PATHS` (files that must exist) - new `SNAPSHOT_FILES` → `CANONICAL_MEMOFS_FILES` (capture what exists) `snapshot` moves to `SNAPSHOT_FILES`, preserving today's behaviour of including trial and warrant state in a snapshot once written. Silently narrowing the shared constant would have dropped that from snapshots. ### 2. Hosted schema URL disagreed with the published `$id` The CLI stamped `$schema: https://docs.memofs.dev/schema/connectors.json` into `.memofs/connectors.json`, but both hosted schemas and both packaged schemas declare `memofs.dev`. Confirmed against what is actually served — both hosts resolve and return byte-identical documents, and the `$id` inside is `memofs.dev`. The CLI constants were the outlier. Corrected both schema constants and the six stale test expectations, including a fixture in `@memofs/connectors`. The remaining `docs.memofs.dev` references are prose links that still resolve, so they are left for a separate sweep rather than bundled into a CI fix. ### 3. One flaky test `packs context for agent use` runs three in-process CLI commands against a real filesystem and measured **5025ms against vitest's 5000ms default** — a coin flip under parallel load. Given an explicit 30s timeout. ## Verified - `@memofs/cli` — **235/235**, twice - `doctor-validate` — 8/8 (was 5 failing) - `@memofs/connectors` — 98/98 - `connectors-schema` — 5/5 (was failing) - typecheck and biome clean ## Known remaining `turbo run test:run --force` still fails `@memofs/adapter-r2`, which passes **5/5 in isolation**. This suite is broadly load-sensitive — several tests sit near the 5s default and only fail when ~26 packages run in parallel. That is a separate systemic issue and not addressed here.
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.
Why main has been red since 2026-09-25
Two tests in
packages/mcp-server/tests/factory.test.tsfailed on every CI run:Root cause — not timing
The lexical assertions inside those same tests passed. Recall worked; only the mock call count was wrong. That ruled out a race.
createMemoFSMcpRuntimeFromConfigdelegates the lazy adapter load into@memofs/core. Core is consumed as a builtdist(exports→./dist/index.mjs) and therefore sits outside vitest's module graph — sovi.mock("@memofs/adapter-transformers")never intercepts theimport(adapterModule)inside it. CI builds core before testing (test:rundependsOn^build), so the real adapter was constructed while the mock recorded zero calls. Local runs only passed because resolution happened to differ, which is why this was not reproducible off-CI.Three further tests asserted the mock was not called — in CI those passed trivially and asserted nothing at all.
Fix
local-embedder.tsalready documented a seam for exactly this ("Injected factory for tests so the dynamic import is not exercised") but it was never plumbed through.adapterFactorythroughRuntimeFactoryOptions. Production callers omit it, so the adapter stays an optional peer dependency and behaviour is unchanged.vi.hoisted, and thebeforeEachreset.Verified
Typecheck clean, Biome clean, 48/48 in the mcp-server suite, changeset added per CONTRIBUTING.
Not reproducible locally, so this CI run is the real confirmation.
Note
The ruleset required a status check named
Quality Checks, which no workflow produces — onlyValidateexists. That has been corrected toValidate, and admins can now bypass on PR merge, so this is mergeable.This is also unblocking #32, #33, and #34.