Files
SGF/scripts/industrial-budget-concurrency.php
T

27 lines
4.0 KiB
PHP

<?php
require __DIR__.'/../vendor/autoload.php';$app=require __DIR__.'/../bootstrap/app.php';$app->make(\Illuminate\Contracts\Console\Kernel::class)->bootstrap();
use App\Modules\Industry\IndustrialBudgets;
use App\Shared\Context\CompanyContext;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
use Symfony\Component\Process\Process;
IndustrialBudgets::guard();$f=json_decode(file_get_contents('C:/laragon/data/sgf-tempo/secrets/browser-fixture.json'),true,32,JSON_THROW_ON_ERROR);$fx=$f['budget_fixture'];$proof=[];$key=fn()=>(string)Str::uuid();
$base=['tenant'=>$f['tenant'],'company'=>$f['company'],'unit'=>$f['unit'],'lot'=>$fx['lot']];
$pair=function($one,$two)use($base){
$a=new Process([PHP_BINARY,'scripts/industrial-budget-worker.php','--env=testing'],base_path(),null,json_encode($one+$base+['pause'=>true]));$b=new Process([PHP_BINARY,'scripts/industrial-budget-worker.php','--env=testing'],base_path(),null,json_encode($two+$base));
$a->start();if(!$a->waitUntil(fn($t,$v)=>str_contains($v,'LOCK_HELD')))throw new RuntimeException('Budget concurrent lock not observed.');$b->start();$a->wait();$b->wait();$out=[];
foreach([$a,$b] as $p){if(!$p->isSuccessful())throw new RuntimeException('Budget worker failed.');$lines=array_values(array_filter(explode("\n",trim($p->getOutput())),fn($v)=>str_starts_with($v,'{')));$out[]=json_decode(end($lines),true,32,JSON_THROW_ON_ERROR);}return $out;
};
$check=function($out,bool $replay){if($out[0]['status']!==200||$out[1]['status']!==($replay?200:409)||($replay&&(!$out[1]['result']['replayed']||$out[0]['result']['id']!==$out[1]['result']['id'])))throw new RuntimeException('Unexpected concurrent budget outcome.');return $out[0]['result']['id'];};
$last=DB::table('ib_budgets')->where('lot_id',$fx['lot'])->orderByDesc('version')->first();
$p=['actor'=>$f['manager_id'],'method'=>'propose','key'=>$key(),'input'=>['version'=>($last?->version??0)+1,'previous_id'=>$last?->id,'dimensions'=>app(IndustrialBudgets::class)->dimensions(DB::table('ic_lots')->find($fx['lot'])),'amounts'=>['material'=>'900','labour'=>'600','allocated'=>'300'],'evidence'=>'Successeur synthétique explicitement révisé.']];
$id=$check($pair($p,$p),true);$proof['proposal_replay_one_version']=true;
$d=['actor'=>$f['reader_id'],'method'=>'decide','key'=>$key(),'input'=>['id'=>$id,'version'=>$p['input']['version'],'decision'=>'approved','reason'=>'Revue synthétique distincte.']];$check($pair($d,$d),true);$proof['decision_replay_one_effect']=true;
$result=DB::table('ic_results')->where('lot_id',$fx['lot'])->orderByDesc('version')->first();$lastC=DB::table('ib_comparisons')->where('lot_id',$fx['lot'])->orderByDesc('version')->first();
$c=['actor'=>$f['manager_id'],'method'=>'compare','key'=>$key(),'input'=>['version'=>($lastC?->version??0)+1,'previous_id'=>$lastC?->id,'budget_id'=>$id,'budget_version'=>$p['input']['version'],'result_id'=>$result->id,'result_version'=>$result->version]];
$cid=$check($pair($c,$c),true);$proof['comparison_replay_one_snapshot']=true;
$p['key']=$key();$p['input']['version']++;$p['input']['previous_id']=$id;$other=$p;$other['key']=$key();$other['input']['amounts']['material']='950';$new=$check($pair($p,$other),false);$proof['competing_successors_one_winner']=true;
$d['key']=$key();$d['input']['id']=$new;$d['input']['version']=$p['input']['version'];$other=$d;$other['key']=$key();$other['input']['decision']='refused';$check($pair($d,$other),false);$proof['competing_decisions_one_winner']=true;
$c['key']=$key();$c['input']['version']++;$c['input']['previous_id']=$cid;$c['input']['budget_id']=$new;$c['input']['budget_version']=$p['input']['version'];$other=$c;$other['key']=$key();$check($pair($c,$other),false);$proof['competing_comparisons_one_revision']=true;
file_put_contents(base_path('docs/proofs/industrial-budget-concurrency.json'),json_encode(['policy'=>IndustrialBudgets::POLICY,'database'=>'sgf_tempo_test','overlapping_processes_per_case'=>2,'checks'=>$proof,'synthetic_only'=>true],JSON_PRETTY_PRINT|JSON_THROW_ON_ERROR));echo "Six overlapping budget concurrency cases passed.\n";