Files
SGF/docs/SGF_SETTLEMENT_READ_ISOLATION_DELIVERY.md
2026-11-04 09:37:20 +02:00

52 lines
7.8 KiB
Markdown

# Consulta de liquidação SGF separada dos bloqueios de escrita
02/11/2026 — `SGF-SETTLEMENT-READ-ISOLATION-SIM-v1`. Continuação local sintética do [histórico paginado](SGF_SETTLEMENT_PAGED_READ_DELIVERY.md). Remove da consulta paginada SGF os bloqueios de escrita da empresa/utilizador; preserva a autoridade, os bloqueios e a conferência actual dos comandos.
## Implementação e contrato
O núcleo aceita uma autorização opcional e específica para a leitura paginada de pagamentos. O adaptador SGF fornece a mesma verificação existente de actor autenticado, contexto exacto, pessoa e direitos `view/payments_view`, usando o ramo sem bloqueio. Não se criou uma concessão paralela nem se concederam direitos novos.
`SupplierSettlements::listingPage()` usa esse callback apenas na consulta. `command()` conserva o callback original de escrita; `listing()` e construtores sem o argumento novo conservam também a autorização anterior. O callback de leitura nunca autoriza uma decisão. O pacote instalado da composição nativa não foi substituído ou activado, e essa composição não optou automaticamente pelo novo contrato.
Quando é dona da transacção, a consulta paginada inicia `REPEATABLE READ READ ONLY`. O controlador SGF inicia igualmente uma única transacção desse tipo para a leitura completa de pagamentos, posições documentais, propostas exactas e referências. Todas essas listas partilham o mesmo instantâneo do pedido. Uma leitura dentro de uma transacção já existente participa nela; não tenta mudar o isolamento depois de já haver consultas. O percurso HTTP efectivo foi verificado como transacção própria só de leitura.
Não se alteraram os cálculos de principal, afectações, reversões ou saldo. As confirmações continuam a obter os bloqueios e a conferir os factos/versões/ciclo actuais. A identidade capturada na construção do motor é comparada novamente na consulta; direitos revogados, pessoa alterada ou actor trocado não são herdados da construção anterior.
## Concorrência efectivamente observada
Reutilizada a base sintética própria da entrega anterior, com 1.000 pagamentos, sem reset ou novas operações persistentes. Uma transacção principal bloqueou a linha de `companies` e preparou/confirmou, sem commit, uma reversão adicional pelos comandos comuns. Dentro dessa transacção, o montante por afectar passaria de 0,41 para 0,42 MZN.
Três processos PHP/ligação independentes exercitaram os percursos:
| Percurso | Enquanto o escritor mantém o bloqueio | Depois da libertação |
|---|---|---|
| Consulta paginada pelo controlador SGF | Termina em **357,581 ms**, sem `FOR UPDATE`, com `repeatable read/read_only=on`; vê 0,41 MZN e os nove eventos confirmados | Nenhuma alteração de dados |
| Consulta integral anterior, pela mesma autorização de escrita | Aguarda em `companies FOR UPDATE` | Conclui com 0,41 MZN; conserva os dois bloqueios de escrita anteriores |
| Confirmação de proposta sintética de afectação | Aguarda em `companies FOR UPDATE` | Revalida e conclui; a repetição da mesma chave recupera a mesma decisão, com exactamente uma decisão e uma afectação para o destino |
`pg_blocking_pids` e `pg_stat_activity` identificaram a cadeia até à transacção principal. Um processo esperava no `transactionid`; o outro podia esperar no `tuple`, atrás do primeiro concorrente. A ordem variou com a chegada dos processos. O diagnóstico inicial exigia incorrectamente que ambos tivessem o pai como bloqueador directo; a prova final segue também a ligação indirecta da fila, sem confundir essa espera com outro recurso ou outra autorização.
A consulta nova terminou enquanto **ambos os outros processos ainda estavam bloqueados**. Não observou a reversão por confirmar. O pai libertou o bloqueio por rollback; a confirmação posterior decorreu dentro de outra transacção externa, igualmente revertida depois de conferir o resultado e a repetição. Assim, a proposta sintética de afectação original mantém-se pendente e não foi efectuada qualquer decisão de pagamento histórico importado.
Os tempos totais dos processos antigos incluem a espera, e a consulta integral lê um universo diferente do foco paginado. **Não são um comparativo controlado de velocidade por página**, throughput ou capacidade. O resultado demonstrado é a independência da consulta perante esse bloqueio de linha, com escrita ainda serializada e revalidada.
## Provas dirigidas e recuperação
- Quatro cenários novos, **23 asserções**: transacção própria coerente/só de leitura; ausência de `FOR UPDATE`; modo de leitura não persiste na ligação; contrato antigo mantém os dois bloqueios; callback de leitura não autoriza comandos; direitos/pessoa/actor alterados recusados.
- Reutilizados os SHA-256 das quatro janelas de 25/100 e da posição original da entrega anterior. Igualdade confirmada; os benchmarks anteriores não foram repetidos. Não se acrescentam novas medições de memória, índices ou volumes nesta entrega.
- Tentativa injectada de inserir um evento dentro da consulta: PostgreSQL recusa com `25006`, a transacção é desfeita e a leitura seguinte recupera normalmente. Nenhum evento foi gravado.
- **11 verificações HTTP reais**, dirigidas à mudança: ausência de autenticação401, JSON e HTML com isolamento/só-leitura e zero `FOR UPDATE`, posição original, contexto obsoleto409, foco indevido403, confirmação recusada ao leitor403, CSRF419 e `no-store`. A instrumentação é exclusivamente do router QA privado. Servidor loopback8047 encerrado; não houve navegador.
- Pós-ensaio só de leitura confirmou o fingerprint financeiro integral anterior: fontes, propostas, obrigações, pagamentos, decisões, afectações, reversões, eventos, comandos e direitos iguais. A decisão da proposta pendente continua ausente. Sequências podem avançar pelas inserções revertidas; não foram repostas para ocultar o ensaio.
Manifesto: [resultados, condições e hashes](proofs/sgf-settlement-read-isolation-20261102.json). Inclui conferência dos hashes de **todos os artefactos privados registados na prova anterior**, sem a sobrescrever. Execuções diagnósticas não são contadas como aprovadas. A comparação inicial entre posições foi corrigida para comparar os valores serializados, em vez da identidade de objectos PHP distintos; o cálculo não mudou.
Reprodução dirigida com PHP fixado: `scripts/payable-history-sgf-proof.php <settings QA privado> settlement-read-race`, `settlement-read-cases` ou `settlement-read-post`. Cada prova concluída é preservada, sem sobrescrita automática. HTTP: `scripts/settlement-read-http.mjs <tag>`. Consolidação sem repetir testes: `scripts/summarize-settlement-read.mjs <tag>`. Guardas exigem a base/role próprias do cluster55439; credenciais, sessões, entradas e logs permanecem privados.
## Limites preservados
Os direitos e os factos são conferidos no instantâneo de cada pedido. Uma revogação que ocorra depois desse instantâneo será observada pelos pedidos seguintes; não há fotografia congelada entre páginas visitadas por uma pessoa. As decisões continuam a conferir o estado actual no seu percurso de escrita.
Leitura normal continua sujeita aos recursos e bloqueios gerais da base, incluindo DDL; não se garante ausência absoluta de espera. Não foi medida carga sustentada, contenção entre muitas empresas ou capacidade de implantação. A prova não altera o conjunto de medições anteriores de documentos ou pagamentos nem autoriza instalar índices.
Sem novas rotas operacionais, direitos, migrações no destino, activação de Compras, pagamentos reais, fornecedor histórico SGF vivo, cutover financeiro, reconciliação, contabilidade, publicação ou checkpoint. Seis registos protegidos, cache bloqueada, demonstrações e trabalho alheio intactos. Revisão visual e implantação permanecem pendências separadas.