#!/usr/bin/env node 'use strict'; /* * proba-vocabular.mjs - proves that every verdict the scanner can emit survives the whole way * to the client, and that a genuinely unmeasurable input still comes out as NOT MEASURED. * * WHY IT EXISTS. The scanner emitted RED / YELLOW / GREEN. Two downstream files each wrote their * own list, and both wrote AMBER. So a hybrid contract, which is exactly the client who has * already started migrating and is the most likely to pay, was reported as "we could not measure * this address" in the free scan and as NOT MEASURED in the paid report. Measured 2026-08-16. * * The defect was invisible to every test we had, because each side was self-consistent. Only a * test that walks the WHOLE path, scanner output to client wording, can see it. That is this file. * * CONTROL POZITIV: each of the three verdicts must survive end to end. * CONTROL NEGATIV: an input that carries no verdict at all must still degrade to NOT MEASURED, * otherwise this test would pass even if the reader returned a constant, and would prove nothing. * * node proba-vocabular.mjs exit 0 all good, 1 something drifted */ import { execFileSync } from 'node:child_process'; import path from 'node:path'; import { fileURLToPath } from 'node:url'; import { VERDICTE, citesteVerdict } from './lib/bytecode.js'; const __dirname = path.dirname(fileURLToPath(import.meta.url)); const linii = []; const spune = (ok, ce, obs) => { linii.push({ ok, ce, obs }); console.log(' ' + (ok ? 'PASS' : 'FAIL') + ' ' + ce + (obs ? ' ' + obs : '')); }; // Bytecode fixtures chosen so the scanner reaches each of its three branches offline, with no RPC. // hibrid : uses a PQ precompile AND a classical one -> YELLOW // doar PQ : uses only a PQ precompile -> GREEN // clasic : uses only ecrecover -> RED // Nota platita la prima rulare a acestei probe: fixtura pentru GREEN continea PUSH1 0x01 ca // argument de CALL, iar scanerul l-a citit, corect, ca adresa lui ecrecover, deci fixtura iesea // YELLOW si verdictul GREEN nu era atins de nimic. Proba a semnalat-o singura, si de aia are linia // care cere ca FIECARE verdict din vocabular sa fie atins de cel putin o fixtura. const FIXTURI = { YELLOW: '0x602060006080600060006001610ae1f150600160006080600060006001610001f15000', GREEN: '0x60206000602060006000610ae1611388f15000', RED: '0x602060006080600060006001610001f15000', }; function scan(bytecode) { try { return execFileSync(process.execPath, ['scan.js', '0x1111111111111111111111111111111111111111', '--bytecode', bytecode], { cwd: __dirname, encoding: 'utf8', timeout: 60000 }).trim(); } catch (e) { return String((e.stdout || '') + (e.stderr || e.message)).trim(); } } console.log('proba de vocabular: fiecare verdict al scanerului ajunge intreg la client\n'); console.log('vocabularul, din singura lui sursa: ' + VERDICTE.join(', ') + '\n'); // ── control pozitiv: fiecare verdict produs de scaner e citit ca atare ─────────────────────── console.log('CONTROL POZITIV, fiecare verdict pe tot drumul:'); const vazute = new Set(); for (const [asteptat, bytecode] of Object.entries(FIXTURI)) { const text = scan(bytecode); const emis = (text.match(/^\s*([A-Z]{3,14})\b/m) || [, '(niciunul)'])[1]; const citit = citesteVerdict(text) || 'NOT MEASURED'; vazute.add(emis); spune(citit === emis && citit !== 'NOT MEASURED', 'scanerul emite ' + emis + ', consumatorul citeste ' + citit, emis === asteptat ? '' : '(fixtura viza ' + asteptat + ', dar ce conteaza e ca ce s-a emis a fost citit)'); } // Every verdict the vocabulary declares must actually be reachable by some fixture, otherwise a // branch could rot unnoticed exactly the way YELLOW did. for (const v of VERDICTE) { spune(vazute.has(v), 'verdictul ' + v + ' e atins de cel putin o fixtura', vazute.has(v) ? '' : 'nicio fixtura nu il produce, deci nimeni nu l-ar fi prins daca se strica'); } // ── control negativ: fara el, proba de mai sus ar trece si daca cititorul minte ────────────── console.log('\nCONTROL NEGATIV, ca proba de mai sus sa insemne ceva:'); const fara = citesteVerdict('acest text nu poarta niciun verdict\nnicio linie nu incepe cu unul\n'); spune(fara === null, 'un text fara verdict da null, deci NOT MEASURED la consumator', 'a dat ' + (fara === null ? 'null' : fara)); const gol = citesteVerdict(''); spune(gol === null, 'textul gol da null', 'a dat ' + (gol === null ? 'null' : gol)); // A word that merely CONTAINS a verdict must not be mistaken for one. const aproape = citesteVerdict(' GREENISH pasture\n REDACTED line\n'); spune(aproape === null, 'un cuvant care doar contine un verdict nu e luat drept verdict', 'a dat ' + (aproape === null ? 'null' : aproape)); // ── verdict ───────────────────────────────────────────────────────────────────────────────── const rele = linii.filter((l) => !l.ok).length; console.log('\n' + (linii.length - rele) + ' din ' + linii.length + ' verificari trec'); if (rele) { console.log('VERDICT: vocabularul a divergat undeva pe drum. Verdictele nu ajung intregi la client.'); process.exitCode = 1; } else { console.log('VERDICT: fiecare verdict al scanerului ajunge intreg la client, si un text fara verdict'); console.log('ramane NOT MEASURED. Proba poate deveni rosie, deci verdele ei inseamna ceva.'); }