select("SELECT tablename FROM pg_tables WHERE schemaname='public' ORDER BY tablename") as $r){$table=$r->tablename;if(!preg_match('/^[a-z_][a-z0-9_]*$/D',$table))throw new LogicException('Table');$tables[$table]=(array)$db->selectOne('SELECT count(*) rows,md5(coalesce(string_agg(row_to_json(t)::text,chr(10) ORDER BY row_to_json(t)::text),\'\')) hash FROM "'.$table.'" t');}return hash('sha256',json_encode($tables));}; $before=$snapshot($host);$installer=new CompositionSchema; $result=$installer->run(false,function($db)use($app,$installer,$f,$ok){ config(['sgf_single_installation.enabled'=>true,'sgf_single_installation.schema_sha256'=>$installer->fingerprint()]); $id=(int)$db->table('permission_grants')->max('id')+1000; foreach(['clients.view','clients.create','services.view','services.create','service_drafts.view','service_drafts.create','billing_drafts.view','billing_drafts.create','workshop.view','workshop.open','workshop.assign','workshop.authorize','workshop.record','workshop.verify'] as $right){ $scope=['tenant_id'=>$f['tenant'],'company_id'=>$f['company'],'unit_id'=>str_starts_with($right,'clients.')||str_starts_with($right,'services.')?null:$f['unit'],'user_id'=>$f['actor'],'permission'=>$right]; if(!$db->table('permission_grants')->where($scope)->exists())$db->table('permission_grants')->insert(['id'=>$id++]+$scope); } $user=App\Models\User::findOrFail($f['actor']);Auth::guard('web')->setUser($user);$session=app('session')->driver();$session->start();$session->put('company_context',$f['scope']+['token'=>'single-composition-proof','module_id'=>'commercial']); $request=Illuminate\Http\Request::create('/api/a/clients','POST');$request->setLaravelSession($session);$request->setUserResolver(fn()=>$user);$request->attributes->set('sgf_module','commercial');$app->instance('request',$request); $ctx=app(CompanyContext::class);$ctx->selectFor($user->id,$f['tenant'],$f['company'],$f['unit']); $service=app(ServiceWorkflow::class);$client=$service->save('clients',null,$user->id,['name'=>'Cliente novo do percurso único QA'],(string)Str::uuid())['id']; $catalogue=$service->save('services',null,$user->id,['name'=>'Diagnóstico de ensaio'],(string)Str::uuid())['id']; $draft=$service->save('service_drafts',null,$user->id,['client_id'=>$client,'currency'=>'MZN','lines'=>[['service_id'=>$catalogue,'description'=>'Diagnóstico QA','quantity'=>'1','unit_price'=>'100']]],(string)Str::uuid()); $billing=$service->save('billing_drafts',null,$user->id,['source_id'=>$draft['id']],(string)Str::uuid()); $ok($db->table('a_billing_drafts')->where('id',$billing['id'])->value('source_id')===$draft['id'],'Comercial preserves service-to-billing origin in the composed host'); $ok(ModuleRecords::query('a_clients')->where('id',$client)->exists(),'new client explicitly belongs to Comercial'); $request->attributes->set('sgf_module','workshop');$session->put('company_context.module_id','workshop'); $input=['reference'=>'OT-UNICA-'.Str::uuid(),'client_id'=>$client,'equipment_identifier'=>'EQ-'.Str::uuid(),'equipment_description'=>'Equipamento fictício','request'=>'Diagnóstico no mesmo SGF','location'=>'Unidade QA','evidence'=>'Pedido novo sintético, sem alterar pendentes']; $workshop=app(WorkshopWorkflow::class);$blocked=false;try{$workshop->open($user->id,$input,(string)Str::uuid());}catch(Symfony\Component\HttpKernel\Exception\HttpExceptionInterface $e){$blocked=$e->getStatusCode()===403;} $ok($blocked,'cross-module client is refused before an explicit individual association'); ModuleRecords::associate('clients',$client,$user->id,['tenant_id'=>$f['tenant'],'company_id'=>$f['company'],'unit_id'=>null],'workshop','Decisão individual apenas sobre este cliente novo do ensaio.',false,1); $key=(string)Str::uuid();$order=$workshop->open($user->id,$input,$key);$retry=$workshop->open($user->id,$input,$key); $ok($order['id']===$retry['id']&&$retry['replayed'],'Oficinas opens once and recovers the same order without duplication'); $ok($db->table('wo_orders')->where('id',$order['id'])->value('client_id')===$client,'Oficinas retains the exact explicitly associated Comercial client'); foreach(['unit.view','workshop.view'] as $right){$grant=['tenant_id'=>$f['tenant'],'company_id'=>$f['company'],'unit_id'=>$f['foreign_unit'],'user_id'=>$user->id,'permission'=>$right];if(!$db->table('permission_grants')->where($grant)->exists())$db->table('permission_grants')->insert(['id'=>$id++]+$grant);} $ctx->selectFor($user->id,$f['tenant'],$f['company'],$f['foreign_unit']);$foreign=$workshop->listing($user->id);$ok(!array_filter($foreign['orders'],fn($o)=>(int)$o['id']===$order['id']),'another authorized unit cannot see the new order');$ctx->selectFor($user->id,$f['tenant'],$f['company'],$f['unit']); $destructiveBlocked=false;try{Event::dispatch(new Illuminate\Console\Events\CommandStarting('migrate:fresh',new Symfony\Component\Console\Input\ArrayInput([]),new Symfony\Component\Console\Output\NullOutput));}catch(RuntimeException $e){$destructiveBlocked=$e->getMessage()==='SGF_COMPOSITION_DESTRUCTIVE_COMMAND_REFUSED';} $ok($destructiveBlocked,'destructive command is refused by the command-start guard without executing it'); $ok($db->table('si_invoices')->count()===0&&$db->table('sr_records')->count()===0,'new drafts and workshop order do not issue invoices or create financial effects automatically'); return ['synthetic_client'=>$client,'service_draft'=>$draft['id'],'billing_draft'=>$billing['id'],'workshop_order'=>$order['id'],'rollback'=>true]; }); $ok($snapshot($host)===$before,'all original table rows unchanged after rolling back the new composed flow'); $result=['passed'=>true,'checks'=>$checks,'schema'=>$result,'target8085_touched'=>false,'qa_sequences_may_advance'=>true,'previous_schema_proof_reused'=>'sgf-composition-proof-32c029d5b44c','new_database'=>false,'new_server'=>false];file_put_contents($proof.'/flow-result.json',json_encode($result,JSON_PRETTY_PRINT|JSON_THROW_ON_ERROR));echo json_encode(['passed'=>true,'checks'=>count($checks),'proof'=>$proof.'/flow-result.json']).PHP_EOL;