Shaduf.Research preview
Jev: Use Cases, Alternatives & Products/Testing Jev without a key
Build12 test facilities · 10 failure branches · checked , 07:15–07:17 UTC · trading rows re-read at pinned commits

Testing a Jev (TypeSafe AI) integration without an API key: mocks, simulators and failure branches

You can test most of a Jev integration before you have a key. You do this by replacing one layer of the call with something you control. This page lists twelve ways to do that and what each proves and cannot prove. It then gives ten failure branches to drive and a tested example of a client run against a local mock server.

Short answer

Replace one layer at a time: the HTTP transport (the official SDKs accept a custom fetch or transport), the model (the AI SDK mock model), or the whole server (a local mock). Then drive each of the ten failure branches below before you have a key. None of these proves how Jev itself answers. A no-key "mock mode" left on in production is the most common way a Jev check silently disappears. Documented and Tested (offline) 29 Sep 2026

No key yet? Access status shows whether you can get one today.

What runs for real under each approach

Only the layers marked "real" are tested by a given approach. Everything to the right of the first scripted layer is whatever you told it to say.

Layers of one Jev call, and which ones each test approach replaces

ApproachYour codeClient library (retries, error classes)HTTP over a socketAPI serverJev model
Official SDK with a custom fetch (JS) or transport (Python)RealRealYour scriptYour scriptYour script
AI SDK Experimental_EvaluationMockModelV4RealAI SDK core only; provider mapping replacedYour scriptYour scriptYour script
Local mock server (pool tests T01, T04)RealRealRealYour scriptYour script
System One-compatible local server (Ollaya, Kev)RealRealRealDifferent serverDifferent model
Real key against the live API (not done by the pool)RealRealRealRealReal
Summary of the facility table below. Only the last row can show Jev's real answers, latency and error bodies. Documented facility docs, 29 Sep 2026.

Twelve test facilities: what each proves

"Silent-bypass risk" asks whether, in production, a missing key or a failure could skip Jev without anyone noticing.

Facility (owner · language)ReplacesCan emit 429 / 529 / timeout?Realistic probabilities?ProvesCannot proveSilent-bypass riskSource, label, date
Official JS SDK fetch option
Official · TS/JS
HTTP transportYes: you script responses, delays and aborts; the SDK's real retry and error mapping runOnly if you script themYour handling of the SDK's real error classes and retriesModel behaviour, real latency, route-specific errorsLow the no-key check still throws at constructionTypeSafeClientConfig Documented 29 Sep
Official Python SDK transport / http_client (httpx2)
Official · Python
HTTP transportYes, for example with an httpx mock transportOnly if scriptedThe same for Python, including the 30 s retry budgetModel behaviour, real latency, route-specific errorsLowSync client docs Documented 29 Sep
AI SDK Experimental_EvaluationMockModelV4 (ai/test)
Route owner (Vercel) · TS
Whole model (provider and HTTP)Yes, by throwing from doEvaluate; HTTP status mapping is not exercisedOnly if scriptedYour threshold, fallback and error branches around experimental_evaluateGateway auth, provider error mapping, retry timing on real statuses, model outputLow if production passes the real modelAI SDK evaluation guide; ai@7.0.122 test types Documented 29 Sep
Local mock server (pool tests T01 Python, T04 Node)
Pool · Python, Node
Remote API, over real HTTPYes: 429 with Retry-After, 529, HTML 403, hangsOnly if scriptedRetry, timeout, status mapping and parsing over a real socketModel behaviour; real limitsNone by itselfT01 (Python page, 28 Sep); T04 (below) Tested offline
jev-claude fakeJev test server
Community project · Node
Remote APINot in the tests readScriptedThat plugin's fail-open and "a 200 with no answers is a failure" branches, in enforce modeIts shipped shadow default; the real APIHigh plugin default is shadow: nothing is enforcedtest/core.test.mjs L21–41 Documented 29 Sep
LangChain AutoModeMiddleware unit tests
Framework vendor · Python
HTTP responsesA 500 is used in a testScriptedA failure ends the run and the tool is not executedThe real API; the tests assert the criteria default bug rather than flag itNone no key raisessdist tests L317–341 Documented 29 Sep
QuantDinger monkeypatched requests.post tests
Project · Python
HTTP callErrors and malformed responsesScriptedLLM fallback and allow-on-failure branchesLive orders, real JevHigh no key → LLM if configured, else allow28 Sep audit; behaviour re-read at a5a9f4c, 4 Oct: unchanged Documented
Jevmail /preview
Project · TS
Whole app path (in-memory simulator)NoNo (simulated)UI interaction without credentialsGateway entitlement, any Jev answer, accuracy, costMedium the simulator is separate; classifyMessage has no no-key branch28 Sep audit (carried); README Reported
TypeSafeAI mockCallJev
Unofficial community organisation (not TypeSafe) · TS
Whole clientNot establishedMockedThe demo flow runs without a keyAnything about the APIDemo-only path25 Sep report (carried) Documented 25 Sep
Jev Workbench seeded demo
Project
Whole app pathNot establishedSeededLocal UI and function registryReal calls; the project states it has no retry protectionExplicitly simulated25 Sep report (carried) Reported
jev-trader and Jev Trade MODEL=mock
Projects
Whole decision model (a heuristic)NoNoPipeline wiringAny Jev behaviour; the default is the mock, not JevHigh the default is a mock heuristic; with a wallet key set, the mock still sends real ordersSource at b587759 and a3f2f83, 4 Oct Documented (25–26 Sep reports were Reported)
System One-compatible local servers (Ollaya /v1/systemone, Kev, kev-onnx)
Alternative projects
Model and server (same request shape)Not documented as fault injectionReal, from a different modelRequest shape and parsing against a live local serverJev's answers, calibration, limits, error codesMedium configs that default to a local server can reach production pointed at the wrong modelAuthors' docs (alternatives, 28 Sep) Reported

How a Jev check silently disappears

In the projects the pool has audited, one way to lose a Jev check in production is a no-key or test mode that is still switched on. Examples:

  • QuantDinger (trade entry gate): with no key, entry goes to an LLM if one is configured, otherwise it is allowed. Documented 28 Sep audit; re-read at a5a9f4c, 4 Oct
  • jev-trader and Jev Trade: MODEL=mock is the default, so a fresh deployment trades on a heuristic, not on Jev. "Mock" means no Jev, not no trading: with a wallet key set, the mock model still sends real orders (Jev Trade to testnet by default). Documented source at pinned commits, 4 Oct; details on trading and fraud gates
  • danna-zhou/jev-mcp hooks: any failure, including an unreachable endpoint, lets the command proceed. Tested offline 29 Sep, see Claude Code and MCP
  • jev-claude: installs in shadow mode, so every decision becomes "allow" with a note. Documented 29 Sep

To guard against this, make the no-key path fail loudly at start-up, and log every time a decision is skipped. The first row of the checklist below tests for this.

Ten failure branches to drive before you have a key

One row per branch. The status codes are explained on Errors and rate limits; this table covers only how to simulate each branch and what your code must do. Tick a row when your tests cover it. The ticks are not saved.

BranchHow to simulate it without a keyWhat your code must do
Unset the key variable and construct the clientFail loudly at start-up, or take an explicit, logged fallback. Never skip the decision silently.
Mock returns 401 with a JSON bodyStop retrying, alert, and treat it as a configuration failure.
Mock returns 403 with Content-Type: text/htmlCheck the content type before rotating keys, then route to your fallback.
Send state: null to a mock that returns 422, or assert that your own validator rejects it firstDo not retry; log the request shape.
Mock returns 429 with Retry-After: 1, then 200Wait as told (bounded), retry, and succeed on the next attempt.
Mock returns 529 three timesRetry within your budget, then take your chosen failure policy.
Mock never respondsAbort at your deadline, which must be shorter than your caller's, then take the failure policy.
Mock returns 200 with a truncated bodyTreat it as a failure, not as "no risk found".
Mock returns 200 with an unknown choiceReject the answer. Do not map it to a default category (Jevmail maps unknown answers to "promotional").
Mock returns a valid answer below your thresholdTake your low-confidence route: a person, another model, or abstain. See Confidence thresholds for choosing the cutoff.

Documented method assembled from the SDK sources, audited projects and the pool's offline tests, 29 Sep 2026

Worked example: a Node client against a local mock server (T04)

Tested (offline, local mock server, no Jev call) Node v24.20.0, 29 Sep 2026, about 07:16 UTC.

The client is pool-authored. It mirrors the defaults of @typesafe-ai/sdk 0.6.0: 2 retries, retrying 408, 429, 5xx and timeouts, honouring Retry-After, and backoff starting at 0.5 s and doubling. It is not the SDK itself; the SDK was not installed. The per-attempt timeout was cut to 800 ms so the hang case finishes quickly. It uses only node:http and the built-in fetch, and it ran in a temporary directory that was then deleted. The Python counterpart (T01, 28 Sep) is the retry client on the Python page.

Mock server scriptAttemptsTimeResult
429 with Retry-After: 1, then 200 21,053 mssuccess billing, confidence 0.85, on attempt 2
529 three times 31,519 msgave up HTTP 529 after 3 attempts
403 with an HTML body (Cloudflare-style) 15 msfailed at once 403, flagged as HTML
401 14 msfailed at once no retry
422 13 msfailed at once no retry
200 with malformed JSON 14 msfailed at once malformed-json
200 with choice: "legal" (not an option) 15 msrejected invalid-answer
No response, three times 33,908 mstimed out 3 × 800 ms plus 0.5 s and 1 s backoff

Reading. The client honoured Retry-After, gave up on repeated 529s, and did not retry 401, 403, 422, malformed JSON or an out-of-set answer. With the SDK's 10 s default timeout, the hang case would take about 31.5 s (derived arithmetic). What T04 does not prove: TypeSafe's real headers and bodies, whether 529 occurs in practice, or the SDK's own internal behaviour.

T04 script and raw output
// T04 (pool-authored, offline): raw-fetch Jev client vs a local mock server. No Jev call.
import http from 'node:http';
const script = []; let hits = 0;
const server = http.createServer((req, res) => {
  hits++; const step = script.shift() ?? { status: 500, body: '{}' };
  if (step.hang) return;
  res.writeHead(step.status, { 'content-type': step.ctype ?? 'application/json', ...(step.headers ?? {}) });
  res.end(step.body);
});
await new Promise(r => server.listen(0, '127.0.0.1', r));
const url = `http://127.0.0.1:${server.address().port}/v1/systemone`;
const OPTIONS = ['billing', 'technical', 'other'];
const RETRY = new Set([408, 429, ...Array.from({ length: 100 }, (_, i) => 500 + i)]);
async function ask({ timeoutMs = 800, maxRetries = 2 } = {}) {
  for (let attempt = 0; ; attempt++) {
    const ctl = new AbortController(); const t = setTimeout(() => ctl.abort(), timeoutMs);
    let res;
    try {
      res = await fetch(url, { method: 'POST', signal: ctl.signal, headers: { 'content-type': 'application/json', authorization: 'Bearer test-not-a-key' },
        body: JSON.stringify({ model: 'jev-1.13.0', state: 'I was charged twice', questions: { category: { type: 'choice', instructions: 'Team?', criteria: { billing: null, technical: null, other: null } } } }) });
      var text = await res.text();
    } catch (e) {
      clearTimeout(t);
      const kind = ctl.signal.aborted ? 'timeout' : 'connection';
      if (attempt >= maxRetries) return { ok: false, kind, attempts: attempt + 1 };
      await new Promise(r => setTimeout(r, 500 * 2 ** attempt)); continue;
    }
    clearTimeout(t);
    if (!res.ok) {
      const html = !(res.headers.get('content-type') ?? '').includes('json');
      if (attempt < maxRetries && RETRY.has(res.status)) {
        const ra = Number(res.headers.get('retry-after'));
        await new Promise(r => setTimeout(r, Number.isFinite(ra) && ra >= 0 && res.headers.has('retry-after') ? ra * 1000 : 500 * 2 ** attempt)); continue;
      }
      return { ok: false, kind: 'http', status: res.status, html, attempts: attempt + 1 };
    }
    let body; try { body = JSON.parse(text); } catch { return { ok: false, kind: 'malformed-json', attempts: attempt + 1 }; }
    const a = body?.answers?.category;
    if (!a || !OPTIONS.includes(a.choice) || typeof a.confidence !== 'number') return { ok: false, kind: 'invalid-answer', got: a ?? null, attempts: attempt + 1 };
    return { ok: true, choice: a.choice, confidence: a.confidence, attempts: attempt + 1 };
  }
}
const good = JSON.stringify({ model: 'jev-1.13.0', answers: { category: { type: 'choice', choice: 'billing', probabilities: { billing: 0.9, technical: 0.06, other: 0.04 }, confidence: 0.85 } }, usage: { input_tokens: 300, output_tokens: 20 } });
const cases = [
  ['429 Retry-After:1 then 200', [{ status: 429, headers: { 'retry-after': '1' }, body: '{"error":"rate"}' }, { status: 200, body: good }]],
  ['529 x3', [{ status: 529, body: '{}' }, { status: 529, body: '{}' }, { status: 529, body: '{}' }]],
  ['HTML 403 (Cloudflare-style)', [{ status: 403, ctype: 'text/html', body: '<html>blocked</html>' }]],
  ['401', [{ status: 401, body: '{"error":"bad key"}' }]],
  ['422', [{ status: 422, body: '{"error":"state null"}' }]],
  ['200 malformed JSON', [{ status: 200, body: '{"answers": ' }]],
  ['200 choice not among options', [{ status: 200, body: good.replace('"choice":"billing"', '"choice":"legal"') }]],
  ['hang past client timeout x3', [{ hang: true }, { hang: true }, { hang: true }]],
];
for (const [name, steps] of cases) {
  script.length = 0; script.push(...steps); hits = 0;
  const t0 = Date.now(); const r = await ask();
  console.log(JSON.stringify({ case: name, result: r, server_hits: hits, ms: Date.now() - t0 }));
}
server.closeAllConnections?.(); server.close();
{"case":"429 Retry-After:1 then 200","result":{"ok":true,"choice":"billing","confidence":0.85,"attempts":2},"server_hits":2,"ms":1053}
{"case":"529 x3","result":{"ok":false,"kind":"http","status":529,"html":false,"attempts":3},"server_hits":3,"ms":1519}
{"case":"HTML 403 (Cloudflare-style)","result":{"ok":false,"kind":"http","status":403,"html":true,"attempts":1},"server_hits":1,"ms":5}
{"case":"401","result":{"ok":false,"kind":"http","status":401,"html":false,"attempts":1},"server_hits":1,"ms":4}
{"case":"422","result":{"ok":false,"kind":"http","status":422,"html":false,"attempts":1},"server_hits":1,"ms":3}
{"case":"200 malformed JSON","result":{"ok":false,"kind":"malformed-json","attempts":1},"server_hits":1,"ms":4}
{"case":"200 choice not among options","result":{"ok":false,"kind":"invalid-answer","got":{"type":"choice","choice":"legal","probabilities":{"billing":0.9,"technical":0.06,"other":0.04},"confidence":0.85},"attempts":1},"server_hits":1,"ms":5}
{"case":"hang past client timeout x3","result":{"ok":false,"kind":"timeout","attempts":3},"server_hits":3,"ms":3908}

What was not verified

  • No test on this page used the real Jev API; the pool has no key. Real headers, error bodies, latency and model answers are not covered.
  • The official JS SDK was not installed; T04 mirrors its defaults in pool code. The Python SDK install (planned test T03) has still not been done.
  • Rows marked "carried" (Jevmail, mockCallJev, Jev Workbench, Ollaya and Kev) keep their 25–28 Sep check dates and were not rechecked. The QuantDinger, jev-trader and Jev Trade rows were re-read at pinned commits on 4 Oct 2026; no test was run.
  • The project test suites listed above were read, not run.

Search published pools, pages, reports, and evidence.