hasTable('gl_industrial_correction_capability'))throw new LogicException('Explicit new industrial correction capability required'); if($phase==='ledger-cost-industrial-correction-ready'){ $out=$s['root'].'/industrial-correction-fixture.json';if(file_exists($out)||DB::table('gl_journals')->where('snapshot->source->effect_type','industry.cost.validated')->exists())throw new LogicException('Fresh industrial correction fixture required');$p=$command('prepare','effect-prepare',$body);$command('validate','validate',['proposal_id'=>$p['proposal_id'],'revision'=>$p['revision'],'decision'=>'approved','reason'=>'Distinct original industrial1800 journal review.']);$j=$command('prepare','post',['proposal_id'=>$p['proposal_id'],'revision'=>$p['revision'],'reason'=>'Original industrial1800 immutable baseline.']);$original=(array)DB::table('gl_journals')->where('id',$j['journal_id'])->first();$old=DB::table('ic_inputs')->find($i['refs']['material_rate']['id']);$data=json_decode($old->data,true);$data['amount']='51';$rate=$ic->input($i['lot_id'],$enter('prepare')->id,['kind'=>'material_rate','source_ref'=>$old->source_ref,'version'=>2,'previous_id'=>$old->id,'data'=>$data,'evidence'=>'Explicit authorised20KGx51=1020; labour500 and CIF300 retained.'],(string)Str::uuid());$ic->decide($i['lot_id'],$enter('validate')->id,['type'=>'input','id'=>$rate['id'],'version'=>2,'decision'=>'approved','reason'=>'Distinct exact industrial successor rate51.'],(string)Str::uuid());$refs=$i['refs'];$refs['material_rate']=['id'=>$rate['id'],'version'=>2];$r=$ic->calculate($i['lot_id'],$enter('prepare')->id,['version'=>2,'previous_id'=>$i['result_id'],'refs'=>$refs,'currency'=>'MZN'],(string)Str::uuid());$ic->decide($i['lot_id'],$enter('validate')->id,['type'=>'result','id'=>$r['id'],'version'=>2,'decision'=>'approved','reason'=>'Distinct selected industrial1820/10UN=182; residual300 remains separate.'],(string)Str::uuid());foreach(['REVERSE'=>'reversal','REPLACE'=>'replacement'] as $name=>$kind)DB::table('gl_rules')->insert($scope+['rule_key'=>'QA-INDUSTRIAL-CORRECTION-'.$name,'version'=>1,'policy'=>'QA-INDUSTRIAL-JOURNAL-v1','effect_type'=>'industry.cost.'.$kind,'currency'=>'MZN','valid_from'=>'2026-10-01','valid_to'=>'2026-10-31','debit_account_id'=>$i['accounts'][$kind==='reversal'?'QA-COMPENSACAO-INDUSTRIAL':'QA-CUSTO-INDUSTRIAL'],'credit_account_id'=>$i['accounts'][$kind==='reversal'?'QA-CUSTO-INDUSTRIAL':'QA-COMPENSACAO-INDUSTRIAL'],'created_by'=>$g['actors']['prepare'],'reason'=>'Explicit new authorised artificial industrial correction rule.','created_at'=>now()]);$source=$provider->source($enter('read'),$i['lot_id']);if($source['principal_minor']!==182000||$source['residual_exact']!=='300'||$source['unit_cost_exact']!=='182')throw new LogicException('Actual successor1820/residual300 must reconcile');file_put_contents($out,json_encode(['passed'=>true,'original_journal_id'=>$j['journal_id'],'original_journal_sha256'=>hash('sha256',Payables::canonical($original)),'original_result_sha256'=>hash('sha256',Payables::canonical((array)DB::table('ic_results')->where('id',$i['result_id'])->first())),'replacement_rate_id'=>$rate['id'],'replacement_result_id'=>$r['id'],'replacement_refs'=>$refs,'original_minor'=>180000,'replacement_minor'=>182000,'residual_exact'=>'300','source_fingerprint'=>$fingerprint(),'initial_industrial_correction_groups'=>0],JSON_PRETTY_PRINT|JSON_THROW_ON_ERROR));echo "Original industrial1800 posted; actual successor51/result1820 independently approved, residual300 separate; no correction group.\n";exit; } $ig=json_decode(file_get_contents($s['root'].'/industrial-correction-fixture.json'),true,64,JSON_THROW_ON_ERROR);$correctionBody=['journal_id'=>$ig['original_journal_id'],'journal_on'=>'2026-10-29','period_key'=>'QA-2026-10','reason'=>'Explicit indivisible industrial reversal1800 and replacement1820.'];$captureCorrection=fn()=>$command('prepare','correct-prepare',$correctionBody);$approveCorrection=fn($p)=>$command('validate','correct-validate',['correction_id'=>$p['correction_id'],'revision'=>$p['revision'],'decision'=>'approved','reason'=>'Distinct exact industrial original1800, successor1820, delta20 and four-line pair.']);$postCorrectionBody=fn($p)=>['correction_id'=>$p['correction_id'],'revision'=>$p['revision'],'reason'=>'Apply reviewed industrial correction pair atomically once.']; $originalsIntact=fn()=>$fingerprint()===$ig['source_fingerprint']&&hash('sha256',Payables::canonical((array)DB::table('gl_journals')->where('id',$ig['original_journal_id'])->first()))===$ig['original_journal_sha256']&&hash('sha256',Payables::canonical((array)DB::table('ic_results')->where('id',$i['result_id'])->first()))===$ig['original_result_sha256']; if($phase==='ledger-cost-industrial-correction-deep-scope'){require __DIR__.'/ledger-industrial-correction-deep-scope.php';exit;} if($phase==='ledger-cost-industrial-correction-security'){require __DIR__.'/ledger-industrial-correction-security.php';exit;} if($phase==='ledger-cost-industrial-correction-coexistence'){require __DIR__.'/ledger-industrial-correction-coexistence.php';exit;} if($phase==='ledger-cost-industrial-correction-cases'){require __DIR__.'/ledger-industrial-correction-cases.php';exit;} if(in_array($phase,['ledger-cost-industrial-correction-race','ledger-cost-industrial-correction-worker'],true)){require __DIR__.'/ledger-industrial-correction-race.php';exit;} if(in_array($phase,['ledger-cost-industrial-correction-preservation','ledger-cost-industrial-correction-postcheck'],true)){$out=$s['root'].($phase==='ledger-cost-industrial-correction-postcheck'?'/industrial-correction-demo-post.json':'/industrial-correction-demo-preservation.json');if(file_exists($out)||!$originalsIntact()||DB::table('gl_corrections')->exists()||DB::table('gl_period_closures')->exists()||DB::table('gl_journals')->count()!==2)throw new LogicException('Initial team state changed; no reset');file_put_contents($out,json_encode(['passed'=>true,'initial_journals'=>2,'initial_industrial_groups'=>0,'initial_closures'=>0,'source_original_outbox_rights_exact'=>true],JSON_PRETTY_PRINT));exit;} if($phase==='ledger-cost-industrial-correction-final'){ $out=$s['root'].'/industrial-correction-final.json';if(file_exists($out))throw new LogicException('Completed final preserved');$w=$ledger->industrial($enter('prepare'),$i['lot_id']);$report=$ledger->report($enter('read'),'trial-balance',['from_on'=>'2026-10-01','to_on'=>'2026-10-31']);$account=$ledger->report($enter('read'),'account-ledger',['from_on'=>'2026-10-01','to_on'=>'2026-10-31','account_id'=>$i['accounts']['QA-CUSTO-INDUSTRIAL']]);$page=view('accounting.industrial-ledger',['data'=>$w])->render();if(DB::table('gl_journals')->count()!==11||DB::table('gl_lines')->count()!==23||DB::table('gl_period_closures')->count()!==1||$report['totals']['debit_minor']!==872500||$account['closing_net_minor']!==182000||$w['industrial']['accounting_state']!=='current'||count(array_filter($w['corrections'],fn($g)=>$g->result!==null))!==1||str_contains($page,'data-action='))throw new LogicException('Final industrial correction/joint close differs');DB::select('SELECT gl_assert_balanced(id) FROM gl_journals');DB::select('SELECT gl_industrial_pair_assert(c.id) FROM gl_corrections c JOIN gl_correction_results r ON r.correction_id=c.id JOIN gl_journals j ON j.id=c.original_journal_id WHERE j.snapshot->\'source\'->>\'effect_type\'=\'industry.cost.validated\'');file_put_contents($out,json_encode(['passed'=>true,'journals'=>11,'lines'=>23,'gross_minor'=>872500,'industrial_closing_minor'=>182000,'residual_exact'=>'300','joint_closures'=>1,'typed_industrial_groups'=>1,'closed_ui_no_commands'=>true,'current_source_resolved'=>true],JSON_PRETTY_PRINT|JSON_THROW_ON_ERROR));echo "Joint final11 journals/23 lines, gross8725, industrial1820 and one close; source resolved and UI read only.\n";exit; } if($phase==='ledger-cost-industrial-correction-workflow'){ $out=$s['root'].'/industrial-correction-workflow.json';if(file_exists($out)||DB::table('gl_corrections')->exists())throw new LogicException('Fresh industrial correction workflow');$p=$captureCorrection();$approveCorrection($p);$body=$postCorrectionBody($p);$key=(string)Str::uuid();$r=$command('prepare','correct-post',$body,$key);$repeat=$command('prepare','correct-post',$body,$key);$other=$command('prepare','correct-post',$body);$book=$ledger->listing($enter('read'),['industrial_lot_id'=>$i['lot_id']]);if(!$repeat['replayed']||$r['result_id']!==$other['result_id']||!$originalsIntact()||count($book['journals'])!==3||count($book['lines'])!==6||count($book['events'])!==9||$book['totals']['debit_minor']!==542000||$ledger->industrial($enter('read'),$i['lot_id'])['industrial']['accounting_state']!=='current')throw new LogicException('Industrial pair/source/repetition mismatch');DB::select('SELECT gl_industrial_pair_assert(?)',[$p['correction_id']]);file_put_contents($out,json_encode(['passed'=>true,'industrial_journals'=>3,'industrial_lines'=>6,'industrial_events'=>9,'gross_minor'=>542000,'industrial_balance_minor'=>182000,'source_original_outbox_rights_exact'=>true,'same_and_other_key_no_duplicate'=>true],JSON_PRETTY_PRINT|JSON_THROW_ON_ERROR));echo "Industrial pair1800->1820 applied once; three typed journals/six lines, gross5420; originals and residual300 preserved.\n";exit; } throw new LogicException('Unknown industrial correction phase');