Files
SGF/scripts/summarize-request-history.mjs
2026-11-04 09:37:20 +02:00

9 lines
5.4 KiB
JavaScript

import fs from 'node:fs';import path from 'node:path';import crypto from 'node:crypto';import assert from 'node:assert/strict';
const [qaTag,demoTag]=process.argv.slice(2);assert([qaTag,demoTag].every(t=>/^[a-f0-9]{12}$/.test(t??'')));const run=JSON.parse(fs.readFileSync('C:/laragon/data/sgf-tempo/run/modular-regression-current.json')),qa=path.join(run.root,'private/receipt-composition-'+qaTag),demo=path.join(run.root,'private/receipt-composition-'+demoTag),prior=path.join(run.root,'private/receipt-composition-2d2d938a3bec'),read=p=>JSON.parse(fs.readFileSync(p,'utf8')),hash=p=>crypto.createHash('sha256').update(fs.readFileSync(p)).digest('hex'),tests={};
for(const [name,base,file,count]of [['history',qa,'request-history-result.json',20],['ui',qa,'request-history-ui.json',10],['demo',demo,'request-history-demo.json',6]]){const p=path.join(base,file),r=read(p);assert(r.passed);assert.equal(r.checks.length,count);tests[name]={file:'private/'+path.basename(base)+'/'+file,sha256:hash(p),checks:count,result:r};}
const files=['app/Modules/Purchasing/RequestController.php','app/Modules/Purchasing/ProcessHistory.php','config/receipt_qa.php','routes/web.php','public/request-workspace.mjs','public/request-history.mjs'];for(const base of [qa,demo])for(const file of files)assert.equal(hash(path.join(base,'app',file)),hash(file),file);
const tail=text=>{const at=text.indexOf('public function preview(');assert(at>=0);return text.slice(at);};assert.equal(tail(fs.readFileSync('app/Modules/Purchasing/RequestController.php','utf8')),tail(fs.readFileSync(path.join(prior,'app/app/Modules/Purchasing/RequestController.php'),'utf8')));assert.equal(hash('app/Modules/Purchasing/ProcessHistory.php'),hash(path.join(prior,'app/app/Modules/Purchasing/ProcessHistory.php')));
const pins=[];for(const base of [qa,demo]){const p={};for(const dir of ['bundle','economic','internal']){p[dir]=hash(path.join(base,dir,'manifest.json'));for(const [file,h]of Object.entries(read(path.join(base,dir,'manifest.json')).files))assert.equal(hash(path.join(base,dir,file)),h);}pins.push(p);}assert.deepEqual(pins[0],pins[1]);assert.deepEqual(pins[0],read('docs/proofs/purchasing-continuity-composition-20261103.json').pinned_native_manifests);
const previous=['docs/proofs/purchasing-continuity-composition-20261103.json','docs/proofs/module-association-consolidation-summary-20261102.json'].map(file=>({file,sha256:hash(file)})),assoc=read(previous[1].file);assert.equal(hash('app/Modules/Identity/Services/ModuleAssociationReview.php'),assoc.source_sha256);assert.equal(hash('app/Modules/Identity/Http/ModuleRecordsController.php'),assoc.controller_sha256);assert.equal(hash('packages/purchasing/current.json'),read(previous[0].file).preservation.installed_purchasing_sha256);
const checks=Object.values(tests).reduce((n,t)=>n+t.checks,0);assert.equal(checks,36);const out='docs/proofs/request-history-composition-20261103.json';assert(!fs.existsSync(out));fs.writeFileSync(out,JSON.stringify({date:new Date().toISOString(),increment:'SGF-REQUEST-HISTORY-CURSOR-QA-v1',passed:true,functional_code:true,checks,tests,sources:files.map(file=>({file,sha256:hash(file)})),pinned_native_manifests:pins[0],authority:{existing_right:'purchasing_requests.view',new_right_names:[],own_stage_filter_unchanged:true,request_preview_confirmation_blocks_unchanged:true,cursor_bound_to_request_actor_context_binding_size:true,cursor_lifetime_seconds:600,permission_rechecked_each_page:true},pagination:{implementation:'Laravel cursorPaginate',page_sizes:[25,100],order:'id descending',global_count:false,initial_page_reused:true,all_universe_loaded:false},regression:{initial_events:127,events_after_new_head:128,original_ids_seen_once:true,native_fixture_notes:126,notes_are_not_request_versions:true,request_version:1,draft_status_preserved:true,inherited_order_fixture_before_history_request:1,inherited_source_setup_removed_for_future_runs:true,successful_prefix_reused:17},demo:{port:8080,entry:'http://127.0.0.1:8080/qa/enter/requester?open=1',initial_main_requests:0,initial_history_volume:0},prior_proofs_preserved:previous,preservation:{installed_purchasing_sha256:hash('packages/purchasing/current.json'),target_database_connected:false,protected_six_records_changed:false,blocked_cache_cleared:false,previous_demo_data_written:false,public_rights_changed:false,publication:false,checkpoint:false},limitations:['Cursor order follows immutable event sequence, not a guaranteed database snapshot across arbitrary external writers. Refresh starts a new consultation.','Ten-minute expiry, changed context, actor or page size require an explicit refresh. Cursor is a read marker, not approval evidence or a business version.','Volume consists of126 explicitly marked audit notes plus original draft events; it is not126 operational request revisions.','The initial inherited harness also prepared one100MZN order before the history request. It remains preserved; this unnecessary setup was removed for future runs. The preservation suffix was corrected without replaying17 valid checks.','UI checks use a simulated DOM; actual API cursor traversal is separately exercised. Browser visual review and accessibility remain pending.','No new React/Vite build: changed UI is static ES modules. Served module hashes and syntax are verified; prior valid build proof is retained.','Sustained load, deployment compatibility and operational readiness remain separate.'],visual_review_pending:true,deployment_capacity_validated:false},null,2)+'\n');console.log(JSON.stringify({output:out,checks,demo_port:8080}));