Files
SGF/scripts/summarize-workshop-stock-closure.mjs
2026-11-02 20:29:34 +02:00

55 lines
7.3 KiB
JavaScript

import fs from 'node:fs';
import path from 'node:path';
import crypto from 'node:crypto';
import {spawnSync} from 'node:child_process';
const read=p=>JSON.parse(fs.readFileSync(p,'utf8').replace(/^\uFEFF/,''));
const hash=p=>crypto.createHash('sha256').update(fs.readFileSync(p)).digest('hex');
const state=read('C:/laragon/data/sgf-tempo/run/modular-regression-current.json');
if(state.port!==55439||!/^[a-f0-9]{12}$/.test(state.id))throw Error('Wrong QA host');
const names=process.argv.slice(2);if(!names.length||names.some(n=>!/^workshop-stock-\d+\.xml$/.test(n)))throw Error('Supply passing isolated JUnit file names');
const attrs=t=>Object.fromEntries([...t.matchAll(/(\w+)="([^"]*)"/g)].map(m=>[m[1],m[2]]));
const selected=new Map();
const proofs=names.map(name=>{
const file=path.join(state.root,name),xml=fs.readFileSync(file,'utf8'),suite=attrs(xml.match(/<testsuite\b[^>]*>/)[0]);
const rawCases=[...xml.matchAll(/<testcase\b[^>]*\/>|<testcase\b[^>]*>[\s\S]*?<\/testcase>/g)].map(m=>m[0]);
const cases=rawCases.map(c=>({...attrs(c.match(/^<testcase\b[^>]*>/)[0]),passed:!/<(?:failure|error|skipped)\b/.test(c)}));
if(cases.length!==Number(suite.tests))throw Error('Unexpected case count');
for(const c of cases)if(c.passed)selected.set(c.name,{name:c.name,assertions:Number(c.assertions),proof:name});
return {file:name,sha256:hash(file),tests:Number(suite.tests),assertions:Number(suite.assertions),failures:Number(suite.failures),errors:Number(suite.errors),selected_passing_cases:cases.filter(c=>c.passed).length};
});
const source=fs.readFileSync('tests/Feature/WorkshopStockTest.php','utf8');
const methods=[...source.matchAll(/public function (test_\w+)\(/g)].map(m=>m[1]);
if(methods.some(m=>!selected.has(m))||selected.size!==methods.length)throw Error('Current affected suite not covered by selected passing evidence');
const uiPath='docs/proofs/workshop-stock-closure-ui-20261102.json',ui=read(uiPath);
if(ui.source_sha256!==hash('resources/js/WorkshopStockWorkspace.jsx'))throw Error('UI evidence stale');
const old=read('docs/proofs/module-association-http-lock-summary-20261102.json');
for(const p of [old.proof,...old.previous_proofs])if(hash(p.path)!==p.sha256)throw Error('Accepted association evidence changed');
const reader=read('docs/proofs/stock-read-load-20261102.json');
if(reader.source_sha256!==hash('packages/inventory-read/src/InventoryReader.php'))throw Error('Reader SQL changed');
const native=read('docs/proofs/native-warehouse-return-20261102.json');
if(native.package.manifest_sha256!==hash('../compras/packages/inventory-return/releases/0.1.0/manifest.json'))throw Error('Return artifact changed');
const post=spawnSync('C:/laragon/tools/sgf-tempo/php-8.4.27/php.exe',['scripts/workshop-stock-state.php'],{encoding:'utf8',windowsHide:true});
if(post.status!==0)throw Error('QA restoration postcheck failed');
const files=['app/Modules/Workshop/WorkshopStock.php','app/Modules/Workshop/Http/WorkshopStockController.php','resources/js/WorkshopStockWorkspace.jsx','routes/web.php','tests/Feature/WorkshopStockTest.php','tests/Support/workshop-stock-worker.php','config/workshop_stock.php'];
const manifest=read('public/build/manifest.json');const asset='public/build/'+manifest['resources/js/app.jsx'].file;
const bundled=fs.readFileSync(asset,'utf8');
if(!bundled.includes('Confirmar retirada sem movimento')||!bundled.includes('state_version')||!bundled.includes('source_hash'))throw Error('Current closure UI not in built application');
const closure=[...selected.values()].filter(c=>c.name.startsWith('test_closure_'));
const report={date:'2026-11-02',increment:'WORKSHOP-STOCK-PROPOSAL-CLOSURE-SIM-v1',status:'local_synthetic_implementation',proofs,
selection:'All current WorkshopStockTest cases covered exactly once by name, selecting passing cases only. Initial history assertion omitted the schema-discovery SELECT: its failure is retained, excluded and replaced by the targeted passing rerun distinguishing one catalogue lookup and one batch data lookup. Other passing cases were reused. No native, association or unrelated suites repeated.',
totals:{distinct_tests:selected.size,assertions:[...selected.values()].reduce((n,c)=>n+c.assertions,0)},
closure_cases:{tests:closure.length,assertions:closure.reduce((n,c)=>n+c.assertions,0)},selected_cases:[...selected.values()],
workflow:{withdraw_requires_original_preparer_and_current_prepare_right:true,reject_requires_independent_current_confirmer:true,explicit_reason:true,presented_state_version_and_source_hash_required:true,stale_physical_preview_can_be_closed_without_execution:true,confirmed_effect_cannot_be_closed_or_reversed_by_this_command:true,replay_same_body_actor_and_state_only:true,new_review_requires_new_proposal:true,zero_stock_effect:true,original_immutable:true,append_only_decision_with_before_after_actor_time_reason:true,audit_in_same_transaction:true},
concurrency:{separate_processes:2,company_lock_observed_with_pg_blocking_pids:true,withdraw_then_confirm:'second refuses 409 after release; no physical movement',confirm_then_withdraw:'second refuses 409 after release; original movement retained',identical_withdrawals:'second replays original; one decision'},
history:{...read(path.join(state.root,'private/workshop-closure-history.json')),filters:['all','pending','confirmed','withdrawn','rejected'],repeatable_read_read_only:true,no_universe_loaded:true},
recovery:{audit_failure_rolls_back_decision:true,retry_creates_one_decision:true,database_update_of_closure_refused:true},
source_sha256:Object.fromEntries(files.map(f=>[f,hash(f)])),ui:{proof:uiPath,sha256:hash(uiPath),...ui},
build:{passed:true,manifest_sha256:hash('public/build/manifest.json'),application_asset:asset,application_asset_sha256:hash(asset),closure_controls_in_built_application:true,modules_transformed:46,navigation_source_changed:false,extra_navigation_checker:'Existing home checker did not complete; only its verified own processes stopped. Direct Vite build and targeted closure UI proof passed. No new navigation acceptance claimed.',browser_interactions_tested:false,visual_review:false},
postcheck:JSON.parse(post.stdout),
reused_proofs:Object.fromEntries(['docs/proofs/workshop-material-cycle-20261102.json','docs/proofs/native-warehouse-return-20261102.json','docs/proofs/stock-read-load-20261102.json'].map(f=>[f,hash(f)])),
preservation:{new_closure_table_and_index_only_in_new_synthetic_fixture_schemas:true,no_installed_migration:true,no_new_rights:true,temporary_qa_rights_restored:true,six_pending_associations_untouched:true,blocked_cache_untouched:true,demos_and_real_data_untouched:true,regression_not_reset:true,previous_proofs_preserved:true,publication:false,activation:false,checkpoint:false},
limits:['Closing a proposal does not correct a confirmed physical effect.','Legacy synthetic sources without ws_closures retain read/confirm capability; closure command returns 503 and UI does not offer closure. No operational installer created.','No change to native forecasting convention, lots, reservations or financial/accounting effects.','No browser interaction, visual acceptance or deployment-capacity validation.'],visual_review_pending:true,deployment_capacity_validated:false};
fs.writeFileSync('docs/proofs/workshop-stock-closure-20261102.json',JSON.stringify(report,null,2)+'\n');
console.log(JSON.stringify({totals:report.totals,closure_cases:report.closure_cases,postcheck:report.postcheck},null,2));