Preserve authorised industrial budget installation and seven audited grants
This commit is contained in:
@@ -1,5 +1,7 @@
|
|||||||
# SGF Tempo — instruções locais
|
# SGF Tempo — instruções locais
|
||||||
|
|
||||||
|
- Autorização específica posterior de 28/10/2026 executada: apenas `110000` aplicada em `sgf_tempo_dev`, por caminho exclusivo com `sgf_dev_owner`, e sete concessões auditadas no tenant #1 / Tempo Lda #1 / SEGI #1: conta #1 `industrial_budgets.view/prepare`, `industrial_budget_comparisons.view/prepare`; conta #2 `industrial_budgets.view/validate`, `industrial_budget_comparisons.view`. Ver actualização de `docs/INDUSTRIAL_BUDGET_DELIVERY.md`. Preservadas 81 tabelas anteriores, acessos e instalação `120000`; seis tabelas novas vazias. Aplicação mantém `sgf_dev_app`; orçamento/conversão/oficinas/custos/recebimentos/emissão reais bloqueados, guardas SQL verificadas. Indicações anteriores de `110000`/sete concessões por aplicar são históricas. Sem utilização real ou publicação.
|
||||||
|
|
||||||
- Autorização específica posterior de 28/10/2026 executada: apenas `120000` aplicada em `sgf_tempo_dev`, por caminho exclusivo com `sgf_dev_owner`, e seis concessões auditadas no tenant #1 / Tempo Lda #1 / SEGI #1: conta #1 `workshop_billing.view/prepare/generate`; conta #2 `workshop_billing.view/review` e `workshop.view`. Ver actualização de `docs/WORKSHOP_BILLING_DELIVERY.md`. Preservadas 74 tabelas anteriores e acessos; sete tabelas novas vazias. Aplicação mantém `sgf_dev_app`; conversão/oficinas/custos/recebimentos/emissão reais bloqueados e guardas SQL verificadas. `110000` e sete concessões do orçamento permanecem pendentes; não aplicar por arrasto. Consulta de oficina da conta #2 não concede apontamento/verificação/supervisão. Indicações anteriores de `120000`/seis concessões por aplicar são históricas; sem utilização real ou publicação.
|
- Autorização específica posterior de 28/10/2026 executada: apenas `120000` aplicada em `sgf_tempo_dev`, por caminho exclusivo com `sgf_dev_owner`, e seis concessões auditadas no tenant #1 / Tempo Lda #1 / SEGI #1: conta #1 `workshop_billing.view/prepare/generate`; conta #2 `workshop_billing.view/review` e `workshop.view`. Ver actualização de `docs/WORKSHOP_BILLING_DELIVERY.md`. Preservadas 74 tabelas anteriores e acessos; sete tabelas novas vazias. Aplicação mantém `sgf_dev_app`; conversão/oficinas/custos/recebimentos/emissão reais bloqueados e guardas SQL verificadas. `110000` e sete concessões do orçamento permanecem pendentes; não aplicar por arrasto. Consulta de oficina da conta #2 não concede apontamento/verificação/supervisão. Indicações anteriores de `120000`/seis concessões por aplicar são históricas; sem utilização real ou publicação.
|
||||||
|
|
||||||
- Aceitação específica de 28/10/2026: utilizador aceitou `WORKSHOP-BILLING-DRAFT-SIM-v1` com limitação de capturas e autorizou checkpoint exclusivamente local, sem credenciais/dados privados. Ver `docs/WORKSHOP_BILLING_ACCEPTANCE.md`. Não transformar provas pendentes em realizadas; Edge não recuperado e capturas não recebidas permanecem limites. Substitui apenas a pendência de aceitação/encerramento deste ensaio. `120000`, seis concessões e utilização real continuam por autorizar; `110000` e sete concessões também pendentes. Sem aplicação, activação operacional ou publicação.
|
- Aceitação específica de 28/10/2026: utilizador aceitou `WORKSHOP-BILLING-DRAFT-SIM-v1` com limitação de capturas e autorizou checkpoint exclusivamente local, sem credenciais/dados privados. Ver `docs/WORKSHOP_BILLING_ACCEPTANCE.md`. Não transformar provas pendentes em realizadas; Edge não recuperado e capturas não recebidas permanecem limites. Substitui apenas a pendência de aceitação/encerramento deste ensaio. `120000`, seis concessões e utilização real continuam por autorizar; `110000` e sete concessões também pendentes. Sem aplicação, activação operacional ou publicação.
|
||||||
|
|||||||
@@ -121,7 +121,7 @@ O primeiro núcleo de cálculo de serviço e a política operacional de truncage
|
|||||||
O menu **Classificação contabilística**, disponível após actualizar a sessão com os acessos especificamente concedidos, permite preparar e submeter versões PGC-NIRF, validar/recusar sem editar e consultar classificação por data. Categoria e excepções são empresariais; operações e respectivos históricos continuam limitados às unidades autorizadas. As tabelas reais começam vazias, sem contas de movimento ou regras aprovadas por omissão. Consultar [utilização, provas e limites da classificação](docs/CATALOGUE_ACCOUNTING_DELIVERY.md).
|
O menu **Classificação contabilística**, disponível após actualizar a sessão com os acessos especificamente concedidos, permite preparar e submeter versões PGC-NIRF, validar/recusar sem editar e consultar classificação por data. Categoria e excepções são empresariais; operações e respectivos históricos continuam limitados às unidades autorizadas. As tabelas reais começam vazias, sem contas de movimento ou regras aprovadas por omissão. Consultar [utilização, provas e limites da classificação](docs/CATALOGUE_ACCOUNTING_DELIVERY.md).
|
||||||
## Ensaio isolado de custo directo
|
## Ensaio isolado de custo directo
|
||||||
|
|
||||||
Ligação sintética oficina → prestação/rascunho rastreável: [âmbito implementado, provas e limites](docs/WORKSHOP_BILLING_DELIVERY.md). Migração `120000` e seis concessões instaladas tecnicamente por autorização específica de 28/10/2026; conversão real continua bloqueada. `110000` e os direitos do orçamento permanecem separados e pendentes.
|
Ligação sintética oficina → prestação/rascunho rastreável: [âmbito implementado, provas e limites](docs/WORKSHOP_BILLING_DELIVERY.md). Migração `120000` e seis concessões instaladas tecnicamente por autorização específica de 28/10/2026; conversão real continua bloqueada. `110000` e sete direitos do orçamento foram instalados por autorização posterior separada, igualmente sem activação real.
|
||||||
|
|
||||||
Página inicial e menus agrupados: [alterações, verificações e limites visuais](docs/HOME_NAVIGATION_DELIVERY.md). Os atalhos dependem dos acessos existentes; não apresentam contagens de pendências ou indicadores financeiros simulados.
|
Página inicial e menus agrupados: [alterações, verificações e limites visuais](docs/HOME_NAVIGATION_DELIVERY.md). Os atalhos dependem dos acessos existentes; não apresentam contagens de pendências ou indicadores financeiros simulados.
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,17 @@
|
|||||||
# Orçamento versus realizado — ensaio isolado
|
# Orçamento versus realizado — ensaio isolado
|
||||||
|
|
||||||
|
## Aplicação técnica especificamente autorizada — 28/10/2026
|
||||||
|
|
||||||
|
Após indicação de que `110000` e as sete concessões concretamente apresentadas eram o passo técnico pendente, o utilizador confirmou «autorizo». Executado `scripts/sgf.ps1 php scripts/industrial-budget-dev-install.php --apply-confirmed-110000-and-seven-grants`, exclusivamente em `sgf_tempo_dev`/55432. Proprietário temporário `sgf_dev_owner` conferido sem superutilizador, criação de bases/papéis ou bypass RLS; aplicação permanece `sgf_dev_app`. Migração por caminho exclusivo `database/migrations/2026_10_28_110000_create_industrial_budgets.php`.
|
||||||
|
|
||||||
|
- 81 tabelas anteriores conferidas por contagem/impressão digital, sem exportar conteúdos de registos; dados, acessos e instalações anteriores preservados. `120000` permanece instalada, sem reaplicação.
|
||||||
|
- Apenas uma migração acrescentada; seis tabelas `ib_budgets`, `ib_decisions`, `ib_comparisons`, `ib_commands`, `ib_events`, `ib_outbox` vazias. Nenhum orçamento, lote, taxa, comparação ou operação real criado.
|
||||||
|
- Sete concessões e sete entradas de auditoria, no tenant #1 / Tempo Lda #1 / SEGI #1: conta #1 `industrial_budgets.view`, `industrial_budgets.prepare`, `industrial_budget_comparisons.view`, `industrial_budget_comparisons.prepare`; conta #2 `industrial_budgets.view`, `industrial_budgets.validate`, `industrial_budget_comparisons.view`. Contas, pertenças, contexto e direitos industriais de consulta existentes conferidos; sem direitos adicionais de gestão ou operação técnica.
|
||||||
|
- Instalação e concessões na mesma transacção, com conferência da preservação e dos bloqueios antes do commit. Após restaurar a ligação da aplicação, listagens das duas contas recusam operação normal, sem lotes/origens de conversão; guardas de proposta/decisão/comparação, conversão/preparação/revisão/geração, oficinas, custos directo/industrial, recebimentos e emissão recusam com 403.
|
||||||
|
- Guardas SQL industrial/oficinas/custo directo/recebimentos recusam desenvolvimento; a guarda industrial é usada por INSERT nas seis tabelas novas. Fontes funcionais e guardas não alteradas.
|
||||||
|
|
||||||
|
Sintaxe PHP aprovada; prova de preservação e bloqueios em `storage/app/private/industrial-budget-dev-install-proof.json`, exclusivamente local e sem credenciais/conteúdos dos registos. Não se repetiram testes que recriam a fixture manual aceite. Referências abaixo a `110000`/sete concessões pendentes são históricas. Aceitação `04870f0` e limitações de capturas mantidas; sem uso real, stock, lançamentos, facturação ou publicação. Alterações desta instalação ainda sem novo checkpoint.
|
||||||
|
|
||||||
**Aceitação posterior de 28/10/2026:** entrega aceite com a limitação das capturas documentada e checkpoint exclusivamente local autorizado. Ver [INDUSTRIAL_BUDGET_ACCEPTANCE.md](INDUSTRIAL_BUDGET_ACCEPTANCE.md). Referências abaixo à aceitação/checkpoint pendentes são históricas. Provas pendentes não se tornam realizadas; `110000`, sete concessões e utilização real continuam por autorizar.
|
**Aceitação posterior de 28/10/2026:** entrega aceite com a limitação das capturas documentada e checkpoint exclusivamente local autorizado. Ver [INDUSTRIAL_BUDGET_ACCEPTANCE.md](INDUSTRIAL_BUDGET_ACCEPTANCE.md). Referências abaixo à aceitação/checkpoint pendentes são históricas. Provas pendentes não se tornam realizadas; `110000`, sete concessões e utilização real continuam por autorizar.
|
||||||
|
|
||||||
28/10/2026, Africa/Johannesburg. `INDUSTRIAL-BUDGET-ACTUAL-SIM-v1`, secção 16 de [INDUSTRIAL_COST_ACCOUNTING_SCOPE.md](INDUSTRIAL_COST_ACCOUNTING_SCOPE.md). Preservados `cbdf2b4`, `4a94e8a` e alterações posteriores. **Sem aceitação presumida ou checkpoint de encerramento.** Nenhuma migração ou concessão nova em desenvolvimento.
|
28/10/2026, Africa/Johannesburg. `INDUSTRIAL-BUDGET-ACTUAL-SIM-v1`, secção 16 de [INDUSTRIAL_COST_ACCOUNTING_SCOPE.md](INDUSTRIAL_COST_ACCOUNTING_SCOPE.md). Preservados `cbdf2b4`, `4a94e8a` e alterações posteriores. **Sem aceitação presumida ou checkpoint de encerramento.** Nenhuma migração ou concessão nova em desenvolvimento.
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
# Oficina → rascunho — entrega técnica em verificação
|
# Oficina → rascunho — entrega técnica em verificação
|
||||||
|
|
||||||
|
**Actualização posterior:** `110000` e sete concessões do orçamento foram entretanto aplicadas por autorização específica separada em 28/10/2026, preservando `120000` e todos os bloqueios. Ver [registo de aplicação do orçamento](INDUSTRIAL_BUDGET_DELIVERY.md). As menções abaixo à sua instalação pendente são históricas; não decorreu desta aplicação qualquer utilização real.
|
||||||
|
|
||||||
## Aplicação técnica especificamente autorizada — 28/10/2026
|
## Aplicação técnica especificamente autorizada — 28/10/2026
|
||||||
|
|
||||||
Após apresentação da migração, destino e seis concessões exactas, o utilizador confirmou «autorizo». Executado `scripts/sgf.ps1 php scripts/workshop-billing-dev-install.php --apply-confirmed-120000-and-six-grants`. Apenas `2026_10_28_120000_create_workshop_billing_drafts.php` aplicada em `sgf_tempo_dev`/55432 por ligação temporária `sgf_dev_owner`, sem superutilizador, criação de bases/papéis ou bypass RLS. A aplicação mantém `sgf_dev_app`. Migração e concessões verificadas na mesma transacção de instalação; ligação de proprietário removida da configuração em memória no fim.
|
Após apresentação da migração, destino e seis concessões exactas, o utilizador confirmou «autorizo». Executado `scripts/sgf.ps1 php scripts/workshop-billing-dev-install.php --apply-confirmed-120000-and-six-grants`. Apenas `2026_10_28_120000_create_workshop_billing_drafts.php` aplicada em `sgf_tempo_dev`/55432 por ligação temporária `sgf_dev_owner`, sem superutilizador, criação de bases/papéis ou bypass RLS. A aplicação mantém `sgf_dev_app`. Migração e concessões verificadas na mesma transacção de instalação; ligação de proprietário removida da configuração em memória no fim.
|
||||||
|
|||||||
@@ -0,0 +1,83 @@
|
|||||||
|
<?php
|
||||||
|
// Only the specifically authorised 110000 and seven grants; preserve 120000 and all operational guards.
|
||||||
|
require __DIR__.'/../vendor/autoload.php';$app=require __DIR__.'/../bootstrap/app.php';$app->make(\Illuminate\Contracts\Console\Kernel::class)->bootstrap();
|
||||||
|
use Illuminate\Support\Facades\{DB,Artisan};
|
||||||
|
use App\Modules\Identity\Services\{LocalDatabaseGuard,Permissions,Audit};
|
||||||
|
use App\Modules\Workshop\{WorkshopBilling,WorkshopWorkflow,DirectCosts};
|
||||||
|
use App\Modules\Industry\{IndustrialCosts,IndustrialBudgets};
|
||||||
|
use App\Modules\Services\{ServiceReceivables,ServiceInvoicing};
|
||||||
|
use App\Shared\Context\CompanyContext;
|
||||||
|
function ensureIbInstall(bool $ok,string $why): void {if(!$ok)throw new RuntimeException($why);}
|
||||||
|
function ibFingerprint(string $table,?int $max=null): array {
|
||||||
|
ensureIbInstall((bool)preg_match('/^[a-z_]+$/D',$table),'Invalid table identifier.');
|
||||||
|
$where=$max===null?'':' WHERE id <= '.$max;
|
||||||
|
$row=DB::selectOne('SELECT count(*) AS n, md5(COALESCE(string_agg(row_to_json(t)::text,E\'\\n\' ORDER BY row_to_json(t)::text),\'\')) AS h FROM (SELECT * FROM "'.$table.'"'.$where.') t');
|
||||||
|
return [(int)$row->n,$row->h]; // Record contents and fingerprints are not exported.
|
||||||
|
}
|
||||||
|
ensureIbInstall(LocalDatabaseGuard::allows(),'Own SGF application connection required.');
|
||||||
|
ensureIbInstall($argv===[$argv[0],'--apply-confirmed-110000-and-seven-grants'],'Exact authorised operation required.');
|
||||||
|
$migration='2026_10_28_110000_create_industrial_budgets';
|
||||||
|
$preserved='2026_10_28_120000_create_workshop_billing_drafts';
|
||||||
|
ensureIbInstall(!DB::table('migrations')->where('migration',$migration)->exists(),'110000 already installed; review instead of replaying.');
|
||||||
|
ensureIbInstall(DB::table('migrations')->where('migration',$preserved)->exists(),'Expected 120000 installation missing.');
|
||||||
|
foreach(['2026_10_27_100000_create_industrial_cost_simulation','2026_10_27_080000_create_workshop_resource_records'] as $prerequisite)ensureIbInstall(DB::table('migrations')->where('migration',$prerequisite)->exists(),'Migration prerequisite missing.');
|
||||||
|
$newTables=['ib_budgets','ib_decisions','ib_comparisons','ib_commands','ib_events','ib_outbox'];
|
||||||
|
$tables=array_map(fn($r)=>$r->tablename,DB::select("SELECT tablename FROM pg_tables WHERE schemaname='public' ORDER BY tablename"));
|
||||||
|
ensureIbInstall(!array_intersect($tables,$newTables),'Unexpected existing conversion tables.');
|
||||||
|
$rights=[1=>['industrial_budgets.view','industrial_budgets.prepare','industrial_budget_comparisons.view','industrial_budget_comparisons.prepare'],2=>['industrial_budgets.view','industrial_budgets.validate','industrial_budget_comparisons.view']];
|
||||||
|
$checkScope=function()use($rights): void {
|
||||||
|
ensureIbInstall(DB::table('companies')->where(['id'=>1,'tenant_id'=>1,'name'=>'Tempo Lda'])->exists(),'Company differs.');
|
||||||
|
ensureIbInstall(DB::table('units')->where(['id'=>1,'tenant_id'=>1,'company_id'=>1,'name'=>'SEGI'])->exists(),'Unit differs.');
|
||||||
|
foreach($rights as $user=>$permissions){
|
||||||
|
ensureIbInstall(DB::table('users')->where('id',$user)->exists()&&DB::table('company_memberships')->where(['user_id'=>$user,'tenant_id'=>1,'company_id'=>1])->exists(),'Existing account/member required.');
|
||||||
|
foreach(['company.view'] as $permission)app(Permissions::class)->require($user,1,1,$permission);
|
||||||
|
app(Permissions::class)->require($user,1,1,'unit.view',1);
|
||||||
|
foreach($permissions as $permission)ensureIbInstall(!DB::table('permission_grants')->where(['user_id'=>$user,'tenant_id'=>1,'company_id'=>1,'unit_id'=>1,'permission'=>$permission])->exists(),'Proposed grant already present; review required.');
|
||||||
|
}
|
||||||
|
foreach([1,2] as $user)app(Permissions::class)->require($user,1,1,'industrial_costs.view',1);
|
||||||
|
ensureIbInstall(!DB::table('permission_grants')->where(fn($q)=>$q->where('permission','like','industrial_budgets.%')->orWhere('permission','like','industrial_budget_comparisons.%'))->exists(),'Unexpected conversion rights.');
|
||||||
|
};
|
||||||
|
$checkScope();$baseline=[];foreach($tables as $t)$baseline[$t]=ibFingerprint($t);
|
||||||
|
$max=[];foreach(['permission_grants','identity_audit'] as $t)$max[$t]=(int)DB::table($t)->max('id');
|
||||||
|
$ledger=DB::table('migrations')->orderBy('id')->get()->map(fn($r)=>(array)$r)->all();
|
||||||
|
$sources=[];foreach(['app/Modules/Industry/IndustrialBudgets.php','app/Modules/Workshop/WorkshopBilling.php','app/Modules/Workshop/WorkshopWorkflow.php','app/Modules/Workshop/DirectCosts.php','app/Modules/Industry/IndustrialCosts.php','app/Modules/Services/ServiceInvoicing.php','app/Modules/Services/ServiceReceivables.php','app/Modules/Services/ServiceWorkflow.php'] as $path)$sources[$path]=hash_file('sha256',base_path($path));
|
||||||
|
$secrets=json_decode(file_get_contents('C:/laragon/data/sgf-tempo/secrets/database.json'),true,32,JSON_THROW_ON_ERROR);
|
||||||
|
$owner=config('database.connections.'.config('database.default'));$owner['username']='sgf_dev_owner';$owner['password']=$secrets['dev_owner'];$owner['url']=null;
|
||||||
|
config(['database.connections.sgf_ib_install_owner'=>$owner]);unset($secrets,$owner);
|
||||||
|
$application=DB::getDefaultConnection();$grants=[];$denials=[];
|
||||||
|
$checkBlocks=function()use(&$denials): void {
|
||||||
|
foreach([1,2] as $actor){app(CompanyContext::class)->selectFor($actor,1,1,1);$list=app(IndustrialBudgets::class)->listing($actor);ensureIbInstall($list['blocked']&&$list['lots']===[],'Budget listing must remain blocked.');$conversion=app(WorkshopBilling::class)->listing($actor);ensureIbInstall($conversion['blocked']&&$conversion['orders']===[],'Conversion listing must remain blocked.');}
|
||||||
|
foreach(['budget','budget_propose','budget_decide','budget_compare','conversion','prepare','review','generate','workshop','direct_cost','industrial_cost','receivables','issuance'] as $entry){
|
||||||
|
try{match($entry){'budget'=>IndustrialBudgets::guard(),'budget_propose'=>app(IndustrialBudgets::class)->propose(0,1,[],'blocked-probe'),'budget_decide'=>app(IndustrialBudgets::class)->decide(0,2,[],'blocked-probe'),'budget_compare'=>app(IndustrialBudgets::class)->compare(0,1,[],'blocked-probe'),'conversion'=>WorkshopBilling::guard(),'prepare'=>app(WorkshopBilling::class)->prepare(0,1,[],'blocked-probe'),'review'=>app(WorkshopBilling::class)->review(0,2,[],'blocked-probe'),'generate'=>app(WorkshopBilling::class)->generate(0,1,[],'blocked-probe'),'workshop'=>WorkshopWorkflow::guard(),'direct_cost'=>DirectCosts::guard(),'industrial_cost'=>IndustrialCosts::guard(),'receivables'=>ServiceReceivables::guard(),'issuance'=>ServiceInvoicing::guard()};throw new RuntimeException('Operational guard did not refuse.');}
|
||||||
|
catch(\Symfony\Component\HttpKernel\Exception\HttpExceptionInterface $e){ensureIbInstall($e->getStatusCode()===403,'Expected 403.');$denials[$entry]=403;}
|
||||||
|
}
|
||||||
|
foreach(['ic','wo','dc','sr'] as $prefix){
|
||||||
|
try{DB::transaction(fn()=>DB::select('SELECT sgf_'.$prefix.'_environment()'));throw new RuntimeException('SQL environment guard allowed development.');}
|
||||||
|
catch(\Illuminate\Database\QueryException $e){ensureIbInstall(str_contains($e->getMessage(),'SGF_'.strtoupper($prefix).'_TEST_DATABASE_ONLY'),'Unexpected SQL guard refusal.');}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
try{
|
||||||
|
$connection=DB::connection('sgf_ib_install_owner');
|
||||||
|
$id=$connection->selectOne('SELECT current_database() AS db,current_user AS role,inet_server_port() AS port,rolsuper,rolcreatedb,rolcreaterole,rolbypassrls FROM pg_roles WHERE rolname=current_user');
|
||||||
|
ensureIbInstall($id->db==='sgf_tempo_dev'&&$id->role==='sgf_dev_owner'&&(int)$id->port===55432&&!$id->rolsuper&&!$id->rolcreatedb&&!$id->rolcreaterole&&!$id->rolbypassrls,'Unexpected owner/destination.');
|
||||||
|
DB::setDefaultConnection('sgf_ib_install_owner');
|
||||||
|
$connection->transaction(function()use($migration,$preserved,$checkScope,$rights,$baseline,$max,$ledger,$newTables,$checkBlocks,&$grants){
|
||||||
|
DB::table('companies')->where('id',1)->lockForUpdate()->firstOrFail();$checkScope();
|
||||||
|
$code=Artisan::call('migrate',['--database'=>'sgf_ib_install_owner','--path'=>'database/migrations/'.$migration.'.php','--force'=>true,'--no-interaction'=>true]);ensureIbInstall($code===0,'Targeted migration failed.');
|
||||||
|
foreach($rights as $user=>$permissions)foreach($permissions as $permission){$g=['user_id'=>$user,'tenant_id'=>1,'company_id'=>1,'unit_id'=>1,'permission'=>$permission];DB::table('permission_grants')->insert($g+['created_at'=>now(),'updated_at'=>now()]);Audit::record('industrial_budgets.initial_grant',null,1,1,1,subject:$user,details:['permission'=>$permission,'reason'=>'Seven specifically authorised grants; operational use remains blocked.']);$grants[]=$g;}
|
||||||
|
foreach($baseline as $t=>$fp)if($t!=='migrations')ensureIbInstall(ibFingerprint($t,$max[$t]??null)===$fp,'Existing records changed: '.$t);
|
||||||
|
ensureIbInstall(DB::table('permission_grants')->where('id','>',$max['permission_grants'])->count()===7,'Exactly seven new grants required.');
|
||||||
|
ensureIbInstall(DB::table('identity_audit')->where('id','>',$max['identity_audit'])->count()===7&&DB::table('identity_audit')->where('id','>',$max['identity_audit'])->where('action','industrial_budgets.initial_grant')->count()===7,'Exactly seven audited grants required.');
|
||||||
|
$actual=DB::table('permission_grants')->where('id','>',$max['permission_grants'])->get(['user_id','tenant_id','company_id','unit_id','permission'])->map(fn($r)=>(array)$r)->all();$sort=fn($a,$b)=>[$a['user_id'],$a['permission']]<=>[$b['user_id'],$b['permission']];usort($actual,$sort);$expected=$grants;usort($expected,$sort);ensureIbInstall($actual===$expected,'Grant scope differs.');
|
||||||
|
$after=DB::table('migrations')->orderBy('id')->get()->map(fn($r)=>(array)$r)->all();ensureIbInstall(count($after)===count($ledger)+1&&array_slice($after,0,count($ledger))===$ledger&&end($after)['migration']===$migration,'Unexpected migration delta.');
|
||||||
|
ensureIbInstall(DB::table('migrations')->where('migration',$preserved)->exists(),'120000 must remain installed.');
|
||||||
|
foreach($newTables as $t)ensureIbInstall(DB::table($t)->count()===0,'New table not empty.');
|
||||||
|
$checkBlocks();
|
||||||
|
});
|
||||||
|
}finally{DB::setDefaultConnection($application);DB::purge('sgf_ib_install_owner');config(['database.connections.sgf_ib_install_owner'=>null]);}
|
||||||
|
ensureIbInstall(LocalDatabaseGuard::allows(),'Application must remain sgf_dev_app.');$checkBlocks();
|
||||||
|
foreach($newTables as $t)ensureIbInstall(DB::table($t)->count()===0,'New table not empty after installation.');
|
||||||
|
foreach($sources as $path=>$hash)ensureIbInstall(hash_file('sha256',base_path($path))===$hash,'Functional source changed.');
|
||||||
|
$proof=['date'=>'2026-10-28','database'=>'sgf_tempo_dev','migration_applied'=>$migration,'only_one_migration_added'=>true,'migration_120000_preserved'=>true,'preexisting_tables_checked'=>count($baseline),'prior_records_and_accesses_preserved'=>true,'new_empty_tables'=>$newTables,'new_grants'=>$grants,'audited_new_grants'=>7,'application_role'=>'sgf_dev_app','budget_and_conversion_listings_blocked'=>true,'entry_denials'=>$denials,'sql_environment_guards_refused'=>true,'functional_sources_unchanged'=>true,'real_operations_created'=>false];
|
||||||
|
file_put_contents(storage_path('app/private/industrial-budget-dev-install-proof.json'),json_encode($proof,JSON_PRETTY_PRINT|JSON_THROW_ON_ERROR));
|
||||||
|
echo 'Applied only 110000 and seven audited grants; '.count($baseline)." previous tables preserved, six new tables empty, 120000 preserved, operational guards verified.\n";
|
||||||
Reference in New Issue
Block a user