Oregami
Repositories/oxedyne/daimond

oxedyne/daimond/dev/verify_slots.mjs

6.4 KiB, 1 run

created by r2519314175:681, which is this file's identity for as long as the history lasts, whatever it is later renamed to

download · who wrote it · its history

1// verify_slots.mjs — parallel workers each run on their OWN minted key.
2//
3// The overspend the multi-key work fixes is caused by parallel workers SHARING
4// one spend-capped key: their concurrent requests race the host's stale cap
5// check and overshoot it. The fix is a key per concurrent slot. This proves the
6// CLIENT half end to end: a conductor that dispatches several workers makes the
7// gateway mint a DISTINCT slot per worker, and each worker's real provider
8// request carries its OWN slot key — never a shared one, never the chat's.
9//
10// The gateway is not run; its /api/inference-key is fetch-stubbed to hand back a key
11// keyed to the slot in the request body, exactly as the real one now keys by slot. The
12// provider endpoint is stubbed to record which bearer key each request used. Everything
13// else is the real wasm, the real models.js and the real daimond.js Workers pool. Needs
14// dev/serve.mjs (DAIMOND_PORT, default 8777) and dev/mockllm.mjs (DAIMOND_MOCK_PORT,
15// default 9099).
16import { open, signInAs, shot, MOCK } from './harness.mjs';
17
18const CORS = { 'access-control-allow-origin': '*', 'access-control-allow-headers': '*' };
19const json = (body, status = 200) => ({ status, contentType: 'application/json', headers: CORS, body: JSON.stringify(body) });
20const OR_BASE = 'https://openrouter.ai/api/v1';
21const OR_URL = `${OR_BASE}/chat/completions`;
22const FLOAT = 200;
23const WORKER_SAYS = /You are a worker agent dispatched/;
24// A key whose slot is legible in a haystack.
25const keyForSlot = (slot) => `sk-or-v1-SLOT${slot}-zqxwmarker000000000000000000000000000000`;
26const slotOf = (auth) => { const m = /SLOT(\d+)-/.exec(auth || ''); return m ? Number(m[1]) : null; };
27
28const ok = [], bad = [];
29const check = (name, pass, detail) => {
30 (pass ? ok : bad).push(name);
31 console.log((pass ? ' ok ' : ' FAIL ') + name + (detail ? ' — ' + detail : ''));
32};
33
34const gw = { bal: 2000, mintedSlots: [], providerCalls: [] };
35
36async function stubGateway(page) {
37 await page.route('**/api/account', r => r.fulfill(json({ ok: true })));
38 await page.route('**/api/auth/challenge', r => r.fulfill(json({ ok: true, challenge: 'chal-zqxw', challenge_id: 'cid-1' })));
39 await page.route('**/api/auth/verify', r => r.fulfill(json({ ok: true })));
40 await page.route('**/api/balance', r => r.fulfill(json({ ok: true, credits_minor: gw.bal, currency: 'usd', entries: [] })));
41
42 // The contract under test: the body names a slot, and the key handed back is
43 // that slot's own. The real gateway does exactly this.
44 await page.route('**/api/inference-key', r => {
45 let slot = 0;
46 try { slot = (JSON.parse(r.request().postData() || '{}').slot) | 0; } catch (e) { slot = 0; }
47 gw.mintedSlots.push(slot);
48 return r.fulfill(json({
49 ok: true, key: keyForSlot(slot), url: OR_BASE,
50 limit_minor: Math.min(FLOAT, gw.bal), credits_minor: gw.bal, currency: 'usd',
51 }));
52 });
53
54 await page.route('https://openrouter.ai/api/v1/models',
55 r => r.fulfill(json({ data: [{ id: 'anthropic/claude-opus-4.5' }, { id: 'openai/gpt-5.2' }] })));
56
57 // The provider the browser talks to directly. Record the bearer key and
58 // whether the caller was a worker, then let the mock actually answer.
59 await page.route(OR_URL, async (r) => {
60 const auth = r.request().headers()['authorization'] || '';
61 const sent = r.request().postData() || '';
62 gw.providerCalls.push({ slot: slotOf(auth), worker: WORKER_SAYS.test(sent) });
63 const res = await fetch(MOCK, { method: 'POST', headers: { 'content-type': 'application/json' }, body: sent });
64 const body = await res.text();
65 return r.fulfill({ status: res.status, headers: CORS, contentType: res.headers.get('content-type') || 'application/json', body });
66 });
67}
68
69const s = await open({ name: 'slots', signIn: false, connect: false });
70const { page } = s;
71await stubGateway(page);
72await signInAs(s, 'slots');
73await page.waitForTimeout(2500); // unlock → bootstrap → mint slot 0 → list catalogue
74
75// Start new chats and Diamonds on credits, so the conductor and its workers all run
76// on the minted key path (slot 0 for the chat/conductor, ≥1 for workers).
77await page.evaluate(() => window.DaimondModels.setDefault('credits', 'anthropic/claude-opus-4.5'));
78
79check('unlock minted slot 0 (the chat/conductor key)', gw.mintedSlots.includes(0), 'slots ' + JSON.stringify(gw.mintedSlots));
80
81// A Diamond, and a conductor turn that dispatches three workers at once.
82await page.click('#new-diamond-btn');
83await page.waitForSelector('.dlg-input', { timeout: 8000 });
84await page.fill('.dlg-input', 'Audit');
85await page.click('.dlg-ok');
86await page.waitForSelector('#chat-input', { timeout: 10000 });
87await page.waitForTimeout(400);
88const steer = '@tools spawn_agent {"name":"a","task":"inspect one"} ;; '
89 + 'spawn_agent {"name":"b","task":"inspect two"} ;; '
90 + 'spawn_agent {"name":"c","task":"inspect three"}';
91await page.fill('#chat-input', steer);
92await page.click('#chat-send');
93
94// Wait for all three workers to finish (Workers.active back to 0).
95const until = async (fn, ms = 25000) => {
96 const t0 = Date.now();
97 for (;;) { try { if (await page.evaluate(fn)) return true; } catch (e) {} if (Date.now() - t0 > ms) return false; await new Promise(r => setTimeout(r, 150)); }
98};
99await until(() => gw.__done, 100).catch(() => {});
100await page.waitForTimeout(6000); // let the fan-out run against the mock
101
102// ── The assertions ────────────────────────────────────────────────
103const workerSlots = gw.mintedSlots.filter(x => x >= 1);
104const uniqWorker = Array.from(new Set(workerSlots));
105check('three workers minted three distinct worker slots',
106 uniqWorker.length >= 3 && workerSlots.length === uniqWorker.length,
107 'minted slots ' + JSON.stringify(gw.mintedSlots));
108check('no worker used slot 0 (the chat/conductor key)',
109 !gw.providerCalls.some(c => c.worker && c.slot === 0),
110 JSON.stringify(gw.providerCalls));
111
112const workerCallSlots = gw.providerCalls.filter(c => c.worker).map(c => c.slot);
113const uniqCallSlots = Array.from(new Set(workerCallSlots));
114check('each worker request carried its OWN distinct slot key',
115 workerCallSlots.length >= 3 && uniqCallSlots.length === workerCallSlots.length,
116 'worker call slots ' + JSON.stringify(workerCallSlots));
117
118await shot(s, 'slots');
119await s.close();
120console.log('\nminted slots: ' + JSON.stringify(gw.mintedSlots));
121console.log('provider calls: ' + JSON.stringify(gw.providerCalls));
122console.log(ok.length + ' ok, ' + bad.length + ' failed');
123process.exit(bad.length ? 1 : 0);