// Row 125 (#1619, REQ-LIMIT-3, REQ-LIMIT-4): Settings shows each token limit as the bus's checks // report it. A limit no switched-on check counts reads "not enforced"; Reset posts the limit's // path alone; a form save keeps the token limits as read. import test from 'node:test'; import assert from 'node:assert/strict'; import {browser} from './browser.mjs'; import {startServer} from '../src/serve.mjs'; import {close} from './fixture.mjs'; const SINCE='2026-10-18T07:00:00.000Z'; const hostile=''; const tokens={instances:{coder:{limit:100,since:SINCE}},keys:{k1:{limit:5,since:SINCE}},providers:{anthropic:{limit:9,since:SINCE}},models:{anthropic:{'claude-opus-5-5':{limit:7,since:SINCE}}}}; const launch={business:'acme',revision:'a'.repeat(64),models:{opus:{provider:'anthropic',model:'claude-opus-5-5'}},limits:{total:4,tokens},instances:{coder:{modelKey:'opus'}},usage:{total:0,providers:{},models:{}}}; const TOKENS=[ {path:['tokens','instances','coder'],limit:100,since:SINCE,status:'counted',check:'token-limit',count:120,kinds:{input:10,output:20,cacheWrite:40,cacheRead:50},unknownTurns:2}, {path:['tokens','keys','k1'],limit:5,since:SINCE,status:'not-enforced',reason:'no records name a key'}, {path:['tokens','providers','anthropic'],limit:9,since:SINCE,status:'not-enforced',reason:null}, {path:['tokens','models','anthropic','claude-opus-5-5'],limit:7,since:SINCE,status:'check-failed',check:hostile,code:'check-threw'}, ]; test('REQ-LIMIT-3 REQ-LIMIT-4 Settings shows token limits counted, not enforced and check failed; Reset posts one path; a save keeps the token limits',{timeout:90000},async()=>{ let answer={revision:launch.revision,limits:launch.limits,tokens:TOKENS}; const bus={messages:async()=>({messages:[],unread:0}),usage:async()=>{throw Error('no usage');},limits:async()=>answer}; const web=await startServer({port:0,board:'http://127.0.0.1:9',bus,reads:{settings:()=>({business:'acme',release:'fixture',notifier:{},launch})}}),b=await browser(); try{ await b.call('Page.addScriptToEvaluateOnNewDocument',{source:`window.posts=[];window.enabled=new URL(location.href).searchParams.has('send');window.fixture=${JSON.stringify(launch)};const original=window.fetch;window.fetch=async(url,options={})=>{if(url==='/api/config')return new Response(JSON.stringify({send:window.enabled}));if(url==='/api/settings'&&options.method==='POST'){posts.push(JSON.parse(options.body));return new Response(JSON.stringify({...fixture,revision:'b'.repeat(64)}));}return original(url,options);};`}); const port=web.address().port; const wait=expr=>b.evaluate(`(async()=>{for(let n=0;n<200;n++){if(${expr})return true;await new Promise(r=>setTimeout(r,30));}throw Error('wait failed: '+${JSON.stringify(expr)});})()`); const cells=()=>b.evaluate("[...document.querySelectorAll('#token-limits-table tbody tr')].map(row=>[...row.querySelectorAll('th,td')].map(c=>c.textContent))"); // Read-only: every status as its words, and Reset disabled. await b.navigate(`http://127.0.0.1:${port}/#/settings/tokens`); await wait('!!document.querySelector("#token-limits-table")'); assert.deepEqual(await cells(),[ ['tokens / instances / coder','100',SINCE,'120 (input 10, output 20, cache write 40, cache read 50); unknown turns 2','Reset'], ['tokens / keys / k1','5',SINCE,'not enforced: no records name a key','Reset'], ['tokens / providers / anthropic','9',SINCE,'not enforced','Reset'], ['tokens / models / anthropic / claude-opus-5-5','7',SINCE,`check failed: check-threw (${hostile})`,'Reset'], ]); assert.equal(await b.evaluate('[...document.querySelectorAll("[data-limit-reset]")].every(e=>e.disabled)'),true); assert.equal(await b.evaluate('document.querySelectorAll("#token-limits-daily").length'),0,'no daily row, no daily line'); assert.equal(await b.evaluate('window.injected===true'),false); // Signed-in send mode: Reset posts the revision and that one path, and nothing else. A draft // typed before the reset stays, and its save carries the revision the reset returned (row 167). await b.navigate(`http://127.0.0.1:${port}/?send=1#/settings/tokens`); await wait('document.querySelector("[data-limit-reset]")?.disabled===false'); await b.evaluate('location.hash="#/settings/limits"'); await wait('!!document.querySelector("#launch-settings-form")'); await b.evaluate(`(()=>{const e=[...document.querySelectorAll('[data-setting]')].find(e=>e.dataset.setting===${JSON.stringify(JSON.stringify(['total']))});e.value='3';e.dispatchEvent(new Event('input',{bubbles:true}));return true;})()`); await b.evaluate('location.hash="#/settings/tokens"'); await wait('document.querySelector("[data-limit-reset]")?.disabled===false'); await b.evaluate('document.querySelectorAll("[data-limit-reset]")[1].click();true'); await wait('document.querySelector("#token-limits-receipt")?.textContent.includes("Limit reset.")'); assert.deepEqual(await b.evaluate('posts'),[{revision:'a'.repeat(64),reset:[['tokens','keys','k1']]}]); // A form save sends the token limits as read, so it never drops or edits them. await b.evaluate('location.hash="#/settings/limits"'); await wait('!!document.querySelector("#launch-settings-form")'); assert.equal(await b.evaluate(`[...document.querySelectorAll('[data-setting]')].find(e=>e.dataset.setting===${JSON.stringify(JSON.stringify(['total']))}).value`),'3'); await b.evaluate('document.querySelector("#launch-settings-form").requestSubmit();true'); await wait('posts.length===2'); const [,save]=await b.evaluate('posts'); assert.equal(save.revision,'b'.repeat(64)); assert.equal(save.limits.total,3); assert.deepEqual(save.limits.tokens,tokens); // Row 126 (#1620): a daily quota row adds one line under the table. Its own query string makes // this a full load, and the next block's /#/settings one too. answer={revision:launch.revision,limits:launch.limits,tokens:[...TOKENS,{path:['tokens','daily','jason-max'],limit:40,since:SINCE,status:'counted',check:'daily-quota',count:3,kinds:{input:1,output:1,cacheWrite:0,cacheRead:1},unknownTurns:0}]}; await b.navigate(`http://127.0.0.1:${port}/?daily=1#/settings/tokens`); await wait('!!document.querySelector("#token-limits-daily")'); assert.equal(await b.evaluate('document.querySelector("#token-limits-daily").textContent'),"Daily quotas count only this stack's own use of the account, not its use anywhere else."); assert.equal(await b.evaluate('document.querySelectorAll("#token-limits-daily").length'),1); // A limits answer the server refuses shows no rows and no count. answer={revision:launch.revision,limits:launch.limits}; await b.navigate(`http://127.0.0.1:${port}/#/settings/tokens`); await wait('document.querySelector("#token-limits-title")?.parentElement.textContent.includes("Token limits unavailable")'); assert.equal(await b.evaluate('document.querySelectorAll("#token-limits-table").length'),0); }finally{await b.close();await close(web);} }); // Row 167 (#1664): the reset and the Assistant section share one snapshot. With an assistant // draft open, a reset gives the assistant submit the revision the reset returned. test('Row 167 with an assistant draft open, a token limit reset gives the assistant submit its revision',{timeout:90000},async()=>{ const withAssistant={...launch,assistants:{assistant:{definition:'assistant',vars:{model:'claude-opus-5-5'},tracker:null}}}; const bus={messages:async()=>({messages:[],unread:0}),usage:async()=>{throw Error('no usage');},limits:async()=>({revision:launch.revision,limits:launch.limits,tokens:TOKENS})}; const web=await startServer({port:0,board:'http://127.0.0.1:9',bus,reads:{settings:()=>({business:'acme',release:'fixture',notifier:{},launch:withAssistant})}}),b=await browser(); try{ await b.call('Page.addScriptToEvaluateOnNewDocument',{source:`window.posts=[];window.fixture=${JSON.stringify(withAssistant)};const original=window.fetch;window.fetch=async(url,options={})=>{if(url==='/api/config')return new Response(JSON.stringify({send:true}));if(url==='/api/settings'&&options.method==='POST'){posts.push(JSON.parse(options.body));return new Response(JSON.stringify({...fixture,revision:'bc'[posts.length-1].repeat(64)}));}return original(url,options);};`}); const q=sel=>`document.querySelector(${JSON.stringify(sel)})`; const wait=expr=>b.evaluate(`(async()=>{for(let n=0;n<200;n++){if(${expr})return true;await new Promise(r=>setTimeout(r,30));}throw Error('wait failed: '+${JSON.stringify(expr)});})()`); await b.navigate(`http://127.0.0.1:${web.address().port}/#/settings/assistant`); await wait(`${q('.assistant-form button[type=submit]')}?.disabled===false`); await b.evaluate(`(()=>{const e=${q('.assistant-form [data-assistant-field="tracker"]')};e.value='{"project":"P19"}';e.dispatchEvent(new Event('input',{bubbles:true}));return true;})()`); await b.evaluate('location.hash="#/settings/tokens"'); await wait('document.querySelector("[data-limit-reset]")?.disabled===false'); await b.evaluate('document.querySelectorAll("[data-limit-reset]")[1].click();true'); await wait('document.querySelector("#token-limits-receipt")?.textContent.includes("Limit reset.")'); assert.deepEqual(await b.evaluate('posts'),[{revision:'a'.repeat(64),reset:[['tokens','keys','k1']]}]); await b.evaluate('location.hash="#/settings/assistant"'); await wait('!!document.querySelector(".assistant-form")'); assert.equal(await b.evaluate(`${q('.assistant-form [data-assistant-field="tracker"]')}.value`),'{"project":"P19"}'); await b.evaluate(`${q('.assistant-form')}.requestSubmit();true`); await wait(`${q('[data-assistant-receipt]')}?.textContent.includes("Assistant settings saved")`); assert.deepEqual(await b.evaluate('posts[1]'),{revision:'b'.repeat(64),assistants:{assistant:{tracker:{project:'P19'}}}}); }finally{await b.close();await close(web);} });