#!/usr/bin/env node // proba-lant-de-incredere.mjs: the AI trust chain end to end in the LABORATORY, with the real children (Proof of Software attest, // the verify-layer sidecar, the agent ledger, Proof of AI, the AIP-23 reference verifier), then the fixtures (each link broken on // purpose, refused for its named reason), then the plantings (--control-negativ: a copy of the verifier with one check removed must // turn exactly its fixture ROSU). --viu adds the witness: the ledger head notarized on testnet 28001 with the L1 test key, read back // under a post-quantum certified anchor, and the bundle judged VALID with --rpc. // node proba-lant-de-incredere.mjs [--viu] [--control-negativ] import crypto from 'node:crypto'; import fs from 'node:fs'; import os from 'node:os'; import path from 'node:path'; import { spawnSync } from 'node:child_process'; import { createRequire } from 'node:module'; import { fileURLToPath, pathToFileURL } from 'node:url'; import { newAgentIdentity, openLedger, agentIdFromKey, sessionId, canonical as canonicLedger } from '../agents/agent-ledger.mjs'; import { definePolicy } from '../agents/agent-policy.mjs'; import { buildProofOfAi } from '../proof-of-ai/proof-of-ai.mjs'; import { ledgerHeadEnvelope, notarizeHead, cheiaDinFisier } from '../agents/agent-ancora.mjs'; const AICI = path.dirname(fileURLToPath(import.meta.url)); const RAD = path.resolve(AICI, '..', '..'); // the children: the sidecar lives beside this component (public copy: ../verify-layer/, rewritten at staging); the AIP-23 reference // verifier comes from AERE_VERIFY_PROOF (public copy, as for agents/) or from the development repository; without it: NEMASURAT (2) const SIDECAR = fileURLToPath(new URL('../verify-layer/sidecar.mjs', import.meta.url)); const VERIFY_PROOF = process.env.AERE_VERIFY_PROOF || path.join(RAD, 'verificator-falcon', 'verify-proof.mjs'); const RPC_28001 = process.env.AERE_TESTNET_RPC || 'https://testnet-rpc.aere.network'; // --viu: the notarization key (gas only, a test key) and the folder whose node_modules hold ethers const CHEIE = process.env.AERE_NOTARY_KEY_FILE || path.join(RAD, 'tools', 'aere-quantum-shield', 'dovezi-l1', '.chei', 'cheie-de-proba-28001.key'); const ETHERS_DIR = process.env.AERE_ETHERS_DIR || path.join(RAD, 'contracts'); // the model artifact and its Proof of Software attestation are a COMMITTED fixture (fixturi/: 4 KB of random bytes attested with // laboratory keys by tools/proof-of-software/pos.mjs, which is not part of this component); regenerate with // node ../proof-of-software/pos.mjs keygen --out k.json && node ../proof-of-software/pos.mjs attest --out fixturi/atestare-model.json --name aere-model-proba --version 1.0.0 --keys k.json fixturi/model-weights.bin const FIXTURI = path.join(AICI, 'fixturi'); if (!fs.existsSync(VERIFY_PROOF)) { console.log(`NEMASURAT: verificatorul AIP-23 nu e la ${VERIFY_PROOF}; AERE_VERIFY_PROOF=`); process.exit(2); } const sha = (b) => '0x' + crypto.createHash('sha256').update(b).digest('hex'); const run = (args, cwd) => { const r = spawnSync(process.execPath, args, { cwd, encoding: 'utf8', timeout: 180000 }); if (r.status !== 0) throw new Error(`${path.basename(args[0])} ${args[1]} exited ${r.status}: ${(r.stdout + r.stderr).slice(-300)}`); return r.stdout; }; const rehash = (env) => ({ ...env, statementHash: sha(Buffer.from(JSON.stringify(env.statement), 'utf8')) }); const clone = (x) => JSON.parse(JSON.stringify(x)); /** the laboratory pieces: a model artifact attested, a host that ran it, an agent allowed to use it, an output */ export function laborator({ toolAllowed = true } = {}) { const T = fs.mkdtempSync(path.join(os.tmpdir(), 'aere-ai-trust-lab-')); // version: the committed fixture (the artifact and its hybrid-signed Proof of Software attestation); the digest is recomputed here, // never read from the attestation, so a fixture whose artifact and attestation drifted apart is caught at P1 const art = path.join(T, 'model-weights.bin'); fs.copyFileSync(path.join(FIXTURI, 'model-weights.bin'), art); const artSha = sha(fs.readFileSync(art)); const attestation = JSON.parse(fs.readFileSync(path.join(FIXTURI, 'atestare-model.json'), 'utf8')); // runtime: the host declares the artifact running, in its audit log, 60 s before the output const t0 = Math.floor(Date.now() / 1000) - 120, t1 = t0 + 60; const iso = (t) => new Date(t * 1000).toISOString(); run([SIDECAR, 'record', '--kind', 'runtime', '--artifact', art, '--attested', artSha, '--host', 'lab-probe', '--log', path.join(T, 'audit.log'), '--at', iso(t0)], T); run([SIDECAR, 'attest-head', '--log', path.join(T, 'audit.log'), '--host', 'lab-probe', '--out', path.join(T, 'head.json')], T); const auditLog = fs.readFileSync(path.join(T, 'audit.log'), 'utf8').split('\n').filter((l) => l.trim()).map((l) => JSON.parse(l)); const record = auditLog[0].proof; const head = JSON.parse(fs.readFileSync(path.join(T, 'head.json'), 'utf8')); // permissions + identity: an agent allowed (or not) to call the model tool const identity = newAgentIdentity(); const { policy, policyHash } = definePolicy({ agentId: identity.agentId, tools: toolAllowed ? ['model:aere-model-proba'] : ['model:other'] }); const ledger = openLedger({ identity, policy, policyHash, now: () => t1 }); // provenance: the output, naming the attested artifact and the agent const proofOfAi = buildProofOfAi({ model: { name: 'aere-model-proba', version: '1.0.0', weightsSha256: artSha }, prompt: 'summarise document X', input: 'document X, 12 kB', output: 'a summary of document X', tools: ['model:aere-model-proba'], agentId: identity.agentId, requester: 'tester', createdAt: iso(t1) }); const r = ledger.record({ kind: 'tool', tool: 'model:aere-model-proba', args: { promptHash: proofOfAi.statement.promptHash } }, { provenance: proofOfAi, at: t1 }); return { T, art, artSha, attestation, record, auditLog, head, identity, policy, policyHash, ledger, proofOfAi, allowed: r.allowed, t0, t1 }; } export async function proba(mod, cer, { viu = false } = {}) { const L = laborator(); const bundle = mod.construieste({ ledger: L.ledger.export(), policy: { policy: L.policy, policyHash: L.policyHash }, proofOfAi: L.proofOfAi, software: { attestation: L.attestation }, runtime: { record: L.record, auditLog: L.auditLog, head: L.head } }); const v0 = await mod.verifica(bundle, { verifyProof: VERIFY_PROOF }); const toate = ['identity', 'version', 'runtime', 'permissions', 'provenance']; cer('P1', 'laborator: toate cele cinci fatete PASSED, martorul ABSENT, verdict PARTIAL (unwitnessed)', toate.every((l) => v0.levels[l] === 'PASSED') && v0.levels.witness === 'ABSENT' && v0.verdict === 'PARTIAL' && v0.reason === 'unwitnessed' ? 'VERDE' : 'ROSU', `${v0.verdict} (${v0.reason}) ${JSON.stringify(v0.levels)}`); cer('P2', 'intrarea registrului a fost PERMISA de politica (unealta model:aere-model-proba in lista)', L.allowed ? 'VERDE' : 'ROSU'); const v1 = await mod.verifica(mod.construieste({ ledger: L.ledger.export(), policy: { policy: L.policy, policyHash: L.policyHash }, proofOfAi: L.proofOfAi }), { verifyProof: VERIFY_PROOF }); cer('P3', 'fara versiune si fara runtime: nivelurile ABSENT, restul PASSED, tot PARTIAL unwitnessed (ce lipseste e spus, nu inventat)', v1.levels.version === 'ABSENT' && v1.levels.runtime === 'ABSENT' && v1.levels.permissions === 'PASSED' && v1.verdict === 'PARTIAL' ? 'VERDE' : 'ROSU', JSON.stringify(v1.levels)); // fixtures: each link broken on purpose const fix = [ ['F1', 'iesirea schimbata in Proof of AI (hash refacut): nu mai e intrarea din registru -> permissions FAILED output-not-in-ledger', (b) => { b.provenance.proofOfAi.statement.outputHash = sha(Buffer.from('another output')); b.provenance.proofOfAi = rehash(b.provenance.proofOfAi); }, 'permissions', 'output-not-in-ledger'], ['F2', 'digestul ponderilor schimbat in Proof of AI: nu e artefactul atestat -> version FAILED version-artifact-mismatch', (b) => { b.provenance.proofOfAi.statement.model.weightsSha256 = '0x' + 'ab'.repeat(32); b.provenance.proofOfAi = rehash(b.provenance.proofOfAi); }, 'version', 'version-artifact-mismatch'], ['F3', 'alt agentId in Proof of AI: identity FAILED identity-mismatch', (b) => { b.provenance.proofOfAi.statement.agentId = 'aere-agent:' + '11'.repeat(20); b.provenance.proofOfAi = rehash(b.provenance.proofOfAi); }, 'identity', 'identity-mismatch'], ['F4', 'inregistrarea de runtime numeste alt artefact: runtime FAILED runtime-artifact-mismatch', (b) => { b.runtime.record.statement.artifactSha256 = '0x' + 'cd'.repeat(32); b.runtime.record = rehash(b.runtime.record); }, 'runtime', 'runtime-artifact-mismatch'], ['F6', 'inregistrarea de runtime datata DUPA iesire: runtime FAILED runtime-after-output', (b) => { b.runtime.record.statement.createdAt = new Date((L.t1 + 3600) * 1000).toISOString(); b.runtime.record = rehash(b.runtime.record); }, 'runtime', 'runtime-after-output'], ['F7', 'o intrare a registrului modificata (argumentele): permissions FAILED ledger-invalid', (b) => { b.permissions.ledger.entries[0].body.action.args = { promptHash: '0x' + '00'.repeat(32) }; }, 'permissions', 'ledger-invalid'], ['F8', 'jurnalul de audit fara inregistrarea de runtime: runtime FAILED runtime-not-in-audit-log', (b) => { b.runtime.auditLog = []; b.runtime.head = null; }, 'runtime', 'runtime-not-in-audit-log'], ['F9', 'atestarea Proof of Software modificata dupa hash: version FAILED version-attestation', (b) => { b.version.attestation.statement.artifacts[0].sha256 = '0x' + 'ef'.repeat(32); }, 'version', 'version-attestation'], ['F10', 'jurnalul de audit cu lantul rupt (hash-ul intrarii schimbat): runtime FAILED audit-log-broken', (b) => { b.runtime.auditLog[0].hash = '0x' + '77'.repeat(32); }, 'runtime', 'audit-log-broken'], ]; for (const [id, eticheta, muta, nivel, motiv] of fix) { const b = clone(bundle); muta(b); const v = await mod.verifica(b, { verifyProof: VERIFY_PROOF }); const ok = v.verdict === 'INVALID' && v.levels[nivel] === 'FAILED' && v.details[nivel].reason === motiv; cer(id, eticheta, ok ? 'VERDE' : 'ROSU', `${v.verdict} (${v.reason}); ${nivel} ${v.levels[nivel]} ${v.details[nivel].reason || ''}`); } { const L2 = laborator({ toolAllowed: false }); const b = mod.construieste({ ledger: L2.ledger.export(), policy: { policy: L2.policy, policyHash: L2.policyHash }, proofOfAi: L2.proofOfAi, software: { attestation: L2.attestation }, runtime: { record: L2.record, auditLog: L2.auditLog } }); const v = await mod.verifica(b, { verifyProof: VERIFY_PROOF }); cer('F5', 'unealta nepermisa de politica: intrarea REFUZATA exista, iesirea nu poate fi "permisa" -> permissions FAILED action-refused', !L2.allowed && v.levels.permissions === 'FAILED' && v.details.permissions.reason === 'action-refused' ? 'VERDE' : 'ROSU', `${v.verdict} ${v.details.permissions.reason || ''}`); } // 2026-10-05: what the chain INHERITS from its children since 2026-10-03 (a classical key under an ML-DSA-65 name is refused by the // agents' ledger verifier and by the audit log verifier), and the list of every rule that refused { // the ledger producer refuses a key that is not ML-DSA-65, so this ledger is written the way only the holder of such a key could: // one entry, with the ledger's published formulas (the id derived from the key, the session from the id and the policy, the // signature over seq|prev|canonical body, the hash over that and the signature) const cl = crypto.generateKeyPairSync('ed25519'); const id = agentIdFromKey(cl.publicKey); const pc = definePolicy({ agentId: id, tools: ['model:aere-model-proba'] }); const ses = sessionId(id, pc.policyHash); const poa = buildProofOfAi({ model: { name: 'aere-model-proba', version: '1.0.0' }, prompt: 'summarise document X', input: 'document X, 12 kB', output: 'a summary of document X', tools: ['model:aere-model-proba'], agentId: id, requester: 'tester', createdAt: new Date(L.t1 * 1000).toISOString() }); const body = { v: 2, agentId: id, policyHash: pc.policyHash, session: ses, at: L.t1, action: { kind: 'tool', tool: 'model:aere-model-proba', at: L.t1 }, decision: { allowed: true, reason: 'tool allowed' }, provenance: null, seq: 0 }; const prev = '0'.repeat(64); const signature = crypto.sign(null, Buffer.from(`0|${prev}|${canonicLedger(body)}`, 'utf8'), cl.privateKey).toString('base64'); const ledger = { version: L.ledger.export().version, agentId: id, publicKeyPem: cl.publicKey.export({ type: 'spki', format: 'pem' }), policyHash: pc.policyHash, session: ses, entries: [{ seq: 0, prev, body, signature, hash: crypto.createHash('sha256').update(Buffer.from(`0|${prev}|${canonicLedger(body)}|${signature}`, 'utf8')).digest('hex') }] }; const v = await mod.verifica(mod.construieste({ ledger, policy: { policy: pc.policy, policyHash: pc.policyHash }, proofOfAi: poa }), { verifyProof: VERIFY_PROOF }); cer('F11', 'agentul are o cheie Ed25519 (id-ul derivat din ea, registrul semnat cu ea): permissions FAILED ledger-invalid, mostenit de la verificatorul registrului', v.verdict === 'INVALID' && v.levels.permissions === 'FAILED' && v.details.permissions.reason === 'ledger-invalid' && /ML-DSA-65/.test(String(v.details.permissions.detail)) ? 'VERDE' : 'ROSU', `${v.verdict} (${v.reason}); permissions ${v.levels.permissions} ${v.details.permissions.reason || ''}: ${String(v.details.permissions.detail || '').slice(0, 90)}`); } { const cl = crypto.generateKeyPairSync('ed25519'); const b = clone(bundle); b.runtime.head.signature = { scheme: 'ml-dsa-65', publicKey: cl.publicKey.export({ type: 'spki', format: 'der' }).toString('base64'), signature: crypto.sign(null, Buffer.from(JSON.stringify(b.runtime.head.statement), 'utf8'), cl.privateKey).toString('base64') }; const v = await mod.verifica(b, { verifyProof: VERIFY_PROOF }); cer('F12', 'capul jurnalului de audit semnat cu o cheie Ed25519 care se declara ml-dsa-65: runtime FAILED audit-head, mostenit de la verificatorul jurnalului', v.verdict === 'INVALID' && v.levels.runtime === 'FAILED' && v.details.runtime.reason === 'audit-head' && /ed25519/.test(String(v.details.runtime.detail)) ? 'VERDE' : 'ROSU', `${v.verdict} (${v.reason}); runtime ${v.levels.runtime} ${v.details.runtime.reason || ''}: ${String(v.details.runtime.detail || '').slice(0, 110)}`); } { const b = clone(bundle); b.version.attestation.statement.artifacts[0].sha256 = '0x' + 'ef'.repeat(32); b.runtime.auditLog[0].hash = '0x' + '77'.repeat(32); // the mutations of F9 and F10 together const v = await mod.verifica(b, { verifyProof: VERIFY_PROOF }); cer('F13', 'doua verigi rupte deodata: verdictul are campul rules cu FIECARE regula care a refuzat, sortate (reason e doar prima)', v.verdict === 'INVALID' && Array.isArray(v.rules) && v.rules.join() === 'audit-log-broken,version-attestation' ? 'VERDE' : 'ROSU', `${v.verdict} (${v.reason}); rules ${JSON.stringify(v.rules)}`); } if (viu) { // the witness: the ledger head notarized on 28001 with the laboratory test key (gas only), read back under a certified anchor const require = createRequire(path.join(ETHERS_DIR, 'package.json')); const { ethers } = require('ethers'); const headEnv = ledgerHeadEnvelope(L.ledger.export()); let notarized; // notarizeHead returns { ok, envelope }: the ENVELOPE (with its notarization) is the head the witness level reads try { const r = await notarizeHead({ envelope: headEnv, rpc: RPC_28001, keyFile: CHEIE, ethers }); if (!r || !r.ok) throw new Error('notarizeHead: ' + JSON.stringify(r).slice(0, 160)); notarized = r.envelope; } catch (e) { cer('V1', 'capul registrului notarizat pe 28001', 'STRICAT', String(e.message).slice(0, 160)); return; } cer('V1', 'capul registrului notarizat pe 28001 (cheia de proba L1, numai gaz)', notarized && notarized.notarization ? 'VERDE' : 'ROSU', notarized && notarized.notarization ? `tx ${String(notarized.notarization.txHash).slice(0, 14)}.. block ${notarized.notarization.block}` : JSON.stringify(notarized).slice(0, 120)); const bw = mod.construieste({ ledger: L.ledger.export(), policy: { policy: L.policy, policyHash: L.policyHash }, proofOfAi: L.proofOfAi, software: { attestation: L.attestation }, runtime: { record: L.record, auditLog: L.auditLog, head: L.head }, witness: { heads: [notarized], chainId: 28001 } }); let vw = null; for (let i = 0; i < 20; i++) { vw = await mod.verifica(bw, { verifyProof: VERIFY_PROOF, rpc: RPC_28001, chain: 28001 }); if (vw.levels.witness !== 'UNMEASURED') break; await new Promise((ok) => setTimeout(ok, 8000)); } cer('V2', 'cu martorul citit sub o ancora certificata (--rpc 28001): witness PASSED, verdict VALID', vw && vw.verdict === 'VALID' && vw.levels.witness === 'PASSED' ? 'VERDE' : (vw && vw.levels.witness === 'UNMEASURED' ? 'STRICAT' : 'ROSU'), vw ? `${vw.verdict} (${vw.reason}); witness ${vw.levels.witness}: ${String(vw.details.witness.detail || vw.details.witness.reason || '').slice(0, 160)}` : 'fara verdict'); const vb = await mod.verifica(bw, { verifyProof: VERIFY_PROOF }); cer('V3', 'acelasi pachet FARA --rpc: martorul UNMEASURED (witness-needs-rpc), nu PASSED', vb.levels.witness === 'UNMEASURED' && vb.verdict === 'PARTIAL' ? 'VERDE' : 'ROSU', `${vb.verdict} (${vb.reason})`); const d = path.join(RAD, 'tools', 'aere-ai-trust', 'dovezi'); fs.mkdirSync(d, { recursive: true }); const f = path.join(d, `lant-28001-${new Date().toISOString().replace(/[:.]/g, '').slice(0, 15)}Z.json`); fs.writeFileSync(f, JSON.stringify({ bundle: bw, verdict: vw }, null, 1)); console.log(' dovada scrisa: ' + f); } } if (process.argv.includes('--control-negativ')) { const SURSA = fs.readFileSync(path.join(AICI, 'lant-de-incredere.mjs'), 'utf8'); const PLANTARI = [ { nume: '(a) identitatea necomparata', de: '/*PAZA:identity*/', cu: "|| String(1) === '1' /*PLANTAT*/", rosii: ['F3'] }, { nume: '(b) artefactul atestat necomparat cu ponderile', de: '/*PAZA:version*/', cu: "|| String(1) === '1' /*PLANTAT*/", rosii: ['F2'] }, { nume: '(c) artefactul rulat necomparat', de: '/*PAZA:runtime*/', cu: "|| String(1) === '1' /*PLANTAT*/", rosii: ['F4'] }, { nume: '(d) ordinea timpilor nejudecata', de: '/*PAZA:order*/', cu: "|| String(1) === '1' /*PLANTAT*/", rosii: ['F6'] }, { nume: '(e) iesirea necautata in registru (prima intrare luata oricum)', de: '/*PAZA:output-in-ledger*/', cu: '|| ledger.entries[0] /*PLANTAT*/', rosii: ['F1'] }, // (f) and (g) sit inside a NEGATED condition (`if (!(x) /*PAZA*/)`): the planting that silences the check is `&& false`, not `|| true` // (measured 2026-10-02: `|| true` made the honest rows fail instead of letting the fixture pass) { nume: '(f) decizia refuzata luata drept permisa', de: '/*PAZA:allowed*/', cu: "&& String(1) === '2' /*PLANTAT*/", rosii: ['F5'] }, { nume: '(g) inregistrarea necautata in jurnalul de audit', de: '/*PAZA:audit*/', cu: "&& String(1) === '2' /*PLANTAT*/", rosii: ['F8'] }, // 2026-10-05: the inherited refusals and the list of rules { nume: '(i) capul jurnalului necomparat (verificatorul jurnalului neascultat)', de: "if (!c.ok) fail('runtime', 'audit-head',", cu: "if (String(1) === '2') fail('runtime', 'audit-head',", rosii: ['F12'] }, { nume: '(j) registrul neverificat (verificatorul registrului neascultat)', de: "if (!v.ok) fail('permissions', 'ledger-invalid',", cu: "if (String(1) === '2') fail('permissions', 'ledger-invalid',", rosii: ['F7', 'F11'] }, { nume: '(k) verdictul fara lista regulilor', de: "rules: LEVELS.filter((l) => levels[l].state === 'FAILED').map((l) => levels[l].reason).sort(),", cu: 'rules: [],', rosii: ['F13'] }, { nume: '(h) controlul controlului: o ancora care nu exista', de: '/*PAZA:nu-exista*/', cu: 'x', rosii: [], asteapta: 'STRICAT' }, ]; let bune = 0; for (const [k, p] of PLANTARI.entries()) { const n = SURSA.split(p.de).length - 1; const copie = path.join(AICI, `_plantat-lant-${process.pid}-${k}.mjs`); let stare, detaliu = ''; try { if (n !== 1) { stare = 'STRICAT'; detaliu = `ancora apare de ${n} ori (cerut 1)`; } else { fs.writeFileSync(copie, SURSA.replace(p.de, p.cu)); const mod = await import(pathToFileURL(copie).href); const randuri = []; // a probe that THROWS on the planted copy is STRICAT for that planting, not the end of the control try { await proba(mod, (id, eticheta, st, det) => randuri.push({ id, stare: st, det })); } catch (e) { randuri.push({ id: 'proba', stare: 'STRICAT', det: String(e.message).slice(0, 160) }); } const stricate = randuri.filter((x) => x.stare === 'STRICAT'); const rosii = randuri.filter((x) => x.stare === 'ROSU').map((x) => x.id); if (stricate.length) { stare = 'STRICAT'; detaliu = 'proba a cazut: ' + stricate.map((x) => x.id + ' ' + x.det).join(' | ').slice(0, 200); } else { const prezise = p.rosii.every((id) => rosii.includes(id)); const numai = rosii.every((id) => p.rosii.includes(id)); stare = prezise && numai ? 'VERDE' : 'ROSU'; detaliu = `rosii: ${rosii.join(',') || '-'} (prezis ${p.rosii.join(',') || '-'})`; } } } finally { fs.rmSync(copie, { force: true }); } const ok = stare === (p.asteapta || 'VERDE'); if (ok) bune++; console.log(` ${ok ? 'BINE' : 'ESEC'} ${p.nume}: ${stare}${p.asteapta ? ' (prezis ' + p.asteapta + ')' : ''} ${detaliu}`); } const ramase = fs.readdirSync(AICI).filter((f) => f.startsWith('_plantat-lant-')); console.log(`CONTROL: ${bune} din ${PLANTARI.length} cum s-a prezis${ramase.length ? '; copii ramase: ' + ramase.join(',') : ''}`); process.exitCode = bune === PLANTARI.length && !ramase.length ? 0 : 1; } else { const mod = await import('./lant-de-incredere.mjs'); let verzi = 0, rosii = 0, stricate = 0; await proba(mod, (id, eticheta, stare, det) => { if (stare === 'VERDE') verzi++; else if (stare === 'ROSU') rosii++; else stricate++; console.log(` [${stare.padEnd(7)}] ${id.padEnd(4)} ${eticheta}${det ? ' ' + det : ''}`); }, { viu: process.argv.includes('--viu') }); console.log(`\nlantul de incredere pentru AI: ${verzi} VERDE, ${rosii} ROSU, ${stricate} STRICAT`); process.exitCode = rosii || stricate ? 1 : 0; }