Files
SGF/scripts/reconcile-module-matrix.mjs
2026-11-04 09:37:20 +02:00

103 lines
37 KiB
JavaScript

import fs from 'node:fs';
const file='docs/integration/sgf-flow-plan.json',text=fs.readFileSync(file,'utf8'),plan=JSON.parse(text),proof=(file,checks)=>({file:'docs/proofs/'+file,checks}),zero=prefix=>[{pointer:prefix+'/failures',equals:0},{pointer:prefix+'/errors',equals:0}],passed=pointer=>[{pointer,equals:true}];
const evidence={requisition_order:[proof('internal-requisitions-sgf.json',passed('/passed'))],accepted_receipt:[proof('stock-receipt-link-20261102.json',[...zero('/tests/native_link'),...passed('/same_native_movement_observed_by_sgf')])],physical_stock:[proof('stock-read-summary-20261102.json',zero('/tests/final_functional'))],supplier_invoice:[proof('payables-http.json',passed('/passed'))],supplier_payable:[proof('payables-http.json',passed('/passed'))],supplier_settlement:[proof('supplier-settlements.json',[{pointer:'/hosts/0/passed',equals:true},{pointer:'/hosts/1/passed',equals:true}])],workshop_execution:[proof('workshop-tests.json',zero(''))],workshop_stock_consumption:[{file:'docs/proofs/workshop-stock-closure-20261102.json',selected_junit:true}],verified_cost:[proof('direct-cost-tests.json',zero('')),proof('industrial-cost-tests.json',zero(''))],sales_draft:[proof('workshop-billing-tests.json',zero('/final_targeted_after_guard'))],sales_invoice:[proof('invoice-test-results.json',passed('/passed'))],customer_receivable:[proof('receivables-tests.json',zero(''))],general_ledger:[proof('common-ledger-industrial-correction-20261103.json',passed('/tests/joint_final/passed').concat(passed('/tests/concurrency/passed'))),proof('financial-receipt-recovery-20261103.json',[{pointer:'/checks',equals:43}])]};
const changes={accepted_receipt:'Native receipt workflow delegates once to the shared writer; SGF observes the actual movement in QA. Preparing/confirming receipts in the SGF interface and an installed procurement composition remain pending.',physical_stock:'Shared paged reader works in both QA hosts, with source revisions and explicit bindings. Operational bindings/installation and stock valuation remain pending; missing source is not zero.',workshop_stock_consumption:'QA issue, existing delivery link, partial allocations, returns and proposal withdrawal/rejection are implemented with explicit review and no duplicate movement. Native warehouse return and SGF observation have separate proof. Operational item/warehouse mappings and installed composition remain pending.',supplier_invoice:'Native verified invoice participates in common payable QA; SGF history remains a controlled receipt, not a live historical adapter. Real fiscal policy and installed procurement composition remain separate.',supplier_payable:'Common recognition, controlled history, report and receipt lookup are implemented in QA. Due date stays unknown when absent; operational history responsibility/source mapping and cutover remain pending.',supplier_settlement:'QA confirmation/allocation/reversal and scoped receipt lookup exist; no bank execution, real reconciliation or live historical SGF cutover is delivered.',sales_invoice:'Actual test issuance and QA accounting recognition are proved. Real fiscal issuance/compliance remains guarded.',customer_receivable:'QA opening, confirmed receipts/allocations400+600, reversal400 and accounting integration are proved. Real money, fiscal receipts and bank reconciliation are excluded.'};
for(const stage of plan.stages){stage.evidence=evidence[stage.id];if(changes[stage.id])stage.gap=changes[stage.id];if(['accepted_receipt','physical_stock','workshop_stock_consumption'].includes(stage.id))stage.state='partial_synthetic';if(stage.id==='verified_cost'){stage.requires=[];stage.origin_paths=[{id:'direct_workshop',requires:['workshop_execution']},{id:'industrial_inputs',requires:[]}];}if(stage.id==='sales_draft'){stage.requires=[];stage.origin_paths=[{id:'workshop_billing',requires:['workshop_execution']},{id:'direct_service',requires:[]}];}}
plan.stages.find(s=>s.id==='physical_stock').evidence.push(proof('stock-receipt-link-20261102.json',passed('/same_native_movement_observed_by_sgf')));
const additions=[
['receipt_writer','sgf','packages/inventory-write/src/ReceiptMovementWriter.php','accepted_receipt'],
['receipt_movement_adapter','compras','app/Services/ReceiptStockMovement.php','accepted_receipt'],
['inventory_reader','sgf','packages/inventory-read/src/InventoryReader.php','physical_stock'],
['stock_read_adapter','sgf','app/Modules/Inventory/StockReadController.php','physical_stock'],
['workshop_stock_bridge','sgf','app/Modules/Workshop/WorkshopStock.php','workshop_stock_consumption'],
['workshop_stock_controller','sgf','app/Modules/Workshop/Http/WorkshopStockController.php','workshop_stock_consumption'],
['receipt_recovery_workspace','sgf','resources/views/accounting/receipt-recovery.blade.php','general_ledger'],
['requisition_core','compras','packages/purchasing/src/InternalRequisitions.php','requisition_order'],
['requisition_qa_composition','sgf','app/Modules/Purchasing/InternalRequisitionQa.php','requisition_order']
];
additions.push(['stock_valuation_core','sgf','packages/general-ledger/src/StockValuation.php','physical_stock'],['stock_valuation_observer','sgf','app/Modules/Accounting/StockValuationRead.php','physical_stock'],['stock_valuation_schema','sgf','packages/general-ledger/src/StockSchema.php','general_ledger'],['stock_valuation_composition','sgf','packages/general-ledger/src/StockComposition.php','general_ledger'],['stock_valuation_adapter','sgf','integrations/purchasing/StockValuationAdapter.php','general_ledger']);
for(const [id,repository,path,stageId]of additions){if(!plan.sources.some(s=>s.id===id))plan.sources.push({id,repository,path});const stage=plan.stages.find(s=>s.id===stageId);if(!stage.source_ids.includes(id))stage.source_ids.push(id);}
plan.stages.find(s=>s.id==='requisition_order').gap='The root SGF composition now mounts the existing shared adapter and interface only in a pinned fresh QA database, with module ownership, context, scoped rights and a navigation link; request100 reserves once and is independently approved. Normal destination remains disabled and demonstration8039 is preserved. Receipt UI and generally installed procurement composition remain pending.';
plan.stages.find(s=>s.id==='requisition_order').evidence.push(proof('requisition-composition-20261103.json',[{pointer:'/passed',equals:true},{pointer:'/checks',equals:50}]));
for(const id of ['physical_stock','general_ledger'])plan.stages.find(s=>s.id===id).evidence.push(proof('common-ledger-stock-valuation-20261103.json',[{pointer:'/passed',equals:true},{pointer:'/tests/workflow/result/stock_minor',equals:7500},{pointer:'/tests/workflow/result/physical_quantity_milli',equals:1500}]));
for(const id of ['physical_stock','general_ledger'])plan.stages.find(s=>s.id===id).evidence.push(proof('stock-prefix-stream-20261103.json',[{pointer:'/passed',equals:true},{pointer:'/checks',equals:48}]));
for(const id of ['physical_stock','general_ledger'])plan.stages.find(s=>s.id===id).evidence.push(proof('stock-period-batches-20261103.json',[{pointer:'/passed',equals:true},{pointer:'/checks',equals:33}]));
for(const id of ['requisition_order','accepted_receipt','physical_stock'])plan.stages.find(s=>s.id===id).evidence.push(proof('receipt-composition-20261103.json',[{pointer:'/passed',equals:true},{pointer:'/checks',equals:68}]));
for(const [id,path]of [['sgf_receipt_runtime','app/Modules/Purchasing/ReceiptRuntime.php'],['sgf_receipt_controller','app/Modules/Purchasing/ReceiptController.php'],['sgf_receipt_screen','resources/views/receipt-workspace.blade.php']]){if(!plan.sources.some(s=>s.id===id))plan.sources.push({id,repository:'sgf',path});const stage=plan.stages.find(s=>s.id==='accepted_receipt');if(!stage.source_ids.includes(id))stage.source_ids.push(id);}
plan.stages.find(s=>s.id==='accepted_receipt').gap='SGF now prepares an explicit preview and confirms through the original locally composed receipt workflow and shared writer, with canonical history, quality/cumulative limits, scoped rights, provenance, concurrency and recovery. New demo8064 remains unconsumed initially. General procurement installation, SGF order creation/issuance, full catalogue search, sustained load and deployment remain pending; no automatic context equivalence.';
plan.stages.find(s=>s.id==='requisition_order').gap='The existing shared requisition adapter is mounted in a pinned fresh SGF QA composition, with scoped rights, navigation, single100MZN reservation and distinct approval. Receipt UI is now delivered separately through the original workflow. SGF order preparation/issuance and generally installed procurement composition remain pending; destination is disabled and8039 preserved.';
for(const id of ['requisition_order','accepted_receipt'])plan.stages.find(s=>s.id===id).evidence.push(proof('order-composition-20261103.json',[{pointer:'/passed',equals:true},{pointer:'/checks',equals:49}]));
for(const [id,repository,path]of [['sgf_order_controller','sgf','app/Modules/Purchasing/OrderController.php'],['native_order_workflow','compras','app/Services/PurchaseWorkflow.php'],['sgf_order_screen','sgf','resources/views/order-workspace.blade.php']]){if(!plan.sources.some(s=>s.id===id))plan.sources.push({id,repository,path});const stage=plan.stages.find(s=>s.id==='requisition_order');if(!stage.source_ids.includes(id))stage.source_ids.push(id);}
plan.stages.find(s=>s.id==='requisition_order').gap='Shared requisition QA and single100MZN reservation remain delivered. A new SGF composition now confers/issues an order from an actually approved native award, records one100MZN source-budget commitment, and receives it through the original workflow and physical writer. Native supplier-selection/award interfaces in SGF and explicit handoff from SGF requisitions to that native source remain pending; no duplicated host budget, general installation or destination activation.';
plan.stages.find(s=>s.id==='accepted_receipt').gap='SGF preview/confirmation/history are delivered through the original receipt workflow. New demo8065 connects an actually SGF-issued order to warehouse receipt, with distinct functions, one canonical physical movement and immutable origin evidence. Demo8064 remains preserved. Full procurement installation, catalogue search, sustained load and deployment remain pending; the native award entry is a prepared QA source, not a new SGF selection/approval interface.';
for(const id of ['requisition_order','accepted_receipt'])plan.stages.find(s=>s.id===id).evidence.push(proof('sourcing-composition-20261103.json',[{pointer:'/passed',equals:true},{pointer:'/checks',equals:74}]));
for(const [id,repository,path]of [['sgf_sourcing_controller','sgf','app/Modules/Purchasing/SourcingController.php'],['sgf_sourcing_screen','sgf','resources/views/sourcing-workspace.blade.php'],['native_quotation_controller','compras','app/Http/Controllers/QuotationController.php'],['native_proposal_comparison','compras','app/Services/ProposalComparison.php']]){if(!plan.sources.some(s=>s.id===id))plan.sources.push({id,repository,path});const stage=plan.stages.find(s=>s.id==='requisition_order');if(!stage.source_ids.includes(id))stage.source_ids.push(id);}
plan.stages.find(s=>s.id==='requisition_order').gap='SGF now registers proposals and individual evaluations, shows native comparison, requires explicit choice and distinct award approval, and continues to actual order/commitment and warehouse receipt in demo8066. Entry remains an approved native synthetic requisition and prepared supplier registry. Handoff from SGF internal requisitions with a single budget authority, SGF supplier registry/reviews, formal tender regimes and later corrections remain pending. No general destination activation or deployment validation.';
plan.stages.find(s=>s.id==='accepted_receipt').gap='SGF source-to-receipt selected path is delivered in QA: three proposals, six evaluations, one approved award, one order/100MZN commitment and one receipt/physical movement, with canonical history and original workflows. Demo8066 starts before these individual decisions;8064/8065 preserved. General installation, catalogue search, sustained load and deployment remain pending; SGF internal requisition handoff remains separate.';
plan.stages.find(s=>s.id==='physical_stock').gap='Common physical readers/writers and selected stock valuation are delivered in isolated QA: receipt2UN/100, issue1UN/50, return0.5UN/25, net1.5UN/75. Same canonical physical/valuation book, with SELECT-only SGF observation and explicit rate/review/dependencies. Operational bindings/installation, real valuation method and hybrid integration with already posted direct/industrial materials remain pending.';
plan.stages.find(s=>s.id==='general_ledger').gap='One QA writer covers supplier, sales/receivables, direct/industrial costs and their approved corrections; joint11 journals/23 lines gross8725 remains its own proof. A separate authorised physical-stock book adds entry100/issue50/return25, three journals/six lines gross175, stock75 and period close. No duplicated material cost: hybrid direct/industrial-stock composition remains excluded. SGF observes the canonical stock book; stock confirmations run in its native QA composition. Real chart/tax/valuation/payroll policy, further corrections, reopening, operational cutover and deployment remain pending.';
plan.stages.find(s=>s.id==='general_ledger').evidence.push(proof('ledger-receipt-recovery-20261103.json',[{pointer:'/checks',equals:29}]),proof('receipt-selection-race-manifest-20261103.json',passed('/passed')));
plan.stages.find(s=>s.id==='requisition_order').evidence.push(proof('supplier-composition-20261103.json',[{pointer:'/passed',equals:true},{pointer:'/checks',equals:64}]));
for(const [id,path]of [['sgf_supplier_controller','app/Modules/Purchasing/SupplierController.php'],['sgf_supplier_access','app/Modules/Purchasing/SupplierAccess.php'],['sgf_supplier_screen','resources/views/supplier-workspace.blade.php']]){if(!plan.sources.some(s=>s.id===id))plan.sources.push({id,repository:'sgf',path});const stage=plan.stages.find(s=>s.id==='requisition_order');if(!stage.source_ids.includes(id))stage.source_ids.push(id);}
plan.stages.find(s=>s.id==='requisition_order').gap='SGF supplier preparation/update and distinct review, activation/suspension, paged registry/history and original proposals-to-receipt selected path are delivered in isolated QA, with explicit company/unit origin and access checked again in the quotation API. Demo8067 adds supplier registration to the existing sourcing flow. Entry remains a native approved synthetic requisition. Handoff from SGF internal requisitions with a single budget authority, document attachments, sourcing selector beyond100, formal tender regimes and later corrections remain pending. No general activation or deployment validation.';
plan.stages.find(s=>s.id==='requisition_order').evidence.push(proof('request-to-receipt-composition-20261103.json',[{pointer:'/passed',equals:true},{pointer:'/checks',equals:103}]));
for(const [id,path]of [['sgf_request_controller','app/Modules/Purchasing/RequestController.php'],['sgf_request_access','app/Modules/Purchasing/RequisitionAccess.php'],['sgf_request_screen','resources/views/request-workspace.blade.php']]){if(!plan.sources.some(s=>s.id===id))plan.sources.push({id,repository:'sgf',path});const stage=plan.stages.find(s=>s.id==='requisition_order');if(!stage.source_ids.includes(id))stage.source_ids.push(id);}
plan.stages.find(s=>s.id==='requisition_order').gap='New SGF requests now start as drafts, submit/reserve once, receive distinct native approval and continue with the same request ID to sourcing, award, order/commitment and receipt in demo8068. Host budget entries stay unchanged. Supplier registry/review remains delivered in QA. Conversion of legacy host-reserved ir_requests requires its own responsibility/recovery protocol and is not delivered. Technical catalogues, formal regimes, later corrections and general deployment remain pending.';
plan.stages.find(s=>s.id==='supplier_invoice').evidence.push(proof('supplier-invoice-composition-20261103.json',[{pointer:'/passed',equals:true},{pointer:'/checks',equals:77}]));
for(const [id,path]of [['sgf_supplier_invoice_controller','app/Modules/Purchasing/InvoiceController.php'],['sgf_supplier_invoice_screen','resources/views/supplier-invoice-workspace.blade.php']]){if(!plan.sources.some(s=>s.id===id))plan.sources.push({id,repository:'sgf',path});const stage=plan.stages.find(s=>s.id==='supplier_invoice');if(!stage.source_ids.includes(id))stage.source_ids.push(id);}
plan.stages.find(s=>s.id==='supplier_invoice').gap='SGF now registers pending supplier invoices and performs distinct exact matching through the original pinned workflow after actual SGF order/receipt. Two partial documents40+60 consume the original100MZN commitment once; conflicting pending70 is preserved and refused. Demo8070 starts before main issuance/receipt/invoice. The earlier common-payable11600MZN scenario retains its own proof; these new invoices are not automatically recognised as a payable. Correction/credit notes, binary attachments, real fiscal policy and general deployment remain separate.';
plan.stages.find(s=>s.id==='supplier_payable').evidence.push(proof('supplier-obligation-composition-20261103.json',[{pointer:'/passed',equals:true},{pointer:'/checks',equals:72}]));
for(const [id,path]of [['sgf_obligation_controller','app/Modules/Purchasing/ObligationController.php'],['sgf_obligation_screen','resources/views/supplier-obligation-workspace.blade.php']]){if(!plan.sources.some(s=>s.id===id))plan.sources.push({id,repository:'sgf',path});const stage=plan.stages.find(s=>s.id==='supplier_payable');if(!stage.source_ids.includes(id))stage.source_ids.push(id);}
plan.stages.find(s=>s.id==='supplier_payable').gap='Explicit SGF invoice preparation and distinct recognition now use the same original native supplier-payable adapter and canonical book in demo8071. One100MZN principal, bounded lists/evidence, current-source replay checks and atomic SGF provenance are proven in new QA fixtures. No automatic recognition, duplicate host debt, payment, accounting or imported-history cutover. Unknown maturity remains visible. Combining all earlier demos in one installation, correction/attachments, visual review, sustained load and general deployment remain pending.';
for(const id of ['requisition_order','supplier_invoice','supplier_payable'])plan.stages.find(s=>s.id===id).evidence.push(proof('purchasing-integrated-composition-20261103.json',[{pointer:'/passed',equals:true},{pointer:'/checks',equals:68}]));
for(const [id,path]of [['sgf_purchasing_workspace','app/Modules/Purchasing/WorkspaceNavigation.php'],['sgf_purchasing_navigation','resources/views/partials/purchasing-navigation.blade.php']]){if(!plan.sources.some(s=>s.id===id))plan.sources.push({id,repository:'sgf',path});const stage=plan.stages.find(s=>s.id==='requisition_order');if(!stage.source_ids.includes(id))stage.source_ids.push(id);}
for(const id of ['requisition_order','supplier_invoice','supplier_payable']){const stage=plan.stages.find(s=>s.id===id);stage.gap+=' Superseding the earlier separate-fixture limitation for Purchasing: demo8072 now starts before the first main request and completes request, sourcing, award, order, receipt, invoice and explicit payable recognition in one native book, with shared permission-aware navigation. Supplier registry and geography are mounted in the same host. This does not unify all six ERP modules or validate deployment, payments or accounting of this origin.';}
plan.stages.find(s=>s.id==='requisition_order').evidence.push(proof('supplier-search-composition-20261103.json',[{pointer:'/passed',equals:true},{pointer:'/checks',equals:51}]));
for(const [id,path]of [['sgf_supplier_picker','public/supplier-picker-model.mjs'],['sgf_supplier_search_ui','public/sourcing-workspace.mjs']]){if(!plan.sources.some(s=>s.id===id))plan.sources.push({id,repository:'sgf',path});const stage=plan.stages.find(s=>s.id==='requisition_order');if(!stage.source_ids.includes(id))stage.source_ids.push(id);}
plan.stages.find(s=>s.id==='requisition_order').gap+=' The earlier100-supplier selection cap is resolved in demo8073: literal name/NUIT search and server pages25/100, explicit selection, stale-response protection and supplier fingerprint revalidation before a new quotation. Existing rights and native rules are reused; no deployment or sustained-load capacity conclusion.';
for(const id of ['requisition_order','supplier_invoice','supplier_payable'])plan.stages.find(s=>s.id===id).evidence.push(proof('purchasing-dossier-composition-20261103.json',[{pointer:'/passed',equals:true},{pointer:'/checks',equals:49}]));
for(const [id,path]of [['sgf_dossier_controller','app/Modules/Purchasing/DossierController.php'],['sgf_dossier_screen','resources/views/purchasing-dossier.blade.php'],['sgf_dossier_ui','public/purchasing-dossier.mjs']]){if(!plan.sources.some(s=>s.id===id))plan.sources.push({id,repository:'sgf',path});const stage=plan.stages.find(s=>s.id==='requisition_order');if(!stage.source_ids.includes(id))stage.source_ids.push(id);}
plan.stages.find(s=>s.id==='requisition_order').gap+=' A GET-only dossier now correlates the actual request through independently authorised downstream evidence in demo8074, with independent25-row pages and filtered history. Read proof reuses the completed canonical regression book without repeating financial commands; all142 tables and sequences remain unchanged. This is not a universal task queue, readiness decision or deployment validation.';
plan.stages.find(s=>s.id==='accepted_receipt').evidence.push(proof('receipt-workspace-completion-20261103.json',[{pointer:'/passed',equals:true},{pointer:'/checks',equals:41}]));
for(const [id,path]of [['sgf_receipt_catalogue','app/Modules/Purchasing/ReceiptCatalogue.php'],['sgf_receipt_workspace_ui','public/receipt-workspace.mjs']]){if(!plan.sources.some(s=>s.id===id))plan.sources.push({id,repository:'sgf',path});const stage=plan.stages.find(s=>s.id==='accepted_receipt');if(!stage.source_ids.includes(id))stage.source_ids.push(id);}
plan.stages.find(s=>s.id==='accepted_receipt').gap+=' Demo8075 now provides per-line article search/pages25/100 beyond the earlier100 cap and navigable receipt history beyond25, with explicit choice and article fingerprint revalidation before a new physical confirmation. Existing unit/binding rules and writer remain authoritative;27 partial receipts total exactly1UN in regression, with25 native-writer history fixtures. Catalogue requests are deferred until a line is selected. No new valuation, payment, visual, sustained-load or deployment claim.';
plan.stages.find(s=>s.id==='requisition_order').evidence.push(proof('supplier-documents-composition-20261103.json',[{pointer:'/passed',equals:true},{pointer:'/checks',equals:52}]));
for(const [id,path]of [['sgf_supplier_documents','app/Modules/Purchasing/SupplierDocumentsController.php'],['sgf_supplier_document_storage','app/Modules/Purchasing/SupplierDocumentFiles.php'],['sgf_supplier_document_ui','public/supplier-documents.mjs']]){if(!plan.sources.some(s=>s.id===id))plan.sources.push({id,repository:'sgf',path});const stage=plan.stages.find(s=>s.id==='requisition_order');if(!stage.source_ids.includes(id))stage.source_ids.push(id);}
plan.stages.find(s=>s.id==='requisition_order').gap+=' Supplier binary evidence is now delivered in demo8076 through the original native upload/download and review invalidation, with private storage, content/context/version conference, idempotent command provenance and bounded metadata pages15. Pending evidence excludes the supplier from sourcing until a distinct current-version review. Other attachment types, authenticity requirements, crash-orphan reconciliation, retention, sustained load and deployment remain separate.';
plan.stages.find(s=>s.id==='accepted_receipt').evidence.push(proof('receipt-documents-composition-20261103.json',[{pointer:'/passed',equals:true},{pointer:'/checks',equals:58}]));
for(const [id,path]of [['sgf_receipt_documents','app/Modules/Purchasing/ReceiptDocumentsController.php']]){if(!plan.sources.some(s=>s.id===id))plan.sources.push({id,repository:'sgf',path});const stage=plan.stages.find(s=>s.id==='accepted_receipt');if(!stage.source_ids.includes(id))stage.source_ids.push(id);}
plan.stages.find(s=>s.id==='accepted_receipt').gap+=' Receipt delivery/quality/other binary evidence is delivered in demo8077 through the pinned native attachment service and private download, with bounded pages15 and dossier events. Individual reason, current source/context/revision/bytes, idempotent keys, content reuse within receipt/type and verified rollback compensation are proven. One HTTP-created document and15 native volume fixtures preserve one1000milli physical movement. Attachment is not a new acceptance/quality decision or authenticity certification. Orphan reconciliation, retention/quotas, other origins, visual review, sustained load and deployment remain separate.';
for(const id of ['requisition_order','accepted_receipt','supplier_invoice','supplier_payable'])plan.stages.find(s=>s.id===id).evidence.push(proof('purchasing-focus-composition-20261103.json',[{pointer:'/passed',equals:true},{pointer:'/checks',equals:77}]));
for(const [id,path]of [['sgf_process_navigation','app/Modules/Purchasing/ProcessNavigation.php'],['sgf_purchasing_focus','public/purchasing-focus.mjs']]){if(!plan.sources.some(s=>s.id===id))plan.sources.push({id,repository:'sgf',path});const stage=plan.stages.find(s=>s.id==='requisition_order');if(!stage.source_ids.includes(id))stage.source_ids.push(id);}
for(const id of ['requisition_order','accepted_receipt','supplier_invoice','supplier_payable'])plan.stages.find(s=>s.id===id).gap+=' Contextual read navigation is delivered in demo8078: authorised dossier cards open exact source ids across seven workspaces, including receipt evidence and invoice-specific obligation consultation. Strict parameter parsing, destination authority, parent matching and stale startup cancellation avoid first-page dependence and automatic fallback. The completed canonical QA book is reused without command replay;142 tables and sequences are unchanged. This does not decide readiness, execute a next stage, grant access, validate visual rendering, sustained load or deployment.';
for(const id of ['requisition_order','accepted_receipt','supplier_invoice','supplier_payable'])plan.stages.find(s=>s.id===id).evidence.push(proof('purchasing-continuity-composition-20261103.json',[{pointer:'/passed',equals:true},{pointer:'/checks',equals:55}]));
for(const [stageId,id,path]of [['requisition_order','sgf_stage_history','app/Modules/Purchasing/ProcessHistory.php'],['supplier_invoice','sgf_invoice_workspace_ui','public/supplier-invoice-workspace.mjs'],['supplier_payable','sgf_obligation_workspace_ui','public/supplier-obligation-workspace.mjs']]){if(!plan.sources.some(s=>s.id===id))plan.sources.push({id,repository:'sgf',path});const stage=plan.stages.find(s=>s.id===stageId);if(!stage.source_ids.includes(id))stage.source_ids.push(id);}
plan.stages.find(s=>s.id==='requisition_order').gap+=' A subsequent scope fix filters request/sourcing audit events in SQL before limits/counts/pages, closing an alternate downstream financial-history exposure without changing original audit or writers. Empty initial supplier searches now survive middleware normalisation while closed-award and permission guards remain. Completed canonical history book is reused read-only with142 tables/sequences intact.';
plan.stages.find(s=>s.id==='accepted_receipt').gap+=' Demo8079 fixes the actual form-to-picker binding and blank initial article search. DOM-to-real-HTTP proof selects an article, transmits its revision, previews, confirms1UN and recovers a deliberately lost response with201/200, one receipt/movement. This is not browser visual acceptance or a new concurrency/load trial.';
for(const id of ['accepted_receipt','supplier_invoice','supplier_payable'])plan.stages.find(s=>s.id===id).gap+=' Inline receipt/invoice/obligation source links now preserve ids and follow the currently presented menu; destination APIs remain authoritative. No new financial effect, permission, deployment or operational-readiness claim.';
plan.stages.find(s=>s.id==='requisition_order').evidence.push(proof('request-history-composition-20261103.json',[{pointer:'/passed',equals:true},{pointer:'/checks',equals:36}]));
for(const [id,path]of [['sgf_request_history_ui','public/request-history.mjs'],['sgf_request_workspace_ui','public/request-workspace.mjs']]){if(!plan.sources.some(s=>s.id===id))plan.sources.push({id,repository:'sgf',path});const stage=plan.stages.find(s=>s.id==='requisition_order');if(!stage.source_ids.includes(id))stage.source_ids.push(id);}
plan.stages.find(s=>s.id==='requisition_order').gap+=' Demo8080 removes the direct request-history25-event cap using bounded cursor pages25/100, own-stage SQL filtering and encrypted request/actor/context/size-bound cursors with600-second lifetime. Initial page is reused; history refresh does not reset unsaved request fields.127 original event ids traverse once despite a new head note; refresh includes128. Audit-volume fixtures are not operational request revisions. An inherited100MZN order setup was preserved and removed from future history harness runs. This is not a persistent MVCC snapshot, visual acceptance, sustained-load or deployment validation.';
plan.stages.find(s=>s.id==='supplier_invoice').evidence.push(proof('invoice-matching-progress-20261103.json',[{pointer:'/passed',equals:true},{pointer:'/checks',equals:47}]));
for(const [id,path]of [['sgf_invoice_matching_progress','app/Modules/Purchasing/InvoiceMatchingProgress.php'],['sgf_invoice_matching_ui','public/invoice-matching.mjs']]){if(!plan.sources.some(s=>s.id===id))plan.sources.push({id,repository:'sgf',path});const stage=plan.stages.find(s=>s.id==='supplier_invoice');if(!stage.source_ids.includes(id))stage.source_ids.push(id);}
plan.stages.find(s=>s.id==='supplier_invoice').gap+=' Demo8081 exposes per-line ordered/accepted/returned/reversed/validated/pending/remaining quantities using two aggregate fact queries and original correction values. Pending documents do not reserve quantity; overlap is a read warning, not a replacement for native validation. Two completed QA books are reused read-only with all tables/sequences unchanged. The display revision uses one original state observation before capability decoration; mutation/state definitions are unchanged. Full dependency materialisation, large invoice-history scaling, visual review, sustained load and deployment remain pending.';
plan.stages.find(s=>s.id==='supplier_payable').evidence.push(proof('obligation-evidence-workspace-20261103.json',[{pointer:'/passed',equals:true},{pointer:'/checks',equals:26}]));
if(!plan.sources.some(s=>s.id==='sgf_obligation_evidence_ui'))plan.sources.push({id:'sgf_obligation_evidence_ui',repository:'sgf',path:'public/obligation-evidence.mjs'});if(!plan.stages.find(s=>s.id==='supplier_payable').source_ids.includes('sgf_obligation_evidence_ui'))plan.stages.find(s=>s.id==='supplier_payable').source_ids.push('sgf_obligation_evidence_ui');
plan.stages.find(s=>s.id==='supplier_payable').gap+=' Demo8082 separates evidence browsing from an explicitly selected proposal decision. Reason and preview survive pagination; changed observed source/actor/permissions invalidate old forms, and late reads/previews cannot reactivate them. Temporary read failure preserves the form; in-flight operations prevent selection changes.26 new simulated-UI/demo checks reuse72 native authority checks without repetition. Controller/runtime/kernel and legacy evidence branch are unchanged. No new real confirmation, financial writer, backend pagination protocol, visual/load or deployment validation.';
for(const id of ['accepted_receipt','physical_stock'])plan.stages.find(s=>s.id===id).evidence.push(proof('stock-composed-source-20261103.json',[{pointer:'/passed',equals:true},{pointer:'/checks',equals:41}]));
if(!plan.sources.some(s=>s.id==='sgf_composed_stock_read'))plan.sources.push({id:'sgf_composed_stock_read',repository:'sgf',path:'app/Modules/Inventory/CompositionStockRead.php'});
for(const id of ['accepted_receipt','physical_stock'])if(!plan.stages.find(s=>s.id===id).source_ids.includes('sgf_composed_stock_read'))plan.stages.find(s=>s.id===id).source_ids.push('sgf_composed_stock_read');
plan.stages.find(s=>s.id==='physical_stock').gap+=' The integrated Purchasing QA host now observes the same physical book through a SELECT-only Stock role, explicit warehouse mapping and existing React reader (demo8083). Operational installation and real bindings remain pending; no additional valuation or availability is supplied.';
for(const id of ['accepted_receipt','physical_stock'])plan.stages.find(s=>s.id===id).evidence.push(proof('stock-receipt-trace-20261103.json',[{pointer:'/passed',equals:true},{pointer:'/checks',equals:46}]));
for(const [id,file]of [['sgf_stock_receipt_trace','app/Modules/Purchasing/StockReceiptTraceController.php'],['sgf_stock_receipt_transition','resources/js/stock-receipt-trace.js'],['sgf_stock_receipt_focus','public/stock-receipt-focus.mjs']]){if(!plan.sources.some(s=>s.id===id))plan.sources.push({id,repository:'sgf',path:file});for(const stage of ['accepted_receipt','physical_stock'])if(!plan.stages.find(s=>s.id===stage).source_ids.includes(id))plan.stages.find(s=>s.id===stage).source_ids.push(id);}
plan.stages.find(s=>s.id==='physical_stock').gap+=' Demo8084 adds explicit Stock-to-Purchasing receipt evidence navigation for current receipt_in movements. The server resolves actual parent ids, current rights and scope; no inferred historical origin, business command or wider Stock reader grants. Existing Purchasing runtime locks remain; no new load/deployment claim.';
plan.stages.find(s=>s.id==='physical_stock').evidence.push(proof('stock-period-report-20261103.json',[{pointer:'/passed',equals:true},{pointer:'/checks',equals:52}]));
for(const [id,file]of [['sgf_stock_period_projection','app/Modules/Inventory/StockPeriodReport.php'],['sgf_stock_period_ui','resources/js/StockPeriodReportWorkspace.jsx'],['sgf_stock_period_request','resources/js/stock-period-request.js']]){if(!plan.sources.some(s=>s.id===id))plan.sources.push({id,repository:'sgf',path:file});if(!plan.stages.find(s=>s.id==='physical_stock').source_ids.includes(id))plan.stages.find(s=>s.id==='physical_stock').source_ids.push(id);}
plan.stages.find(s=>s.id==='physical_stock').gap+=' Demo8085 delivers a UTC-registration-period physical quantity report with opening/incoming/outgoing/closing per article/warehouse, exact numeric/text quantities, explicit dates and25/100 SQL pages. Five projection SELECTs at either page size;105 pairs are SQL fixtures, not workflow operations. No cross-unit total, valuation, availability, full export, sustained-load or deployment claim.';
for(const stage of ['requisition_order','accepted_receipt','supplier_invoice','supplier_payable']){plan.stages.find(s=>s.id===stage).evidence.push(proof('purchasing-completion-final-20261104-r2.json',[{pointer:'/passed',equals:true},{pointer:'/criteria/C10/passed',equals:true}]));plan.stages.find(s=>s.id===stage).gap+=' On04/11 the agreed local acquisition-to-payable journey was completed through actual UI modules and HTTP in the existing8085 installation, including a new reviewed supplier and distinct decisions. One entry /compras, document retention, readable previews and exit protection; no new database, port, isolated demo or business-engine copy. This does not validate real deployment, payments/accounting of this origin or visual acceptance.';}
for(const [id,file]of [['sgf_purchasing_entry','app/Modules/Purchasing/PurchasingEntry.php'],['sgf_purchasing_board','public/purchasing-board.mjs'],['sgf_purchasing_presenter','public/purchasing-presenter.mjs'],['sgf_purchasing_exit_guard','public/purchasing-exit.mjs']]){if(!plan.sources.some(s=>s.id===id))plan.sources.push({id,repository:'sgf',path:file});for(const stage of ['requisition_order','accepted_receipt','supplier_invoice','supplier_payable'])if(!plan.stages.find(s=>s.id===stage).source_ids.includes(id))plan.stages.find(s=>s.id===stage).source_ids.push(id);}
let updated=text;for(const stage of plan.stages){const lines=updated.split('\n');const index=lines.findIndex(line=>{try{const value=JSON.parse(line.trim().replace(/,$/,''));return value.id===stage.id&&value.owner;}catch{return false;}});if(index<0)throw Error('Stage line missing');const comma=lines[index].trimEnd().endsWith(',');lines[index]=' '+JSON.stringify(stage)+(comma?',':'');updated=lines.join('\n');}
for(const [id,contract]of [['sales_invoice','COMMON-LEDGER-SALES-RECEIVABLE-SIM-v1'],['customer_receivable','COMMON-LEDGER-SALES-RECEIVABLE-SIM-v1'],['physical_stock','COMMON-LEDGER-STOCK-VALUATION-SIM-v1']]){const lines=updated.split('\n');const index=lines.findIndex(line=>{try{const v=JSON.parse(line.trim().replace(/,$/,''));return v.source===id&&v.target==='general_ledger';}catch{return false;}});if(index<0)throw Error('Missing event edge');const comma=lines[index].trimEnd().endsWith(','),edge=JSON.parse(lines[index].trim().replace(/,$/,''));edge.synthetic_delivery=contract;lines[index]=' '+JSON.stringify(edge)+(comma?',':'');updated=lines.join('\n');}
const start=updated.indexOf(' "sources": [');if(start<0)throw Error('Source section missing');updated=updated.slice(0,start)+' "sources": '+JSON.stringify(plan.sources,null,2).replaceAll('\n','\n ')+'\n}\n';
fs.writeFileSync(file,updated);