{"record":{"id":"d35667cd15b03bb2","repo":"affaan-m/ECC","slug":"replay-no-store","errorCode":"replay.no_store","errorMessage":"a FixtureStore is required","messagePattern":"a FixtureStore is required","errorType":"error_code","errorClass":"ReplayError","httpStatus":null,"severity":"error","filePath":"scripts/lib/eval-harness/replay.js","lineNumber":98,"sourceCode":"      throw new ReplayError('tool.fixture_mismatch', `fixture ${key.slice(0, 16)} response hash does not match its content`, { tool, key });\n    }\n    return record;\n  }\n}\n\n/**\n * tools: { name: { effect_class, determinism: 'deterministic'|'nondeterministic', impl(args) } }\n * options: { mode: 'record'|'replay', store: FixtureStore, maxEffectClass: 'SE2', onCall(entry) }\n */\nfunction createReplayer(tools, options = {}) {\n  const mode = options.mode || 'replay';\n  const store = options.store;\n  const maxRank = envelope.effectRank(options.maxEffectClass || 'SE2');\n  if (!['record', 'replay'].includes(mode)) {\n    throw new ReplayError('replay.bad_mode', `mode must be record or replay, got ${mode}`);\n  }\n  if (!store) {\n    throw new ReplayError('replay.no_store', 'a FixtureStore is required');\n  }\n  for (const [name, tool] of Object.entries(tools)) {\n    if (!envelope.EFFECT_CLASSES.includes(tool.effect_class)) {\n      throw new ReplayError('replay.bad_declaration', `tool ${name} must declare an effect_class`);\n    }\n    if (!['deterministic', 'nondeterministic'].includes(tool.determinism)) {\n      throw new ReplayError('replay.bad_declaration', `tool ${name} must declare determinism`);\n    }\n  }\n\n  const calls = [];\n  const emit = (entry) => {\n    calls.push(entry);\n    if (typeof options.onCall === 'function') {\n      options.onCall(entry);\n    }\n  };\n","sourceCodeStart":80,"sourceCodeEnd":116,"githubUrl":"https://github.com/affaan-m/ECC/blob/8321021c54d670126ce3b2969d5deb880b4b0c2a/scripts/lib/eval-harness/replay.js#L80-L116","documentation":"createReplayer throws ReplayError('replay.no_store') when options.store is falsy. Both record and replay modes need a FixtureStore: record writes fixtures into it and replay reads them. The constructor requires it unconditionally so a misconfigured suite cannot appear to pass while actually skipping persistence.","triggerScenarios":"Calling createReplayer(tools) with no options, or with options.store undefined/null — e.g. the FixtureStore was never constructed, a factory function returning null on failure, or a conditional `...(useStore && { store })` spread evaluating false.","commonSituations":"Copy-pasting an example that omitted the store; refactoring away the fixture directory constant so `new FixtureStore(dir)` is never called; a config loader returning null when a path is missing; forgetting that the store argument is required, not optional.","solutions":["Construct and pass a FixtureStore: createReplayer(tools, { store: new FixtureStore('fixtures/eval'), mode }).","Verify the store-producing helper actually returns a FixtureStore instance and not undefined/null (log it before createReplayer).","Make the fixture directory a required, validated config value so it cannot silently become undefined.","If the store depends on an optional feature, fail earlier with a clear message instead of letting the spread drop the option."],"exampleFix":"// before\nconst replayer = createReplayer(tools, { mode: 'record' });\n\n// after\nconst store = new FixtureStore(path.join(__dirname, 'fixtures'));\nconst replayer = createReplayer(tools, { mode: 'record', store });","handlingStrategy":"validation","validationCode":"const store = new FixtureStore(process.env.FIXTURE_DIR || path.join(__dirname, 'fixtures'));\nif (!(store instanceof FixtureStore)) throw new Error('fixture store not initialized');\ncreateReplayer(tools, { mode, store });","typeGuard":"function isFixtureStore(v) {\n  return v instanceof FixtureStore;\n}","tryCatchPattern":"try {\n  return createReplayer(tools, { mode, store });\n} catch (e) {\n  if (e instanceof ReplayError && e.code === 'replay.no_store') {\n    throw new Error('FixtureStore must be constructed and passed as options.store');\n  }\n  throw e;\n}","preventionTips":["Always construct the FixtureStore next to createReplayer in the same setup function","Make the fixture directory a validated required config value","Avoid conditional spreads that can silently drop options.store","Write one shared suite-bootstrap helper so the store is never forgotten"],"tags":["configuration","missing-argument","fixture","replay"],"backgroundTag":"missing-required-argument","analyzedSha":"8321021c54d670126ce3b2969d5deb880b4b0c2a","analyzedAt":"2026-09-16T10:08:13.343Z","contentChangedAt":"2026-09-16T10:08:13.343Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}