Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions docs/execucao/BACKLOG_EXECUTAVEL.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ Estados: APROVADO (escopo autorizado), EM_EXECUCAO, VALIDADO (com evidência), B
| Ordem | Item | Estado inicial | Aceite |
|---|---|---|---|
| 1 | P0.1-A inventário e gate estático de governança das migrations | VALIDADO | 185 SQLs / 175 manifesto / 171 auto / 171 baseline / 10 órfãs; gate artefatos PASS |
| 2 | P0.1-B convergência em PostgreSQL 16 vazio/legado | EM_EXECUCAO | Vazio+reapply+one-shot+equivalência PASS (Podman); upgrade legado ainda BLOCKED |
| 2 | P0.1-B convergência em PostgreSQL 16 vazio/legado | EM_EXECUCAO | Aplicador PowerShell agora executa probes nomeados transacionalmente e revalida estado final na reaplicação; vazio+reapply+one-shot+equivalência têm evidência anterior, upgrade legado e reconfirmação desta alteração ainda BLOCKED |
| 3 | P0.2 build Release locked e suites realmente executadas | VALIDADO | build `-warnaserror` + testes 389/123/102 PASS em 2026-09-10 |
| 4 | P0.3 ApiExplorer/Swagger/OpenAPI/rotas | VALIDADO | Swagger HTTP 200 (3 445 457 bytes); 630 rotas sem conflito direto |
| 5 | P0.4 login, sessões, cache, revogação e dois tenants | EM_EXECUCAO | Login/CPF/CNPJ/MinhaCentral/logout + 2 tenants hero PASS; revogação/suspenso/legado pendentes |
Expand All @@ -17,4 +17,4 @@ Estados: APROVADO (escopo autorizado), EM_EXECUCAO, VALIDADO (com evidência), B
| 9 | P4 demais módulos na ordem do contrato | AGUARDA_GATE | Auditoria por fluxo, sem telas decorativas |
| 10 | GED | AGUARDA_GATE | Último módulo; anteriores sem PARCIAL/ESTRUTURA pendente, salvo adiamento formal |

Próximo item exato: upgrade legado formal em PG16 + evidências de revogação/tenant suspenso/acesso cruzado API; só então Gate B (SaaS). Gates C–D e GED não avançam.
Próximo item exato: validar sintaxe do aplicador com `pwsh -NoProfile -File scripts/apply-migrations-manifest.ps1 -ValidateOnly`, executar upgrade legado formal em PG16 e então obter evidências de revogação/tenant suspenso/acesso cruzado API; só depois Gate B (SaaS). Gates C–D e GED não avançam.
5 changes: 2 additions & 3 deletions docs/execucao/STATUS_REAL_MODULOS.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Status real dos módulos

Corte: 2026-09-10 (recalc remoto); origin/main `dc7c1ac23f0c4ee95d7362e149157f2bec8284dc`; branch de trabalho `codex/rc51-02c-foundation-saas-multimodulo`.
Corte: 2026-09-10 (RC51.02D); checkout `work` em `86a8cfcb3803221735426bf937924606c1c201ba`, sem remoto/upstream configurado nesta execução.
Inventário documental: docs/inventario-modulos-sigov.md, docs/execucao/rc50_67_plano_homologacao_integrada_real.md e docs/roadmap/saas-industria-auditoria.md. Classificação conservadora: os 15 requisitos do contrato não foram demonstrados conjuntamente em runtime.

| Domínio/módulos existentes | Status | Evidência existente e lacuna de aprovação |
Expand All @@ -26,5 +26,4 @@ Inventário documental: docs/inventario-modulos-sigov.md, docs/execucao/rc50_67_
| Legislativo, transparência, diário oficial, convênios, trânsito, defesa | PARCIAL | Inventários e controllers existentes; verificar cada fluxo após P0–P3 |
| GED e assinaturas | PARCIAL | Estrutura histórica existente; catálogo rebaixado para não promover GED na RC51.00; implementação bloqueada até última fase |

Nenhum módulo foi promovido a FUNCIONAL, HOMOLOGADO ou PRODUCAO. RC51.02C (recalc) evidenciou apply/reapply/one-shot/equivalência, Swagger e autenticação HTTP (login/MinhaCentral/logout, CPF/CNPJ, dois tenants no hero) em PG16 via Podman; upgrade legado formal e isolamento API profundo seguem pendentes. Indústria Core permanece PARCIAL (telas genéricas). Dual catálogo Commercial/SaaS permanece. GED continua por último.

Nenhum módulo foi promovido a FUNCIONAL, HOMOLOGADO ou PRODUCAO. RC51.02D tornou determinística no aplicador PowerShell a execução dos probes separados de Compras, Educação/Saúde e SaaS, inclusive na reaplicação, mas não produziu nova evidência runtime por ausência de `pwsh`, `.NET` e PostgreSQL 16. A evidência anterior da RC51.02C permanece histórica; upgrade legado formal e isolamento API profundo seguem pendentes. Indústria Core permanece PARCIAL (telas genéricas). Dual catálogo Commercial/SaaS permanece. GED continua por último.
12 changes: 12 additions & 0 deletions docs/execucao/ULTIMA_EXECUCAO.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
# Última execução

Data: 2026-09-10. RC51.02D (validação determinística das pós-condições). Estado: PARCIAL / BLOCKED.

- Branch observada: `work`; HEAD inicial `86a8cfcb3803221735426bf937924606c1c201ba`; working tree inicialmente limpa; branch sem upstream e checkout sem remoto configurado, portanto a comparação atualizada com `origin/main` ficou BLOCKED sem alterar o trabalho local.
- As correções forward-only e os probes separados das migrations `20260802210000`, `20260819120000` e `20260908120000` já existiam no HEAD inicial. A lacuna encontrada estava no aplicador PowerShell: ele executava apenas `postConditionSql`, ignorava `postConditionProbes` e, na reaplicação, pulava toda validação das versões presentes no ledger.
- Implementado: probes nomeados agora participam da mesma transação antes do registro no ledger. Ao final, o aplicador revalida a pós-condição booleana e cada probe de todas as migrations automáticas, inclusive quando o ledger já estava completo. Falhas preservam o nome da versão/invariante e não são convertidas em sucesso.
- Compras permanece com o rename conservador do bootstrap 070, contrato empresarial UUID e contrato governamental bigint separados; Educação/Saúde preserva template global anulável sem conceder perfil; SaaS preserva nome/disponibilidade comerciais administráveis e valida tabela, tipos, constraint, funções e triggers separadamente.
- **BLOCKED:** restore/build/test e parser PowerShell não executados porque `dotnet` e `pwsh` não existem no ambiente desta execução.
- **BLOCKED:** PostgreSQL 16 vazio, reaplicação, upgrade sanitizado, equivalência, Swagger, login/MinhaCentral/logout, isolamento e validação visual não executados porque `psql`, runtime e navegador não estão disponíveis/configurados.
- Próximo comando exato: `pwsh -NoProfile -File scripts/apply-migrations-manifest.ps1 -ValidateOnly`; em seguida, com PostgreSQL 16 descartável configurado, executar aplicação vazia, reaplicação e upgrade sanitizado antes de liberar Gate B.

---

Data: 2026-09-10. RC51.02C (recalc + remoto). Estado: PARCIAL / BLOCKED. Gate A quase fechado em runtime Podman PG16; Gate B–D não iniciados.

## Preflight recalculado
Expand Down
55 changes: 51 additions & 4 deletions scripts/apply-migrations-manifest.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -124,11 +124,11 @@ foreach ($entry in $manifest.migrations) {
$psqlArgs += @('-f', $file)
$tempSqlFiles = @()
try {
$tempDir = Join-Path $root '.local/tmp'
New-Item -ItemType Directory -Force -Path $tempDir | Out-Null
$postConditionProperty = $entry.PSObject.Properties['postConditionSql']
if ($null -ne $postConditionProperty -and -not [string]::IsNullOrWhiteSpace([string]$postConditionProperty.Value)) {
$condition = [string]$postConditionProperty.Value
$tempDir = Join-Path $root '.local/tmp'
New-Item -ItemType Directory -Force -Path $tempDir | Out-Null
$postFile = Join-Path $tempDir ("sigov-post-" + [guid]::NewGuid().ToString('N') + '.sql')
$postSql = @(
'do $sigov_post$'
Expand All @@ -143,8 +143,30 @@ foreach ($entry in $manifest.migrations) {
$tempSqlFiles += $postFile
$psqlArgs += @('-f', $postFile)
}
$tempDir = Join-Path $root '.local/tmp'
New-Item -ItemType Directory -Force -Path $tempDir | Out-Null
foreach ($probe in (Get-OptionalArray $entry 'postConditionProbes')) {
$probeName = [string]$probe.name
$probeSql = ([string]$probe.sql).Trim().TrimEnd(';')
if ([string]::IsNullOrWhiteSpace($probeName) -or [string]::IsNullOrWhiteSpace($probeSql)) {
throw "postConditionProbe sem nome ou SQL para $versionLiteral"
}

$probeNameLiteral = $probeName.Replace("'", "''")
$probeFile = Join-Path $tempDir ("sigov-probe-" + [guid]::NewGuid().ToString('N') + '.sql')
$probeScript = @(
'do $sigov_probe$'
'declare failure_message text;'
'begin'
" select result into failure_message from ($probeSql) as probe_result(result);"
" if nullif(btrim(failure_message), '') is not null then"
" raise exception using message = 'postConditionProbe reprovada para $versionLiteral [$probeNameLiteral]: ' || failure_message;"
' end if;'
'end'
'$sigov_probe$;'
) -join "`n"
[System.IO.File]::WriteAllText($probeFile, $probeScript + "`n")
$tempSqlFiles += $probeFile
$psqlArgs += @('-f', $probeFile)
}
$registrationFile = Join-Path $tempDir ("sigov-reg-" + [guid]::NewGuid().ToString('N') + '.sql')
[System.IO.File]::WriteAllText($registrationFile, $registrationSql + "`n")
$tempSqlFiles += $registrationFile
Expand All @@ -167,4 +189,29 @@ if ($canExecute) {
foreach ($compatibility in (Get-OptionalArray $manifest 'compatibilityAfterAll')) {
Invoke-SqlFile -Path (Resolve-Compatibility $compatibility) -Stage 'POST_MIGRATION_COMPATIBILITY'
}

# Revalida o estado final inclusive na reaplicação, quando todas as versões já
# constam do ledger. Probes nomeados retornam NULL em sucesso e uma mensagem
# diagnóstica em falha; não são substitutos da pós-condição booleana.
foreach ($entry in $manifest.migrations) {
if ($entry.applyAutomatically -ne $true) { continue }
$versionKey = [string]$entry.version
$baseArgs = @('-X', '-q', '-h', $HostName, '-p', $Port, '-U', $User, '-d', $Database, '-v', 'ON_ERROR_STOP=1', '-At')
$postConditionProperty = $entry.PSObject.Properties['postConditionSql']
if ($null -ne $postConditionProperty -and -not [string]::IsNullOrWhiteSpace([string]$postConditionProperty.Value)) {
$conditionResult = & $PsqlPath @baseArgs -c ([string]$postConditionProperty.Value)
if ($LASTEXITCODE -ne 0 -or [string]$conditionResult -notmatch '^(?i:t|true|1)$') {
throw "postConditionSql final reprovada para $versionKey"
}
}
foreach ($probe in (Get-OptionalArray $entry 'postConditionProbes')) {
$probeName = [string]$probe.name
$probeResult = & $PsqlPath @baseArgs -c ([string]$probe.sql)
if ($LASTEXITCODE -ne 0) { throw "postConditionProbe final não executou para $versionKey [$probeName]" }
$failure = (@($probeResult) -join "`n").Trim()
if (-not [string]::IsNullOrWhiteSpace($failure)) {
throw "postConditionProbe final reprovada para $versionKey [$probeName]: $failure"
}
}
}
}
15 changes: 15 additions & 0 deletions tests/Sigov.IntegrationTests/DatabaseMigrationRegressionTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,21 @@ public void Correcao_Deve_Ser_ForwardOnly_Idempotente_E_Preservar_Suspensao_Come
sql.Should().NotContain("create table if not exists sigov.compras_fatura");
}

[Fact]
public void Aplicador_PowerShell_Deve_Executar_Probes_Nomeados_Antes_De_Registrar_Ledger()
{
var script = File.ReadAllText(Path.Combine(Root, "scripts", "apply-migrations-manifest.ps1"));
var probes = script.IndexOf("foreach ($probe in (Get-OptionalArray $entry 'postConditionProbes'))", StringComparison.Ordinal);
var registration = script.IndexOf("$psqlArgs += @('-f', $registrationFile)", StringComparison.Ordinal);

probes.Should().BeGreaterThan(0);
probes.Should().BeLessThan(registration, "probes reprovados devem abortar a transação antes do registro no ledger");
script.Should().Contain("nullif(btrim(failure_message), '') is not null");
script.Should().Contain("postConditionProbe reprovada");
script.Should().Contain("postConditionSql final reprovada");
script.Should().Contain("postConditionProbe final reprovada");
}

private static string ReadAllMigrations() => string.Join('\n', Directory.GetFiles(MigrationsPath, "*.sql", SearchOption.TopDirectoryOnly).OrderBy(static file => file, StringComparer.OrdinalIgnoreCase).Select(File.ReadAllText));

private static string ReadBaselineMigrations()
Expand Down
Loading