test(ci): isolate witness fixture and search mocks

This commit is contained in:
Rudy Celekli committed 2026-09-27 10:30:47 -04:00
1 parent 44ac70aa39
commit 24a80bd75d
4 files changed
+37 -7

No files matched your search

@@ -0,0 +1,20 @@
{
"manifest": {
"schema": "ruflo-witness/v1",
"gitCommit": "synthetic-smoke-test-fixture",
"fixes": [
{
"id": "test-source",
"desc": "Synthetic source-only strict verification fixture",
"file": "source.js",
"sha256": "7efd9d12f48223fce735bfca349a8f96bcdc888d2dc8b8cfe3364cc545dd6a6e",
"marker": "witnessSmokeMarker"
}
]
},
"integrity": {
"manifestHash": "3fdc9d312a7364e8c4a9e55f48c858f51e3289f2184bb99714ea1863a7c1b92b",
"publicKey": "d6b01eb8cf88be0eac71ff419ea32fc8c34de1e1790ff5c709a6fda16c71b6ac",
"signature": "00ca3722db547fc5eb9af57b8ade4ef082cbb4d3657bba7ea9cc1b655652daedc8f52c98425a2629767770ebc6f455069f089398be416e5df1f85f80eab99d0f"
}
}
@@ -0,0 +1,2 @@
// Synthetic witness smoke-test fixture; not a release artifact.
export const witnessSmokeMarker = true;
@@ -95,9 +95,13 @@ try {
&& sourceResult?.signature?.publicKeyReproducible === true,
`signature=${JSON.stringify(sourceResult?.signature)}`,
);
const strictClean = run(tmp, REAL_MANIFEST, '--source-only', '--strict');
// The release witness hashes a historical tree, so legitimate later source
// changes may drift. Test the zero-drift path against a fixed signed fixture.
const fixtureRoot = resolve(REPO_ROOT, 'scripts/fixtures/witness-source-only');
const fixtureManifest = join(fixtureRoot, 'manifest.json');
const strictClean = run(fixtureRoot, fixtureManifest, '--source-only', '--strict');
record(
'--strict accepts an unchanged source tree',
'--strict accepts the unchanged signed test fixture',
strictClean.status === 0 && parseOutput(strictClean)?.summary?.drift === 0,
`exit=${strictClean.status}, output=${strictClean.stdout.slice(0, 300)}`,
);
@@ -25,7 +25,11 @@ interface SearchResponse {
smartFallback?: string;
stats?: { variantCount: number; rawCandidateCount: number };
}
let memoryModuleFactory: () => object | Promise<object>;
async function search(input: Record<string, unknown>): Promise<SearchResponse> {
// Register once per search: two queued doMock calls for this resolved ID
// can finish out of order while Vite resolves their module IDs.
vi.doMock('/@id/@claude-flow/memory', memoryModuleFactory);
const { memoryTools } = await import('../src/mcp-tools/memory-tools.js');
return memoryTools.find(t => t.name === 'memory_search')!.handler(input) as Promise<SearchResponse>;
}
@@ -37,7 +41,7 @@ beforeEach(() => {
// are faked; this exercises the real MCP handler and its response whitelist.
// The CLI's externalize-optional-deps plugin rewrites this dynamic import
// to /@id/...; mock that resolved ID so Vitest 4 intercepts the import.
vi.doMock('/@id/@claude-flow/memory', async () => import('../../memory/src/smart-retrieval.js'));
memoryModuleFactory = async () => import('../../memory/src/smart-retrieval.js');
});
afterEach(() => vi.restoreAllMocks());
@@ -108,10 +112,10 @@ describe('memory_search score contract (#3327 Finding B)', () => {
});
it.each(['missing export', 'import failure'])('preserves standard fallback on %s', async (reason) => {
vi.doMock('/@id/@claude-flow/memory', () => {
memoryModuleFactory = () => {
if (reason === 'import failure') throw new Error('unavailable package');
return { smartSearch: undefined };
});
};
searchEntries.mockResolvedValue({ success: true, results: [entry('a', 0.49)] });
const result = await search({ query: 'alpha', smart: true });
expect(result.results).toEqual([{
@@ -123,14 +127,14 @@ describe('memory_search score contract (#3327 Finding B)', () => {
});
it('supplies rawScore to older SmartRetrieval implementations that preserve candidate fields', async () => {
vi.doMock('/@id/@claude-flow/memory', () => ({
memoryModuleFactory = () => ({
// The existing return projection is {...candidate, score}. This fake
// deliberately does not create rawScore: the MCP adapter must supply it.
smartSearch: async (rawSearch: (request: RawSearchRequest) => Promise<{ results: object[] }>) => {
const raw = await rawSearch({ query: 'alpha' });
return { results: raw.results.map(r => ({ ...r, score: 0.05 })), stats: {} };
},
}));
});
searchEntries.mockResolvedValue({ success: true, results: [entry('a', 0)] });
const result = await search({ query: 'alpha', smart: true, threshold: 0 });
expect(result.results[0].similarity).toBe(0);