import fs from 'node:fs';import path from 'node:path';import net from 'node:net';import assert from 'node:assert/strict';import {spawn} from 'node:child_process'; const read=p=>JSON.parse(fs.readFileSync(p,'utf8')),state=read('C:/laragon/data/sgf-tempo/run/modular-regression-current.json'),tag=process.argv[2],native=process.argv[3]==='native';if(state.port!==55439||!/^[a-f0-9]{12}$/.test(tag??''))throw Error('Owned report fixture required'); const root=path.join(state.root,'private/ledger-'+(native?'native-':'')+tag),out=path.join(root,'ledger-reports-http.json');if(fs.existsSync(out)||!read(path.join(root,'ledger-reports-cases.json')).passed)throw Error('New HTTP proof over checked report fixture required'); await new Promise((resolve,reject)=>{const s=net.createServer();s.once('error',reject);s.listen(8047,'127.0.0.1',()=>s.close(resolve));});const log=fs.openSync(path.join(root,'ledger-reports-http-server.log'),'a'),server=spawn('C:/laragon/tools/sgf-tempo/php-8.4.27/php.exe',['-S','127.0.0.1:8047',path.resolve(native?'scripts/ledger-cycle-native-http-router.php':'scripts/ledger-http-router.php')],{windowsHide:true,stdio:['ignore',log,log],env:{...process.env,LEDGER_QA_SETTINGS:path.join(root,'settings.json')}}); let checks=0;const ok=(v,s)=>{checks++;assert(v,s);},jar=new Map();let context='';const get=async(url,extra={})=>{const r=await fetch('http://127.0.0.1:8047'+url,{headers:{Accept:'application/json',Cookie:[...jar].map(([k,v])=>k+'='+v).join('; '),'X-SGF-Context':context,...extra},redirect:'manual',signal:AbortSignal.timeout(15000)});for(const c of r.headers.getSetCookie()){const p=c.split(';')[0],i=p.indexOf('=');jar.set(p.slice(0,i),p.slice(i+1));}const text=await r.text();let data;try{data=JSON.parse(text);}catch{}return{status:r.status,data,text,headers:r.headers};}; const range='from_on=2026-10-29&to_on=2026-10-29',url='/api/general-ledger/trial-balance?'+range; try{ let ready=false;for(let n=0;n<50&&!ready;n++){try{ready=(await get('/qa/ledger-demo')).status===200;}catch{}if(!ready)await new Promise(r=>setTimeout(r,100));}ok(ready,'Own report server ready');ok([401,302].includes((await get(url)).status),'Unauthenticated report refused');const login=await get('/qa/ledger-enter/read');ok(login.status===200,'Existing QA read identity');context=login.data.context??''; let first;for(const size of [25,100]){const r=await get(url+'&per_page='+size,{'X-Ledger-Report-Proof':String(size)});ok(r.status===200&&r.data.rows.length===size&&r.data.pagination.total===122,'Paginated actual report API '+size);ok(r.data.totals.debit_minor===13205&&r.headers.get('cache-control').includes('no-store'),'Whole-filter totals and no-store');if(!first)first=r.data;} const observations=[25,100].map(size=>read(path.join(root,'ledger-reports-http-'+size+'.json')));ok(observations.every(v=>v.transaction?.isolation==='repeatable read'&&v.transaction.read_only==='on'&&v.writer_locks===0),'Coherent read-only transactions, zero writer locks in both sizes');ok(observations[0].report_queries===3&&observations[1].report_queries===3,'Three aggregate/page/marker queries independent of account page size'); const account=first.rows.find(r=>r.code==='QA-CONTRAPARTIDA').account_id;let r=await get('/api/general-ledger/account-ledger?'+range+'&account_id='+account+'&page=2');ok(r.status===200&&r.data.rows[0].balance_minor===6055+Array.from({length:25},(_,i)=>i+11).reduce((a,b)=>a+b,0),'HTTP running balance crosses page boundary'); r=await get('/general-ledger/trial-balance?'+range);ok(r.status===200&&r.text.includes('/general-ledger/account-ledger?')&&!r.text.includes('method="post"')&&!r.text.includes('