This commit is contained in:
2026-11-02 20:29:34 +02:00
parent 340f3bb5fa
commit fcf31e8d48
181 changed files with 33383 additions and 51 deletions
+2
View File
@@ -4,6 +4,8 @@ Incremento local posterior: [fila administrativa de conferência](MODULE_ASSOCIA
Fila aceite em 02/11/2026, com autorização de checkpoint local de código funcional/testes/documentação; ver [aceitação](MODULE_ASSOCIATION_QUEUE_ACCEPTANCE.md). Revisão visual, carga de implantação, seis registos sem associação e cache bloqueada permanecem separados e preservados.
Conferência posterior das associações em 02/11/2026: [inventário e proposta de tratamento](MODULE_ASSOCIATIONS_REVIEW.md). Cinco registos pendentes na instalação local e um cliente sintético na demonstração 8039, todos preservados sem associação. Nenhuma atribuição automática ou decisão de módulo executada; revisão humana, volume/paginação e revisão visual continuam separados.
**Aceitação técnica expressa em 02/11/2026**, registada no [relatório de entrega](MODULAR_NAVIGATION_DELIVERY.md), com autorização de checkpoint exclusivamente local e limitado à entrega. Revisão visual, associações antigas pendentes e volume/paginação permanecem separados. Não autoriza publicação, direitos públicos novos ou activação de candidatas; Compras mantém-se em **0.1.1**.
Actualização de 01/11/2026 à [entrega inicial](MODULAR_NAVIGATION_DELIVERY.md). Concluídas as duas frentes técnicas: regressão da suite existente e configuração de perfis sintéticos num ambiente de desenvolvimento separado. A [revisão visual](MODULAR_NAVIGATION_VISUAL_REVIEW.md) continua pendente e separada.
+59
View File
@@ -0,0 +1,59 @@
# Conferência das associações pendentes de módulos
02/11/2026. Levantamento e proposta de tratamento após a aceitação técnica da navegação modular. Não executa decisões de associação, migrações, concessões ou implantação. Não substitui a revisão humana dos dados, a avaliação de volume ou a revisão visual.
## Resultado conferido
Consultas PostgreSQL em transacção `REPEATABLE READ, READ ONLY`, com identidade física conferida, timeout de 15 segundos por instrução e rollback final. Sem autenticação HTTP, navegador ou escrita em dados. Os relatórios contêm identificadores e versões, sem nomes de pessoas/clientes, credenciais, descrições ou valores de documentos.
| Destino | Área | Registos sem associação | Identificadores / versão |
| --- | --- | --- | --- |
| SGF local, `sgf_tempo_dev`, porta 55432 | Clientes | 1 | #1 / v1 |
| Mesmo destino | Serviços | 2 | #1 / v1; #2 / v1 |
| Mesmo destino, unidade #1 | Prestações em rascunho | 1 | #1 / v1 |
| Mesmo destino, unidade #1 | Rascunhos de facturação | 1 | #1 / v1 |
| Demonstração 8039, base `sgf_modules_dev_2576427d1939`, porta 55439 | Clientes | 1 sintético | #1 / v1 |
Todos pertencem ao contexto tenant #1 / empresa #1 **do respectivo destino**, que não torna as duas empresas ou os dois clientes no mesmo registo. As outras três áreas da demonstração estão vazias. Não há registos actualmente associados nem casos com todas as associações retiradas nestes dois inventários. A amostra de até 100 pendentes por área cobre integralmente os resultados encontrados.
«Nunca associado» significa ausência de eventos explícitos para o registo; não prova a idade, a intenção comercial ou o módulo correcto. Não se inferiu destino pelo nome da tabela, autor ou dependências. O âmbito deste inventário são as quatro áreas partilhadas de `ModuleRecords::AREAS`; não constitui inventário de toda a instalação nem de outras demonstrações.
Evidências: [instalação local](proofs/module-associations-installed-20261102.json) e [demonstração](proofs/module-associations-demo-20261102.json). A consulta usa o último evento por empresa/área/registo/módulo, distinguindo ausência de associação de retirada explícita. Não é uma listagem operacional nem uma nova API pública.
## Dependências confirmadas na instalação local
- Prestação #1/v1 referencia cliente #1 e serviço #2.
- Rascunho de facturação #1/v1 referencia cliente #1, serviço #2 e prestação de origem #1, fotografia de origem v1.
- Serviço #1 não é referenciado pelos dois rascunhos inventariados. Isto não prova ausência de utilização noutras capacidades.
Estas referências definem uma ordem útil de conferência, sem propagar associações: cliente/serviço #2 → prestação → rascunho de facturação. O serviço #1 deve ser revisto separadamente. Não alterar fotografias, versões, origens, histórico ou responsabilidade financeira para tornar os registos visíveis.
## Tratamento proposto
1. Manter todos os seis registos sem associação e sinalizados enquanto não houver fundamento explícito para cada destino. O cliente sintético 8039 permanece exemplo de pendência; não o converter automaticamente num exemplo operacional.
2. Preparar uma ficha por registo com destino físico, tenant/empresa/unidade, área, ID, versão consultada, dependências, finalidade pretendida, módulo(s) solicitado(s), responsável pela decisão e fundamento. Estado inicial: **por decidir**. Uma mesma ficha não decide as dependências nem outros destinos.
3. A pessoa responsável pelo cadastro confirma a finalidade e as dependências. A autoridade com `access.manage`, consulta e edição originais, e acesso ao módulo de destino, regista a decisão pelo percurso existente **Opções gerais → Associações de módulos**. O sistema actual não impõe uma segunda aprovação: qualquer exigência futura de dupla decisão necessita de desenho próprio, não se declara entregue.
4. Antes de aplicar, reler a versão e o âmbito. Versão alterada exige nova conferência; a API existente recusa a versão desactualizada com 409. A implementação actual serializa decisões por empresa; não se afirma aqui que substitui todos os controlos de concorrência sobre edições do registo.
5. Registar cada associação autorizada como evento novo, com motivo, preservando o original. Conferir a visibilidade no módulo escolhido, os direitos originais e a ausência de exposição indevida noutros módulos/empresas/unidades. Não conceder direitos para fazer uma associação funcionar.
6. Se o destino estiver errado, retirar por novo evento e fundamentar; nunca apagar auditoria. Uma retirada explícita deve continuar distinta de «nunca associado», para evitar reatribuição automática posterior.
Esta proposta não determina Comercial ou qualquer outro destino para os cinco registos locais. A autorização desta passagem é de conferência/proposta; nenhuma decisão foi executada.
## Próximo incremento técnico delimitado
Propor uma fila administrativa de conferência com filtros por área, unidade e estado (sem eventos / associado / todas as ligações retiradas), paginação no servidor, ordenação estável e resumo das dependências por registo. Sem selecção de módulo por defeito, associação em lote, propagação de vínculos ou novos direitos. O inventário CLI agora disponível é apenas diagnóstico administrativo e não substitui essa fila.
A consulta administrativa actual carrega todos os registos autorizados e consulta o histórico por registo; é um padrão de consultas proporcional ao número de registos. Os volumes observados são pequenos e não validam escala. Antes de implantação, medir em base sintética separada o número de consultas, tempo, memória e plano de execução, incluindo histórico de retiradas/reposições. Só então propor tamanho de página, consulta conjunta de eventos e eventuais índices. Não aplicar índices ou schema por consequência deste levantamento.
Revisão visual e recargas das páginas autónomas permanecem pendentes, sem repetir a via de navegador bloqueada. As provas aceites da navegação são reutilizadas; não houve alteração de interface ou execução da suite destrutiva.
## Repetição controlada do inventário
Pelo PHP 8.4.27 fixado para o projecto:
```text
php scripts/module-associations-inventory.php installed
php scripts/module-associations-inventory.php demo
```
O script só aceita estes destinos fixos e recusa divergência de base/role/porta ou transacção que não seja de leitura. A sua execução pertence ao operador local autorizado; não expor como endpoint nem publicar relatórios de cliente. Não arranca/paralisa serviços, muda configuração ou percorre outras bases. Não foi criado checkpoint ou efectuada publicação nesta passagem.
@@ -0,0 +1,70 @@
# Fila de associações — leituras concorrentes e confirmação
Continuação de 02/11/2026: a [consolidação de carga e libertação dos bloqueios](MODULE_ASSOCIATION_LOAD_CONSOLIDATION.md) identifica a espera no `FOR UPDATE` da empresa e verifica quatro resultados após commit/rollback, sem duplicação. As 440 leituras deste relatório foram preservadas e não repetidas. A limitação de não observar o resultado após libertação, nesta prova original, é agora coberta pela prova separada; a capacidade de implantação continua pendente.
02/11/2026. Continuação da [projecção de referências](MODULE_ASSOCIATION_PROJECTION_DELIVERY.md), **sem alterar o código funcional** já medido. Avaliação nova de concorrência sintética, sem repetir as suites válidas anteriores. A revisão visual e a capacidade de implantação continuam separadas.
## Âmbito e preparação
PHP 8.4.27; base **sgf_tempo_test**, role **sgf_test_runner**, cluster **sgf_modular_regression_2576427d1939**, porta **55439**. Foram preparados 3 000 registos por área, 25 pares de rascunhos com 100 linhas/serviços distintos por rascunho e descrições de 1 000 bytes por linha. A página de 25 rascunhos referencia 2 500 serviços. Existe ruído de outro tenant e unidade não seleccionada, como nas fixtures anteriores.
São **quatro identidades sintéticas novas**, com consulta administrativa explicitamente configurada apenas no novo âmbito QA. Uma identidade dispõe também de `clients.edit` nesse âmbito para a confirmação sintética desfeita. Não se modificaram contas/direitos da instalação SGF, de 8039 ou de outros âmbitos anteriores.
Para processos independentes verem as mesmas linhas, **a nova fixture foi gravada exclusivamente na base de regressão e ficou retida**, com manifesto privado fora da raiz web/repositório. Não se declara rollback desta preparação. Não se apagou ou reinicializou a base. O manifesto identifica o âmbito para diagnóstico; não contém palavras-passe. Entradas privadas dos trabalhadores contêm contexto/tokens de prova e não integram os artefactos públicos.
Foram usados 1/2/4 processos PHP independentes, cada um com identidade e sessão distintas, aquecimento e barreira de arranque. Há três ondas por cenário e cinco pedidos sequenciais por processo. Os leitores executam em **transacção PostgreSQL READ ONLY**, com timeout SQL de 3 s; o coordenador impõe prazos de arranque/conclusão e termina apenas os seus próprios processos em falha.
O pedido percorre o kernel HTTP, middleware, autorização e SQL reais, com autenticação previamente preparada. Não usa servidor HTTP externo, login/MFA, TLS, proxy, navegador ou sessões reais de cliente. O tempo de arranque dos processos foi registado separadamente e excluído da janela principal de leitura.
## Resultados das leituras
Página de 25 registos. P50/P95 são percentis **descritivos da amostra**, pelo método nearest rank; não são garantias de cauda ou SLA. A taxa é a observada neste circuito fechado, incluindo validação entre pedidos, não capacidade máxima sustentada.
| Índice na prova | Área | Processos | Pedidos | P50 ms | P95 da amostra ms | Pedidos/s observados |
| --- | --- | ---: | ---: | ---: | ---: | ---: |
| Sem índice experimental | Clientes | 1 | 15 | 35,86 | 51,07 | 24,61 |
| Sem índice experimental | Clientes | 2 | 30 | 35,73 | 39,46 | 50,32 |
| Sem índice experimental | Clientes | 4 | 60 | 37,99 | 60,81 | 80,58 |
| Sem índice experimental | Facturação, 100 linhas | 1 | 15 | 298,01 | 476,93 | 3,11 |
| Sem índice experimental | Facturação, 100 linhas | 2 | 30 | 264,37 | 358,30 | 6,92 |
| Sem índice experimental | Facturação, 100 linhas | 4 | 60 | 429,46 | 495,43 | 9,57 |
| Revisão experimental | Clientes | 1 | 15 | 11,54 | 13,48 | 65,64 |
| Revisão experimental | Clientes | 2 | 30 | 11,08 | 12,16 | 132,32 |
| Revisão experimental | Clientes | 4 | 60 | 14,79 | 21,40 | 207,56 |
| Revisão experimental | Facturação, 100 linhas | 1 | 15 | 99,51 | 157,65 | 8,47 |
| Revisão experimental | Facturação, 100 linhas | 2 | 30 | 102,92 | 188,29 | 14,36 |
| Revisão experimental | Facturação, 100 linhas | 4 | 60 | 102,86 | 121,34 | 33,81 |
As **420 leituras da matriz** concluíram, sem limites SQL atingidos. Os intervalos medidos confirmaram sobreposição efectiva de 1/2/4 pedidos em todas as ondas correspondentes, não apenas processos configurados. Cada resposta foi validada contra o hash esperado da fixture; identidades diferentes receberam a mesma resposta autorizada.
Mantiveram-se 11 consultas por pedido de clientes e 31 por pedido de facturação. A memória incremental máxima por processo/pedido ficou perto de **0,09 MiB** e **4,85 MiB**, respectivamente. Não se deve multiplicar esses valores para inferir o consumo total do servidor: faltam kernel/processos, PostgreSQL, sessões e demais serviços.
O índice experimental de revisão tinha nome único por execução. Foi **gravado na base sintética para ficar visível aos outros processos e removido explicitamente no final**. Não se declara rollback dessa criação entre processos. A ausência do índice foi verificada; o catálogo anterior ficou igual. Nenhum índice foi criado/removido no destino ou na demonstração persistente.
## Leituras durante uma confirmação e espera de outro decisor
Numa transacção exterior, a API confirmou uma associação **apenas para um cliente novo da fixture** e manteve os bloqueios de empresa/registo. Enquanto a decisão permanecia sem commit, quatro leitores fizeram mais **20 pedidos**, todos com a resposta anterior esperada e sobreposição efectiva de quatro. A leitura MVCC não expôs a decisão não gravada.
Uma segunda conferência do mesmo cliente chamou o serviço de confirmação noutro processo. Foi observada espera real em `pg_stat_activity`, seguida de **SQLSTATE 55P03** ao atingir o `lock_timeout=1000ms` configurado exclusivamente nesse processo: cerca de **1 044 ms**. O chamador directo registou o erro de base de dados; este cenário não mede a apresentação HTTP desse timeout ao utilizador.
A primeira transacção foi **desfeita**. A contagem de eventos de associação do novo âmbito permaneceu igual à anterior à prova; a segunda chamada não gravou decisão. Não se decidiu nenhuma das seis associações protegidas. As provas anteriores de confirmações concorrentes com commit normal continuam válidas e não foram repetidas nesta passagem.
## Evidência e preservação
O coordenador passou **1 ensaio / 346 asserções**. Recolheu ainda a conclusão dos 89 subprocessos de teste: 88 leitores (84 da matriz + quatro da prova mista) e um concorrente de confirmação. Total: **440 leituras medidas completas**, mais o aquecimento; sem falhas nos leitores. Não se somam aqui as asserções internas dos trabalhadores às do coordenador.
[Medições por onda/pedido](proofs/module-association-concurrency-20261102.json) · [resumo, percentis e hashes](proofs/module-association-concurrency-summary-20261102.json).
Foram comparados os IDs e hashes das linhas **que já existiam antes** nas oito tabelas de registos/identidade, bem como o catálogo de índices, depois da prova. Permaneceram iguais. As novas linhas QA e quatro contas sintéticas são adicionais e retidas apenas nessa base; não são confundidas com preservação de contagem global ou com implantação de perfis. As sequências não foram repostas.
Os seis registos protegidos, a cache bloqueada, o código funcional e o trabalho alheio permaneceram intactos. Não houve ligação ao SGF local/8039, concessão real, publicação, activação de Compras ou novo checkpoint. Tokens, credenciais e manifestos privados não foram copiados para o relatório.
## Limites e repetição
A carga é curta, em uma empresa/unidade, com quatro identidades e um único login PostgreSQL de QA; não valida multi-tenant concorrente, grande número de sessões, saturação, arranque frio, dimensionamento de pool, custo de escrita prolongada ou implantação/recuperação de índices. O cluster é partilhado com outra base sintética. Os valores descritivos das amostras de 15/30/60 pedidos não validam percentis de produção ou capacidade de implantação.
O ensaio **não altera a política de timeout da aplicação**. A espera controlada foi exercitada directamente no serviço; tratamento HTTP, retries operacionais e comunicação visual de um timeout continuam a precisar de avaliação própria. A revisão visual permanece pendente, sem nova tentativa pela via bloqueada.
O launcher fixado aceita `scripts/module-association-compare.mjs concurrency`, após `sync` da cópia de regressão existente. Uma nova execução cria outro âmbito sintético e um manifesto privado, pelo que deve ser deliberada; não repete por rotina testes válidos, não reseta a base e não remove as fixtures anteriores. Os trabalhadores só aceitam entradas privadas sob o directório da execução e conferem a identidade física da base. `scripts/summarize-association-concurrency.mjs <relatorio-privado.json>` gera o resumo sem executar testes ou consultar bases.
Esta prova amplia a evidência sintética de concorrência. **Revisão visual, aceitação deste incremento e validação da capacidade de implantação continuam separadas.**
@@ -0,0 +1,43 @@
# Fila de associações — resposta HTTP ao limite de espera
02/11/2026. Continuação local da [consolidação de carga e concorrência](MODULE_ASSOCIATION_LOAD_CONSOLIDATION.md). A pendência escolhida foi a resposta da API quando uma prévia ou confirmação atinge o limite de espera por bloqueio. Não houve nova execução das matrizes de carga, índices ou 440 leituras concorrentes.
## Comportamento implementado
O [controlador administrativo existente](../app/Modules/Identity/Http/ModuleRecordsController.php) trata exclusivamente `QueryException` com SQLSTATE **55P03**, após o serviço devolver a excepção e desfazer a transacção. Prévia e confirmação devolvem **HTTP 423**, `code: association_busy`, `Cache-Control: no-store` e a mensagem:
> A conferência está ocupada por outra operação. Aguarde e volte a confirmar; o estado será novamente validado.
A resposta contém apenas `code` e `message`: não expõe SQL, bindings, tokens, stack trace ou identificadores internos. Outros erros de base de dados continuam a ser propagados ao tratamento existente. Os conflitos 409, recusas de acesso e validações mantêm o percurso anterior. A interface já apresenta a mensagem devolvida pela API e mantém a repetição manual; não precisou de alteração visual.
Não foi introduzida repetição automática da decisão nem alterado o prazo de espera da aplicação/base. Se a ligação já tiver um limite configurado e este for atingido, existe agora uma resposta administrativa compreensível. Sem limite configurado, esta alteração não limita por si só a espera. A política de espera no destino continua por definir/verificar na implantação.
O serviço de leitura conjunta, prévia, confirmação e idempotência não foi alterado: SHA-256 **b901bccc73a59e80d98d32a56532e9300a55ba9a216e5ac5a0ce84d78f976397**. As medições anteriores continuam referidas às respectivas fontes e condições; não medem o desempenho deste novo ramo de resposta HTTP.
## Prova nova e recuperação
Execução exclusivamente em **sgf_tempo_test**, role **sgf_test_runner**, porta **55439**, cluster **sgf_modular_regression_2576427d1939**, com verificação física antes de preparar dados. Três clientes novos num âmbito sintético novo, retido apenas na regressão para visibilidade entre processos, com manifesto privado. Não se limpou/reinicializou a base.
Um processo manteve uma confirmação não gravada. Um segundo processo chamou a API pelo kernel HTTP com `lock_timeout=1000ms` exclusivamente nessa ligação de prova. Observou-se a espera `transactionid` e verificou-se o primeiro processo entre os bloqueadores. O prazo terminou antes de libertar a primeira transacção.
| Operação que esperou | Resposta ao limite | Tempo total ms | Libertação posterior | Recuperação manual |
| --- | --- | ---: | --- | --- |
| Confirmação | 423 / association_busy | 1086,658 | rollback | 200; repetição devolve o mesmo evento |
| Confirmação | 423 / association_busy | 1093,136 | commit | 409 com token antigo; nova prévia disponível |
| Prévia | 423 / association_busy | 1083,944 | rollback | nova prévia 200; confirmação e repetição sem duplicação |
Cada cenário verificou a contagem de decisões imediatamente após libertar a primeira transacção: **zero** nos casos de rollback e **uma** no caso de commit. O pedido que recebeu 423 não deixou uma decisão parcial. Após os passos de recuperação/repetição ficou exactamente **um evento por cliente**. Não se propagaram associações a dependentes.
O teste dos trabalhadores exige a resposta JSON exacta e o cabeçalho sem cache. A recuperação usa as rotas reais da API em processo, mantendo contexto, autenticação e direitos sintéticos. A conferência antiga continua a ser recusada se outra decisão alterou a revisão.
- **1 teste / 54 asserções** no coordenador, mais três trabalhadores aprovados, para os novos cenários HTTP.
- **13 testes / 232 asserções** afectados da fila aprovados. Repetidos porque o controlador de prévia/confirmação mudou; incluem permissões, isolamento, revisão, dependências, concorrência e recuperação existentes. Não se repetiu a suite de navegação nem suites alheias.
- Impressões digitais dos registos QA anteriores e catálogo de índices iguais no ensaio de bloqueio. Hashes das provas válidas anteriores conferidos e preservados.
[Prova sanitizada](proofs/module-association-http-lock-20261102.json) · [Resumo, fontes, testes e hashes](proofs/module-association-http-lock-summary-20261102.json). Launcher específico: `scripts/module-association-compare.mjs http-lock`, após actualizar apenas a cópia de regressão existente com `sync`. Não usar `prepare` ou reset. Entradas dos trabalhadores, tokens e manifestos permanecem privados.
## Preservação e limites
Os seis registos protegidos, a cache bloqueada, a demonstração 8039 e alterações alheias foram preservados. Sem ligação ao destino, índice/migração, direito público, activação de Compras, publicação, aceitação ou checkpoint presumidos. A preparação sintética e os seus resultados ficaram na base de regressão; não se declara rollback de toda a fixture.
Esta prova cobre a resposta pelo kernel HTTP em processo; não mede rede, servidor HTTP implantado, login/MFA, TLS ou navegador. Os tempos incluem a espera deliberada de aproximadamente um segundo. Não representam latência normal, SLA ou capacidade de implantação. A criação de índices e a política operacional de espera/repetição no destino continuam separadas. **Revisão visual e validação da capacidade de implantação permanecem pendentes**, sem tentativa pela via de navegador bloqueada.
@@ -0,0 +1,145 @@
# Fila de associações — consolidação de carga, concorrência e HTTP
02/11/2026. **A optimização está implementada localmente.** A listagem usa leitura conjunta da página e das suas dependências em `describePage/pageStates`, com lotes limitados, sem materializar o universo. A projecção posterior `pageColumns` selecciona metadados e referências em vez dos corpos completos. Prévia e confirmação continuam a obter e revalidar o estado completo actual. Código: [ModuleAssociationReview.php](../app/Modules/Identity/Services/ModuleAssociationReview.php). Esta passagem acrescenta provas e documentação; não altera esse código funcional.
## Cobertura conferida e medições em falta
Consolidação das três entregas, com conferência dos hashes das provas e das fontes actuais do serviço e controlador. Existem **24 combinações obrigatórias**: 3 volumes × 4 áreas × páginas de 25/100, todas com resultados medidos para A/B/C, mais **9 cenários de filtros**. Não falta nenhuma combinação dessa comparação da leitura conjunta. **Não se abriu ligação a qualquer base, nem se executou nova medição ou suite nesta consolidação.** Foram reutilizadas as provas válidas.
Há **13 tentativas da baseline limitadas** pelo orçamento de 15 s; constituem resultados censurados, não medições completas nem combinações nunca executadas. A tabela mantém esses limites explícitos, sem inventar medianas ou rácios de ganho. Prolongar apenas a baseline mudaria as condições; não se repetiram as experiências válidas para obter números completos da versão antiga.
A comparação nos três volumes mede o incremento de leitura conjunta **anterior à projecção**, com a fonte B/C identificada abaixo. A versão actual com projecção tem prova própria de 10 000 registos por área, documentos de 100 linhas e duas dimensões de descrição; **não foi medida numa nova matriz completa de 1 000/5 000/10 000 contra a baseline original**. Não se fundiram essas experiências nem se apresentam valores de B como sendo da fonte projectada actual. Essa matriz adicional não é necessária para demonstrar o ganho isolado da leitura conjunta e não foi repetida nesta consolidação.
[Inventário verificável da cobertura, métricas por combinação e hashes](proofs/module-association-consolidation-summary-20261102.json). O verificador `scripts/consolidate-association-evidence.mjs` lê apenas fontes e provas locais, valida as 24 combinações e rejeita lacunas ou alterações de hash; não executa SQL.
## Espera da confirmação: causa e resultado após libertação
A prova anterior atingiu `lock_timeout=1000ms` (SQLSTATE 55P03, 1 044,222 ms) porque a primeira transacção foi deliberadamente mantida aberta. A nova prova observou a consulta sobre **companies com FOR UPDATE**, o PID da primeira transacção em `pg_blocking_pids` e a espera **Lock / transactionid / ShareLock** em `pg_stat_activity/pg_locks`. É serialização da confirmação por empresa; o limite não surgiu da leitura conjunta da auditoria. Pode também serializar confirmações de registos diferentes da mesma empresa; esse volume de escritores não foi medido.
Em quatro cenários novos, a primeira transacção foi libertada depois de observar a espera real e aguardar mais 200 ms. O segundo processo tinha limite de bloqueio de 8 s exclusivamente para esta prova. Os tempos abaixo incluem espera e execução, não representam latência normal nem tempo puro após desbloqueio.
| Cenário | Libertação da primeira | Segunda confirmação | Tempo total ms | Versão do registo final | Eventos de decisão após repetição |
| --- | --- | --- | ---: | ---: | ---: |
| rollback_then_complete | rollback | 200 | 352,39 | 1 | 1 |
| commit_then_stale_revision | commit | 409 | 338,39 | 1 | 1 |
| commit_then_same_token | commit | 200 (repetição) | 333,37 | 1 | 1 |
| commit_record_change_then_stale_version | commit | 409 | 335,55 | 2 | 0 |
Após rollback, a segunda decisão gravou exactamente um evento. Após commit de outra decisão, o token preparado antes da espera recebeu **409 por revisão de associações desactualizada**, mesmo mantendo versão documental 1; nova prévia foi possível. O mesmo token da decisão vencedora recebeu sucesso idempotente e o mesmo identificador de evento. Quando a versão documental mudou para 2 durante a espera, o token da versão 1 recebeu **409**, sem decisão; uma prévia da versão 2 foi possível. As repetições não acrescentaram eventos. Os estados de sucesso/409 do segundo processo são resultados do serviço; as repetições e novas prévias foram também verificadas pela API em processo. A apresentação HTTP do limite foi posteriormente implementada e provada separadamente, conforme a secção seguinte.
**Prova de libertação reutilizada: 1 teste / 79 asserções, sem falhas ou erros**, mais quatro trabalhadores concluídos. [Prova](proofs/module-association-release-20261102.json) e [resumo com hashes](proofs/module-association-release-summary-20261102.json). A primeira tentativa desta prova concluiu os quatro cenários mas falhou na comparação final da auditoria por exceder 65 535 parâmetros SQL; corrigiu-se apenas o auxiliar de preservação para IDs inteiros capturados. A execução acima repetiu esta prova afectada e passou; não se repetiram as matrizes ou suites válidas.
## Tratamento HTTP entregue e provado
O controlador administrativo existente passou a traduzir exclusivamente SQLSTATE **55P03** em **423 / association_busy**, para prévia e confirmação, depois do rollback do serviço. A resposta contém apenas mensagem administrativa e código, com `Cache-Control: no-store`, sem SQL/bindings ou stack trace. Não foram alterados o prazo de espera, os direitos ou o serviço de decisão; não há repetição automática. Outras excepções mantêm o tratamento existente, e mudanças de estado continuam a produzir 409.
| Pedido limitado | Tempo total com espera diagnóstica ms | Resposta | Libertação e recuperação posterior |
| --- | ---: | --- | --- |
| Confirmação | 1086,658 | 423 | Rollback da primeira; repetição manual 200 e repetição idempotente |
| Confirmação | 1093,136 | 423 | Commit da primeira; token antigo 409 e nova prévia 200 |
| Prévia | 1083,944 | 423 | Rollback da primeira; nova prévia 200, confirmação e repetição idempotente |
Em cada caso foi observado o bloqueador real, configurando 1 s apenas na ligação do trabalhador de prova. A contagem após libertação confirmou ausência de decisão parcial do pedido limitado; após recuperação ficou exactamente **um evento por cliente**, sem duplicação. Estes tempos incluem a espera deliberada, não latência normal.
**1 teste / 54 asserções**, mais três trabalhadores aprovados; **13 testes / 232 asserções** da fila afectados pela alteração do controlador também aprovados. Estes últimos foram repetidos na entrega HTTP por haver alteração funcional, não nesta consolidação. A prova anterior de navegação e as matrizes mantiveram-se válidas, sem repetição. Não somar asserções de suites sobrepostas como cobertura distinta.
[Entrega HTTP](MODULE_ASSOCIATION_HTTP_LOCK_DELIVERY.md) · [Prova](proofs/module-association-http-lock-20261102.json) · [Testes e hashes](proofs/module-association-http-lock-summary-20261102.json). Controlador actual SHA-256 **6c16481f7e3f4355ba60ca22bc67385ec3b3113b4784e5d9f57025618e1735a9**. A apresentação foi provada pelo kernel HTTP em processo; navegador, servidor HTTP de implantação e rede permanecem fora da prova.
## Comparação A/B/C: leitura conjunta e índices separados
Medições já válidas, reutilizadas sem nova execução. **A**: checkpoint 340f3bb, consultas por registo; **B**: leitura conjunta, sem índices experimentais, **antes da projecção posterior**; **C**: mesmo B com dois índices experimentais de auditoria. Portanto A→B mede a leitura conjunta e B→C mede separadamente os índices. Não atribuir ao código actual exactamente os tempos de B: a projecção tem outra medição e hash abaixo.
Mesma fixture imutável em cada volume, 1 000/5 000/10 000 **por cada uma das quatro áreas**, dependências incluídas; três repetições, ordem A/B alternada, C sobre os mesmos dados, kernel e buffers aquecidos. Valores: mediana de tempo; consultas por pedido completo; máximo de memória PHP usada incremental acima do início do pedido, em **KiB**, sem incluir PostgreSQL ou memória total do processo. “limite” significa tentativa interrompida pelo orçamento diagnóstico de 15 s, sem mediana/consultas/memória comparáveis; não é um valor de 15 s nem um ganho calculável. Na prova completa foram 258 leituras medidas concluídas e 13 tentativas limitadas; respostas completas comparáveis idênticas.
Cada célula contém **A / B / C**. A memória em B pode aumentar face a A, por conservar o conjunto da página; a redução de consultas não implica redução de memória.
| Registos por área | Área / filtro | Página | Tempo ms A/B/C | Consultas A/B/C | Memória incremental KiB A/B/C |
| ---: | --- | ---: | ---: | ---: | ---: |
| 1000 | Clientes / all | 25 | 1986,50 / 36,77 / 10,66 | 185 / 11 / 11 | 86,50 / 100,29 / 100,13 |
| 1000 | Clientes / all | 100 | 7407,37 / 29,77 / 12,85 | 710 / 11 / 11 | 158,61 / 254,37 / 254,21 |
| 1000 | Serviços / all | 25 | 1924,42 / 30,09 / 10,81 | 185 / 11 / 11 | 86,55 / 99,55 / 99,39 |
| 1000 | Serviços / all | 100 | 7778,43 / 31,96 / 11,90 | 710 / 11 / 11 | 158,70 / 253,59 / 253,45 |
| 1000 | Rascunhos serviço / all | 25 | 3905,95 / 77,23 / 16,65 | 435 / 19 / 19 | 116,95 / 221,35 / 221,22 |
| 1000 | Rascunhos serviço / all | 100 | limite / 77,02 / 22,16 | limite / 19 / 19 | limite / 744,63 / 744,50 |
| 1000 | Rascunhos facturação / all | 25 | 5014,74 / 96,21 / 19,61 | 560 / 23 / 23 | 131,74 / 294,41 / 294,28 |
| 1000 | Rascunhos facturação / all | 100 | limite / 100,60 / 28,94 | limite / 23 / 23 | limite / 1037,20 / 1037,06 |
| 1000 | Clientes / pending | 25 | 1974,80 / 100,45 / 86,03 | 185 / 11 / 11 | 85,87 / 96,77 / 96,63 |
| 1000 | Clientes / associated | 25 | 2034,10 / 107,24 / 34,23 | 185 / 11 / 11 | 92,58 / 112,45 / 112,33 |
| 1000 | Clientes / removed | 25 | 2721,26 / 754,12 / 78,34 | 185 / 11 / 11 | 88,05 / 107,75 / 107,61 |
| 5000 | Clientes / all | 25 | 6295,36 / 97,22 / 18,45 | 185 / 11 / 11 | 86,75 / 100,30 / 100,14 |
| 5000 | Clientes / all | 100 | limite / 87,01 / 19,76 | limite / 11 / 11 | limite / 254,63 / 254,47 |
| 5000 | Serviços / all | 25 | 5238,39 / 92,19 / 17,11 | 185 / 11 / 11 | 86,80 / 100,36 / 100,20 |
| 5000 | Serviços / all | 100 | limite / 77,98 / 18,13 | limite / 11 / 11 | limite / 254,70 / 254,55 |
| 5000 | Rascunhos serviço / all | 25 | 10553,09 / 216,02 / 36,97 | 435 / 19 / 19 | 117,20 / 221,60 / 221,47 |
| 5000 | Rascunhos serviço / all | 100 | limite / 232,94 / 44,38 | limite / 19 / 19 | limite / 744,88 / 744,75 |
| 5000 | Rascunhos facturação / all | 25 | 13947,25 / 377,18 / 33,66 | 560 / 23 / 23 | 132,33 / 294,41 / 294,28 |
| 5000 | Rascunhos facturação / all | 100 | limite / 322,13 / 65,66 | limite / 23 / 23 | limite / 1037,20 / 1037,06 |
| 5000 | Clientes / pending | 25 | 7236,64 / 578,25 / 104,08 | 185 / 11 / 11 | 85,87 / 96,77 / 96,63 |
| 5000 | Clientes / associated | 25 | 7045,59 / 362,62 / 329,05 | 185 / 11 / 11 | 92,58 / 112,45 / 112,33 |
| 5000 | Clientes / removed | 25 | 6394,64 / 679,37 / 409,55 | 185 / 11 / 11 | 88,05 / 107,75 / 107,61 |
| 10000 | Clientes / all | 25 | 9683,04 / 156,32 / 13,88 | 185 / 11 / 11 | 86,75 / 100,30 / 100,14 |
| 10000 | Clientes / all | 100 | limite / 203,09 / 14,52 | limite / 11 / 11 | limite / 254,63 / 254,47 |
| 10000 | Serviços / all | 25 | 9385,15 / 117,18 / 11,66 | 185 / 11 / 11 | 86,55 / 99,55 / 99,39 |
| 10000 | Serviços / all | 100 | limite / 109,77 / 14,87 | limite / 11 / 11 | limite / 253,59 / 253,45 |
| 10000 | Rascunhos serviço / all | 25 | limite / 333,79 / 20,32 | limite / 19 / 19 | limite / 220,98 / 220,85 |
| 10000 | Rascunhos serviço / all | 100 | limite / 399,87 / 26,89 | limite / 19 / 19 | limite / 744,27 / 744,13 |
| 10000 | Rascunhos facturação / all | 25 | limite / 592,80 / 28,73 | limite / 23 / 23 | limite / 294,05 / 293,91 |
| 10000 | Rascunhos facturação / all | 100 | limite / 451,13 / 35,65 | limite / 23 / 23 | limite / 1036,83 / 1036,70 |
| 10000 | Clientes / pending | 25 | limite / 2553,13 / 113,84 | limite / 11 / 11 | limite / 96,77 / 96,63 |
| 10000 | Clientes / associated | 25 | 9377,31 / 521,51 / 254,95 | 185 / 11 / 11 | 92,58 / 112,45 / 112,33 |
| 10000 | Clientes / removed | 25 | 9973,28 / 1290,76 / 292,74 | 185 / 11 / 11 | 88,05 / 107,75 / 107,61 |
Métricas brutas, incluindo picos PHP absolutos, tempos SQL, amostras e hashes: [comparação](proofs/module-association-optimization-comparison-20261102.json). [Método, planos, índices e recusas de acesso](MODULE_ASSOCIATION_OPTIMIZATION_DELIVERY.md). Os dois índices (ligações por módulo e revisão por registo) foram criados apenas no ensaio sintético e desfeitos por rollback/savepoint; nenhum índice no destino.
## Código actual: projecção e documentos com muitas dependências
A fase posterior comparou B com a projecção actual, mantendo 10 000 registos por área e 100 linhas por rascunho, páginas 25/100, descrições de 128/1 000 bytes. Foram 132 leituras completas, 44 cenários, respostas equivalentes. A projecção reduziu a memória, mas não acelerou todas as leituras sem índice. Para descrições de 1 000 bytes:
| Área / página | Tempo ms antes projecção / actual sem índice / actual só índice revisão / actual par | Memória incremental MiB antes / actual |
| --- | ---: | ---: |
| Serviço / 25 | 668,119 / 728,558 / 97,487 / 225,676 | 8,28 / 4,21 |
| Serviço / 100 | 2150,980 / 2861,608 / 341,479 / 408,455 | 32,42 / 16,65 |
| Facturação / 25 | 815,219 / 905,073 / 111,725 / 127,118 | 11,55 / 4,85 |
| Facturação / 100 | 2720,541 / 2481,159 / 374,043 / 368,403 | 45,49 / 19,23 |
Consultas: serviço 27/57 e facturação 31/61, páginas 25/100; o crescimento decorre dos lotes das dependências (até 10 000 serviços na página), não do carregamento de todo o universo. Índice de revisão: 13,73 MiB; par: 30,50 MiB. O segundo índice não mostrou benefício consistente; não foi recomendado/aplicado automaticamente. Experiências desfeitas apenas na base sintética. [Relatório e provas desta fase](MODULE_ASSOCIATION_PROJECTION_DELIVERY.md).
Proveniência SHA-256 do serviço: A **44a2c75d6a2ecaddc151b3c92175324e15ca4e2664a87a4d50c093913adb4114**; B/C **6df1a85af8ea3112ff8e61741408158cd0444944cc3e0b407ad5bd4ad8043361**; projecção actual e nova prova de libertação **b901bccc73a59e80d98d32a56532e9300a55ba9a216e5ac5a0ce84d78f976397**. A confirmação/prévia não foram alteradas pela optimização.
## Concorrência de leitura e equivalência preservadas
Mantêm-se válidas **440 leituras completas**, até quatro identidades/processos com sobreposição efectivamente observada: 420 da matriz e 20 durante confirmação sem commit. Página 25, 3 000 por área, rascunhos com 100 linhas de 1 000 bytes. Todas corresponderam aos hashes autorizados; os leitores viram o estado anterior enquanto a decisão não tinha commit. Não foram repetidas.
Com quatro processos, clientes: P50/P95 amostral **37,990/60,810 ms sem índice**, **14,790/21,402 ms com revisão**; facturação: **429,457/495,430 ms sem índice**, **102,861/121,342 ms com revisão**. Consultas 11/31, memória incremental máxima aproximada 0,09/4,85 MiB por pedido. Os percentis descrevem amostras pequenas (15/30/60 pedidos); não constituem SLA. O índice desta prova entre processos foi gravado só na regressão para ser visível, depois removido explicitamente, com catálogo anterior igual. [Ondas, tempos e limites](MODULE_ASSOCIATION_CONCURRENCY_REVIEW.md).
Preservam-se também as provas válidas afectadas: **21 testes / 322 asserções**, equivalência de filtros, ordenação, paginação, isolamento e recusas, versões/dependências, prévia, confirmação, falha e recuperação; ensaios separados de planos e acessos documentados na entrega. Não foram repetidos por não haver alteração funcional nesta continuação.
## Gargalos que persistem e correcção mínima proposta
**Leitura SQL:** a leitura conjunta eliminou as consultas à auditoria por cada registo da página, mas os filtros de estado e as contagens conservam `EXISTS/NOT EXISTS` correlacionados, e a agregação de estados ainda tem de procurar/ordenar eventos da auditoria. Sem índice adequado ao âmbito/chaves JSON, continuam varrimentos e trabalho proporcional ao histórico. Em 10 000 clientes, o filtro de pendentes ainda demorou **2 553,134 ms** na variante B sem índice, contra **113,836 ms** com o par; essa melhoria não deve ser atribuída apenas ao batching. Os planos e a experiência posterior distinguindo revisão/par sustentam o candidato mais pequeno, não a criação automática de ambos.
**Proposta mínima:** usar como candidato apenas o índice parcial de revisão já experimentado, sem nova tabela, cache de decisões ou reescrita do circuito. Definição reproduzida para revisão, **não executada nesta passagem e não aplicada no destino**:
```sql
CREATE INDEX sgf_qa_assoc_revision
ON identity_audit
(tenant_id, company_id, (details->>'area'), (details->>'record_id'), id DESC)
WHERE action IN
('module.record.associated', 'module.record.disassociated', 'module.record.reviewed');
```
Este é o nome/DDL do candidato QA, não uma migração de produção. A prova isolada da projecção mediu cerca de **13,73 MiB** para esse índice; o par ocupou **30,50 MiB** e não mostrou ganho consistente. Antes de qualquer implantação, falta validar plano, custo de escrita/manutenção, criação/recuperação e condições do destino. Se os filtros ainda forem lentos com o índice, o incremento seguinte mínimo será calcular os estados por âmbito numa relação SQL comum reutilizada na contagem/página, preservando a semântica da última associação/retirada por módulo e separando-a da revisão. Essa reescrita **não está implementada nem validada**; os dados actuais não justificam fazê-la antes de avaliar o candidato menor.
**Documentos com muitas dependências:** o custo residual de memória/consultas cresce com a página e o número de referências reais (até 10 000 serviços), mesmo após projectar o corpo documental. A projecção já reduziu o pior caso medido de **45,49 para 19,23 MiB**. Um índice não elimina esse custo em PHP; não declarar que o índice resolve memória ou renderização. A página de 25 já disponível é a opção menos pesada no ensaio; não se alterou o limite de 100 nem se truncaram dependências silenciosamente. Uma eventual consulta progressiva das dependências exigiria outro incremento e prova de equivalência.
**Confirmações:** o `FOR UPDATE` da empresa serializa os escritores e foi mantido para preservar a revalidação de contexto/permissões. O 423 já entregue melhora a resposta a um limite, mas não remove o bloqueio nem aumenta o débito. Não remover ou estreitar esse lock sem provar corridas com a administração de acessos. O mínimo operacional pendente é definir um orçamento de espera coerente com o servidor HTTP e manter repetição manual/revalidação; não se escolheu ou aplicou um prazo real por consequência destes testes.
## Preservação e pendências separadas
A execução de libertação anteriormente concluída verificou fisicamente **sgf_tempo_test / sgf_test_runner / porta 55439 / cluster sgf_modular_regression_2576427d1939**. Usou quatro clientes e âmbito novos, exclusivamente de regressão, gravados para visibilidade entre processos e retidos com manifesto privado. A primeira tentativa também deixou a sua pequena fixture sintética nesta base; não se apagou nem reinicializou a base. A execução válida verificou hashes dos registos QA anteriores e igualdade do catálogo de índices. Tokens, contexto e manifestos privados não integram estas provas públicas.
Os seis registos protegidos, a demonstração 8039, o SGF local, a cache bloqueada, provas válidas e trabalho alheio foram preservados; não se abriu ligação ao destino nesta prova. Sem novos índices, direitos públicos, activação de Compras, publicação ou checkpoint. O auxiliar de preservação foi corrigido, não a aplicação.
**Capacidade de implantação não validada.** Estes ensaios locais usam kernel HTTP em processo e trabalhadores PHP; não medem navegador, login/MFA, rede/TLS, servidor HTTP implantado, carga sustentada, vários escritores ou recursos completos do servidor. Faltam condições, orçamento de memória, índices/planos e política de espera/repetição próprios do destino. A revisão visual permanece separada e pendente, sem repetir a via de navegador bloqueada.
Nesta consolidação não se alterou código da aplicação, não se executou SQL nem se repetiram testes. Conferiram-se as fontes e os hashes das provas anteriores e produziu-se o inventário de cobertura. **Revisão visual**: pendente, incluindo a apresentação de páginas com muitas dependências e mensagens ao utilizador. **Capacidade de implantação**: pendente, com as provas operacionais próprias enumeradas acima. Uma pendência não é pré-condição para documentar a outra nem prova de que esteja concluída. Os seis registos e a cache não foram acedidos ou alterados.
+91
View File
@@ -0,0 +1,91 @@
# Avaliação sintética de carga e paginação da fila
Seguimento: [optimização local, comparação final A/B/C e limitações](MODULE_ASSOCIATION_OPTIMIZATION_DELIVERY.md). A avaliação abaixo permanece a linha de base histórica; a comparação nova usa 1 000/5 000/10 000 registos em **cada** área e mede separadamente código e índices exclusivamente sintéticos. Não se considera validada a capacidade de implantação.
02/11/2026. Avaliação do código funcional aceite em **340f3bb5fa0e72d659abe43f3498b49e25ca3809**, sem o modificar. A paginação e os filtros devolveram os registos esperados nos casos concluídos, mas a leitura repetida da auditoria torna o tempo elevado com mais histórico. **Não se considera resolvida a capacidade de implantação.**
## Método e isolamento
Novo ensaio explícito em `scripts/benchmarks/ModuleAssociationLoadTest.php`, fora das pastas da suite habitual. Executa pedidos autenticados pelo kernel HTTP no processo de testes, com sessões em memória e PostgreSQL real em loopback. Não mede transporte HTTP externo, login, TLS, navegador ou capacidade com utilizadores simultâneos. Não foram repetidos os testes válidos da entrega aceite nem o build.
PHP **8.4.27**, Node fixado **24.22.1**, PostgreSQL **17.11**; base **sgf_tempo_test**, role **sgf_test_runner**, cluster **sgf_modular_regression_2576427d1939**, porta **55439**, aplicação de regressão em `C:/laragon/data/sgf-tempo/run/modular-regression-2576427d1939/app`. Guardas conferidas antes de criar fixtures. A base persistente 8039, a instalação local e os seus seis registos protegidos não foram consultados ou alterados nesta passagem.
Cada escala usa empresa/tenant/contas fictícias novas e rollback das fixtures; sem reset, migração, direitos públicos, alteração de índices ou decisões reais. Foram gerados eventos de associação/retirada **apenas como histórico sintético**, sem alterar os registos protegidos. Inclui ruído de outro tenant e uma prestação de unidade não seleccionada.
| Clientes | Serviços | Prestações | Rascunhos de facturação | Eventos de associação/retirada |
| ---: | ---: | ---: | ---: | ---: |
| 1 000 | 100 | 100 | 100 | 7 376 |
| 5 000 | 100 | 500 | 500 | 34 570 |
| 10 000 | 100 | 1 000 | 1 000 | 68 579 |
O estado é distribuído pelo ID sintético: cerca de um terço sem eventos, um terço associado e um terço com associações retiradas. Para os registos com eventos, quatro pares de associação/retirada e uma associação final nos activos. Os rascunhos referenciam cliente, serviço e, na facturação, prestação de origem. Não representa todas as possíveis distribuições de módulos ou histórico.
Há aquecimento por escala, depois três amostras por cenário concluído. Limites de diagnóstico: 3 s por instrução SQL, 15 s por pedido observado entre consultas e 2 500 consultas. **Estes limites protegem o ensaio; não são SLA nem limites configurados no produto.** Após atingir um limite, não se repete esse cenário para obter uma mediana artificial.
## Resultados
Medianas em segundos, incluindo instrumentação e kernel, excluindo criação das fixtures e `EXPLAIN`. Primeira/última página usam a mesma ordenação por ID.
| Cenário | 1 000 clientes | 5 000 clientes | 10 000 clientes |
| --- | ---: | ---: | ---: |
| Clientes, 25, primeira página | 0,396 | 1,673 | 4,811 |
| Clientes, 25, última página | 0,412 | 1,900 | 4,611 |
| Clientes, 100, primeira página | 1,611 | 7,772 | Limite de 15 s atingido |
| Clientes sem eventos, 25 | 0,458 | 2,142 | 6,365 |
| Clientes associados, 25 | 0,447 | 2,017 | 4,249 |
| Clientes com associações retiradas, 25 | 0,491 | 2,495 | 5,208 |
| Pesquisa que selecciona um cliente | 0,027 | 0,088 | 0,202 |
| Prestações com dependências, 25 | 0,803 | 3,189 | 9,365 |
| Facturação com dependências, 25 | 1,018 | 4,189 | 11,503 |
**26 de 27 cenários concluíram as três amostras: 78 pedidos medidos completos.** O outro cenário atingiu o orçamento e não tem mediana nem confirmação de resultado completo. Não houve timeout SQL nos cenários finais; o limite observado foi o do pedido instrumentado. A conclusão do ensaio não equivale a aprovação desse cenário.
O novo teste terminou aprovado: **1 teste, 2 439 asserções**. Verificou totais/IDs exactos nos casos completos, primeira/última página, estados, pesquisa selectiva, ausência de dependências inacessíveis e exclusão do ruído fora do âmbito. Na escala de 1 000 houve ainda percurso integral de dez páginas de 100, com cobertura ordenada exacta sem repetição ou omissão. Nas escalas maiores não se percorreu cada página intermédia.
| Resposta | Consultas por pedido completo | Tamanho observado da resposta na maior escala |
| --- | ---: | ---: |
| 25 clientes | 185 | cerca de 3,7 KB |
| 100 clientes | 710 nas escalas concluídas | cerca de 13,8 KB em 5 000 |
| Pesquisa de um cliente | 17 | 448 bytes |
| 25 prestações | 435 | cerca de 7,2 KB |
| 25 rascunhos de facturação | 560 | cerca de 9,2 KB |
Pico PHP observado: 44/48/54 MiB por escala. Inclui kernel, PHPUnit e alocações de fixtures/instrumentação; **não é memória exclusiva da listagem nem memória PostgreSQL**. Não se infere capacidade de concorrência ou consumo por utilizador a partir destes valores.
## Gargalos sustentados pelos planos
Na maior escala, 25 clientes provocam **50 chamadas `DISTINCT ON` à auditoria e 50 chamadas `MAX(id)`**: o estado é pedido na listagem e novamente na descrição do grafo. No terceiro pedido medido da primeira página, essas duas formas acumularam aproximadamente **3,87 s + 0,83 s** de tempo SQL. Nos rascunhos de facturação sobem para **125 chamadas de cada forma**, aproximadamente **9,86 s + 1,62 s** naquele pedido medido.
Os planos amostrados mostram varrimento sequencial de `identity_audit` para `DISTINCT ON`, com extracção de chaves JSON, ordenação e, na maior escala, trabalhadores paralelos. `MAX(id)` pode percorrer a chave primária filtrando dezenas de milhares de eventos até encontrar o registo, ou percorrê-los sem encontrar associação. O catálogo conferido mostra apenas **identity_audit_pkey** nessa tabela; não há índice por empresa/área/registo/módulo.
O filtro de pendentes também é relevante: o plano de página amostrado em 10 000 contém `Nested Loop`/`Materialize`, **75 iterações** da entrada materializada e **27 818 blocos temporários lidos**, além da leitura posterior do estado de cada registo. Não somar blocos repetidos de pais/filhos do plano como se fossem páginas distintas.
A primeira e a última página de 25 ficaram próximas neste ensaio; os dados não sustentam que o OFFSET seja o gargalo dominante actual. A pesquisa selectiva é mais rápida porque descreve um registo em vez de 25. A resposta HTTP mantém-se pequena: os principais custos observados estão na leitura SQL repetida e nos filtros, não no volume de JSON devolvido.
## Tratamento técnico proposto, ainda não implementado
1. Construir o conjunto de registos/dependências autorizados de cada página e ler os eventos correspondentes **em conjunto**, reutilizando resultados dentro do pedido. Eliminar a dupla descrição do estado do registo e consultas repetidas das mesmas dependências. Não manter cache entre pedidos que possa esconder revogações ou mudanças.
2. Separar correctamente «última associação/retirada por módulo» de «última revisão de qualquer decisão». `module.record.reviewed` afecta a revisão/idempotência, mas não deve inventar associação activa ou transformar um registo sem eventos de associação num associado.
3. Ensaiar em base sintética um índice composto/de expressão compatível com tenant, empresa, área, registo, módulo e ordem de evento. Medir a consulta em conjunto e os filtros de estado; não assumir que a chave primária basta ou que um índice isolado resolve as consultas por registo.
4. Rever a consulta dos estados para evitar materializar/repercorrer o histórico repetidamente. Manter filtros e ordenação no servidor e as verificações de consulta originais antes de apresentar dependências.
5. Repetir apenas as medições e provas afectadas pela futura optimização, comparar com esta linha de base e definir critérios de latência/carga antes de homologar implantação. Validar também distribuição de histórico mais longa, várias empresas, decisões concorrentes, custos de escrita e recuperação do índice. A confirmação individual deve continuar a reler/bloquear o estado, sem confiar na fotografia da listagem.
Não se propõe aumentar o tamanho de página como solução. A interface mantém 25; o limite de 100 da API não deve ser interpretado como capacidade validada em todos os volumes. Não se alterou o código funcional, um índice, um direito ou configuração de cliente nesta avaliação.
## Evidência, recuperação e limites
[Medições e planos](proofs/module-association-load-20261102.json) · [resumo e hashes](proofs/module-association-load-summary-20261102.json) · [catálogo de índices](proofs/module-association-load-catalog-20261102.json). Os planos publicados omitem bindings e filtros com valores: não exportam nomes, documentos ou credenciais.
As fixtures foram desfeitas por rollback. Duas consultas READ ONLY posteriores confirmaram vazias as quatro tabelas de registos, auditoria, utilizadores, concessões e pertenças da base descartável: [consulta 1](proofs/module-association-load-postcheck1-20261102.json), [consulta 2](proofs/module-association-load-postcheck2-20261102.json). **Ambas são posteriores ao ensaio**, não uma comparação com impressão digital anterior. As sequências avançam com a preparação sintética e não foram repostas. Estatísticas `ANALYZE` e disposição física/cache pertencem à base de provas; não são alterações da implantação.
As escalas correram sucessivamente na mesma base, com rollback e `ANALYZE`, sem recriação ou `VACUUM` entre escalas. Cache, páginas físicas e estatísticas podem influenciar as diferenças; não se infere uma curva pura de cardinalidade. São três amostras por caso, sem percentis de cauda ou throughput. O cluster é isolado da instalação, mas partilhado com a demonstração sintética noutro banco; não se ensaiou saturação de recursos ou multiutilizador.
Uma primeira tentativa de preparação falhou por parâmetro JSON sem tipo PostgreSQL (`42P18`). Corrigiu-se apenas o gerador sintético com cast explícito; a transacção falhada foi desfeita. A execução final acima não apresentou erros. Não houve correcção de produto, repetição da suite aceite, novo checkpoint, publicação ou activação de Compras. A cache bloqueada ficou intacta.
## Repetição deliberada
O launcher é `scripts/module-association-load.mjs`, invocado pelo Node fixado do SGF; usa explicitamente PHP 8.4.27 e confere o host isolado. Antes de uma nova avaliação autorizada, `scripts/modular-regression-run.mjs sync` actualiza apenas a cópia de regressão. Não executar `prepare` sobre o cluster existente nem apontar PHPUnit à demonstração persistente. O relatório/JUnit ficam no directório privado dessa execução; os artefactos publicados acima contêm apenas métricas/planos sem bindings.
`scripts/module-association-load-state.php` é um diagnóstico READ ONLY exclusivo da base de regressão, com guarda e identidade física; não serve para consultar dados de cliente. Nesta entrega foi usado apenas depois do ensaio.
Avaliação sintética concluída como diagnóstico, **optimização e validação da capacidade de implantação pendentes**. Revisão visual permanece separada. A fila continua tecnicamente aceite no âmbito anterior e os seis registos continuam dependentes de decisões individuais futuras.
@@ -0,0 +1,131 @@
# Optimização local da fila administrativa de associações
Continuação posterior: [projecção de referências, ensaio de 100 linhas e índices isolados](MODULE_ASSOCIATION_PROJECTION_DELIVERY.md). As medições abaixo pertencem à fase anterior à projecção; a continuação reduziu a memória de documentos largos e preservou o contrato da fila. A capacidade de implantação continua pendente.
02/11/2026. Incremento autorizado após a [avaliação sintética de carga](MODULE_ASSOCIATION_LOAD_REVIEW.md). Fonte anterior: checkpoint técnico **340f3bb**. O incremento altera apenas a descrição da página na API; não altera a confirmação individual, direitos, contratos de prévia, navegação ou interface React. Sem publicação, activação de Compras ou índice no destino.
## Implementação
`ModuleAssociationReview::listing()` conserva filtros, pesquisa literal, ordenação por ID e paginação no servidor. A página continua limitada a 100, com 25 na interface. Os registos dessa página são a raiz de um percurso das suas referências explícitas; não se consulta todo o cadastro para construir o grafo.
As dependências são deduplicadas por área/ID, consultadas em grupos de até 500 IDs e limitadas ao tenant/empresa e à unidade activa quando aplicável. O direito original de consulta de cada área é conferido antes da leitura. Uma dependência inacessível ou ausente continua a marcar a linha como restrita e a ocultar **toda** a lista de dependências dessa linha, sem divulgar os identificadores inacessíveis. Não há propagação de associações.
A auditoria é lida por área e grupos de até 500 IDs **da página e da sua cadeia de dependências**. O SQL agrega a revisão máxima e o último evento de associação/retirada por módulo. O PHP recebe estados agregados por registo, sem receber o universo de eventos. `module.record.reviewed` avança a revisão, mas não cria uma associação activa nem altera a classificação «sem eventos de associação» dos filtros.
As estruturas de registos, referências, permissões e estados são locais à chamada. O percurso final usa um método recursivo, sem uma closure que se capture a si própria e retenha o grafo até à recolha de ciclos do PHP. Não há cache entre pedidos nem alteração da cache cuja limpeza foi bloqueada.
`preview()`, `snapshot()`, `graph()` e `confirm()` mantêm a leitura actual, as permissões, o contexto, versões, hashes, bloqueios, auditoria e idempotência anteriores. A confirmação não reutiliza a descrição da listagem. Tokens anteriores continuam sujeitos às suas condições originais; a optimização não inventa uma nova autorização ou decisão.
## Protocolo de comparação
A comparação final usa as mesmas fixtures imutáveis por escala, nos mesmos processos/ligação/kernel e na mesma base isolada. São **1 000, 5 000 e 10 000 registos em cada uma das quatro áreas**: clientes, serviços, prestações e rascunhos de facturação. Nesta comparação, os serviços e rascunhos crescem também; por isso os resultados não devem ser confundidos com as cardinalidades menores dessas áreas no primeiro levantamento de carga.
Variantes:
- **A — anterior, sem índices experimentais:** serviço recuperado de `340f3bb` para ficheiro privado de prova, alterando apenas o nome da classe. A API usa um controlador de ensaio com o mesmo kernel, middleware, resposta e serviço anterior. Nenhum percurso de produção carrega essa cópia.
- **B — leitura conjunta, sem índices experimentais:** código funcional desta entrega, na mesma fixture. A ordem A/B alterna entre as três repetições para reduzir viés de ordem/cache.
- **C — leitura conjunta com índices experimentais:** mesma fixture e código B, depois de criar dois índices na transacção da base sintética. O ganho B→C é apresentado separadamente do ganho A→B.
As respostas completas são comparadas por SHA-256 dos bytes JSON, incluindo dependências, versões, associações e revisão. Os IDs/totais/estados esperados também são verificados contra a fixture, com ruído de outro tenant e unidade não seleccionada. Quando A não conclui, não se afirma equivalência dos seus bytes nesse caso: compara-se B/C e verifica-se o resultado esperado da fixture.
PHP 8.4.27, Node fixado 24.22.1 e PostgreSQL no cluster `sgf_modular_regression_2576427d1939`, porta **55439**, base **sgf_tempo_test**, role **sgf_test_runner**. A guarda e identidade são conferidas antes das fixtures/DDL. Não houve ligação à instalação local ou à base persistente 8039. A preparação inteira é sintética e desfeita por rollback.
Há aquecimento, recolha de ciclos antes de cada amostra e três amostras por caso completo. Limites de diagnóstico iguais entre variantes: 3 s por SQL, 15 s por pedido observado entre consultas e 2 500 consultas. Uma amostra limitada é explicitamente marcada; não se extrapola uma mediana, um SLA ou uma latência exacta para pedidos incompletos. Medições incluem kernel/instrumentação; não incluem login, transporte HTTP externo, browser ou concorrência multiutilizador.
## Medições finais comparáveis
Em cada célula: **A / B / C**. Tempos em ms; consultas por pedido; memória incremental máxima usada pelo PHP em KiB. `lim.` significa que não se completaram três amostras nesse perfil; não é uma mediana nem uma medição completa de memória. Os detalhes de cada tentativa, incluindo os pedidos limitados, estão no JSON.
| Registos por área | Área | Página | Tempo A / B / C (ms) | Consultas A / B / C | Memória A / B / C (KiB) |
| ---: | --- | ---: | --- | --- | --- |
| 1000 | Clientes | 25 | 1986,5 / 36,8 / 10,7 | 185 / 11 / 11 | 86,5 / 100,3 / 100,1 |
| 1000 | Clientes | 100 | 7407,4 / 29,8 / 12,9 | 710 / 11 / 11 | 158,6 / 254,4 / 254,2 |
| 1000 | Serviços | 25 | 1924,4 / 30,1 / 10,8 | 185 / 11 / 11 | 86,6 / 99,6 / 99,4 |
| 1000 | Serviços | 100 | 7778,4 / 32,0 / 11,9 | 710 / 11 / 11 | 158,7 / 253,6 / 253,4 |
| 1000 | Prestações | 25 | 3905,9 / 77,2 / 16,6 | 435 / 19 / 19 | 117,0 / 221,4 / 221,2 |
| 1000 | Prestações | 100 | lim. / 77,0 / 22,2 | lim. / 19 / 19 | lim. / 744,6 / 744,5 |
| 1000 | Facturação | 25 | 5014,7 / 96,2 / 19,6 | 560 / 23 / 23 | 131,7 / 294,4 / 294,3 |
| 1000 | Facturação | 100 | lim. / 100,6 / 28,9 | lim. / 23 / 23 | lim. / 1037,2 / 1037,1 |
| 5000 | Clientes | 25 | 6295,4 / 97,2 / 18,5 | 185 / 11 / 11 | 86,8 / 100,3 / 100,1 |
| 5000 | Clientes | 100 | lim. / 87,0 / 19,8 | lim. / 11 / 11 | lim. / 254,6 / 254,5 |
| 5000 | Serviços | 25 | 5238,4 / 92,2 / 17,1 | 185 / 11 / 11 | 86,8 / 100,4 / 100,2 |
| 5000 | Serviços | 100 | lim. / 78,0 / 18,1 | lim. / 11 / 11 | lim. / 254,7 / 254,6 |
| 5000 | Prestações | 25 | 10553,1 / 216,0 / 37,0 | 435 / 19 / 19 | 117,2 / 221,6 / 221,5 |
| 5000 | Prestações | 100 | lim. / 232,9 / 44,4 | lim. / 19 / 19 | lim. / 744,9 / 744,8 |
| 5000 | Facturação | 25 | 13947,3 / 377,2 / 33,7 | 560 / 23 / 23 | 132,3 / 294,4 / 294,3 |
| 5000 | Facturação | 100 | lim. / 322,1 / 65,7 | lim. / 23 / 23 | lim. / 1037,2 / 1037,1 |
| 10000 | Clientes | 25 | 9683,0 / 156,3 / 13,9 | 185 / 11 / 11 | 86,8 / 100,3 / 100,1 |
| 10000 | Clientes | 100 | lim. / 203,1 / 14,5 | lim. / 11 / 11 | lim. / 254,6 / 254,5 |
| 10000 | Serviços | 25 | 9385,2 / 117,2 / 11,7 | 185 / 11 / 11 | 86,6 / 99,6 / 99,4 |
| 10000 | Serviços | 100 | lim. / 109,8 / 14,9 | lim. / 11 / 11 | lim. / 253,6 / 253,4 |
| 10000 | Prestações | 25 | lim. / 333,8 / 20,3 | lim. / 19 / 19 | lim. / 221,0 / 220,9 |
| 10000 | Prestações | 100 | lim. / 399,9 / 26,9 | lim. / 19 / 19 | lim. / 744,3 / 744,1 |
| 10000 | Facturação | 25 | lim. / 592,8 / 28,7 | lim. / 23 / 23 | lim. / 294,0 / 293,9 |
| 10000 | Facturação | 100 | lim. / 451,1 / 35,7 | lim. / 23 / 23 | lim. / 1036,8 / 1036,7 |
A memória incremental da leitura conjunta é maior que a da leitura individual nos casos anteriores completos: é a troca por reter e reutilizar a página/dependências. Em compensação, para o mesmo tamanho de página, mantém-se aproximadamente estável entre 1 000 e 10 000 registos por área: cerca de 100 KiB para 25 clientes, 255 KiB para 100 clientes e 1 037 KiB para 100 rascunhos de facturação. Não se usa a memória total do processo — que inclui todas as fixtures — como se fosse custo exclusivo do pedido.
Na escala de 10 000, os filtros de clientes sem eventos/associados/retirados ficaram em **2 553 / 522 / 1 291 ms** sem índices, e **114 / 255 / 293 ms** com os índices experimentais. Portanto, a queda nas consultas por linha não elimina todos os custos dos filtros e das contagens.
[Amostras completas e métricas](proofs/module-association-optimization-comparison-20261102.json) · [resumo, hashes e verificações](proofs/module-association-optimization-summary-20261102.json).
Foram comparados **33 cenários por variante**: quatro áreas, páginas de 25/100 e três filtros adicionais de clientes, em três escalas. B e C concluíram as três amostras em todos os cenários. A concluiu 20 cenários; 13 atingiram o orçamento de 15 s, sem timeout SQL. No total: **258 pedidos medidos completos e 13 tentativas limitadas**. Os casos completos devolvem bytes JSON iguais entre as variantes comparáveis; todos os casos B/C são iguais entre si e aos resultados esperados da fixture.
As escalas contêm, respectivamente, **22 670 / 113 339 / 226 662 eventos**. A comparação final passou **1 teste / 25 521 asserções**. O resumo inclui os hashes dos JUnit, do serviço anterior e do serviço optimizado; o hash da fonte entregue corresponde ao da medição. A parte da fonte desde `preview()` até `confirm()` foi também comparada com `340f3bb` e permanece igual, desconsiderando apenas a normalização de fins de linha.
## Índices experimentais
Somente na base sintética, dentro de savepoint:
```sql
CREATE INDEX sgf_qa_assoc_links ON identity_audit
(tenant_id,company_id,(details->>'area'),(details->>'record_id'),
(details->>'module_id'),id DESC)
WHERE action IN ('module.record.associated','module.record.disassociated');
CREATE INDEX sgf_qa_assoc_revision ON identity_audit
(tenant_id,company_id,(details->>'area'),(details->>'record_id'),id DESC)
WHERE action IN ('module.record.associated','module.record.disassociated',
'module.record.reviewed');
```
O primeiro foi desenhado para as consultas de associação/retirada; o segundo inclui as revisões sem mudança e a leitura conjunta das revisões. O par é medido em conjunto; não se atribui a cada índice isoladamente a totalidade do ganho. Nos quatro planos capturados após os índices, observou-se o uso de `sgf_qa_assoc_revision`; não se demonstrou aí uma contribuição isolada de `sgf_qa_assoc_links`. O catálogo e os dados anteriores são comparados antes/depois do rollback, e é verificada a ausência destes índices experimentais. **Nenhum destes comandos foi executado no destino**, nem foi criada migração ou concessão para o aplicar.
Os [planos na base sintética](proofs/module-association-optimization-plans-20261102.json) comparam a leitura conjunta antes/depois dos índices numa fixture de 10 000 registos por área. Não exportam bindings ou valores de filtros de documentos. Limites de plano, quando atingidos, são registados no artefacto e não contados como planos completos.
## Testes afectados
**20 testes / 312 asserções**, aprovados na versão funcional final: os 17 casos da fila/navegação e três casos novos. Estes verificam constância das consultas ao aumentar a página com dependências partilhadas, ausência de leitura de cadastros alheios ao grafo, revisões sem associação, múltiplos módulos/retiradas, revogação de consulta entre pedidos, versões novas nas dependências e conflito na confirmação de uma prévia antiga.
Mantêm-se as provas afectadas de isolamento/recusas, geração de contexto, versão desactualizada, recuperação após falha de auditoria e confirmações realmente concorrentes. Não se repetiram as suites de módulos financeiros ou a regressão geral. Não houve alteração React, pelo que o build e controlos de apresentação aceites foram reutilizados; não se declara nova revisão visual.
O ensaio dirigido de planos também passou: **1 teste / 11 asserções**. A primeira comparação completa foi preliminar: depois da revisão de memória, substituiu-se o percurso por closure recursiva pelo método normal e executou-se a comparação novamente sobre a versão final. Só a execução final deve ser usada para as medições desta entrega.
Uma [prova directa de paridade de acessos](proofs/module-association-optimization-access-20261102.json) passou **1 teste / 238 asserções**, antes/depois dos índices sintéticos. O serviço anterior e o novo devolveram as mesmas recusas: 403 para consulta sem administração ou sem consulta própria e unidade não seleccionada, 422 para tamanho inválido e 409 para geração antiga. Depois de revogar a consulta de uma dependência, ambos ocultaram a cadeia inteira e devolveram exactamente a mesma resposta. As concessões desta prova são apenas fixtures transaccionais e foram desfeitas; não são direitos públicos ou configurações reais.
O catálogo de índices e as impressões digitais das oito tabelas anteriores da base de regressão foram conferidos **antes das fixtures e após o rollback de cada escala**, sem alterações. Não se repuseram sequências nem se apagou auditoria: são fixtures novas dentro de transacções, com comparação do estado anteriormente gravado. A prova de paridade e a prova de planos confirmaram também o rollback dos índices.
## Limitações preservadas
A memória de produto cresce com a página e as dependências explicitamente referenciadas, não com o cadastro inteiro. O ensaio usa uma linha por rascunho; não valida o maior fan-out possível de 100 linhas por documento, payloads documentais grandes ou todo o histórico multi-módulo. O PHP ainda conserva os conteúdos dos registos seleccionados durante a descrição; os picos do processo de teste incluem fixtures/kernel. A memória incremental do pedido é apresentada separadamente da memória total.
Os filtros de estado e as contagens continuam no SQL anterior; o ganho da leitura conjunta não significa que todos os seus planos estejam optimizados. A variante C é posterior a A/B e usa buffers quentes; não constitui uma experiência de arranque frio ou prova estatística da contribuição individual de cada índice. As escalas usam a mesma base sucessivamente, com rollback/ANALYZE e sem reconstrução física entre escalas; páginas físicas/cache podem influenciar os valores.
Não há percentis de cauda, throughput, saturação ou capacidade com vários utilizadores validada. Custos de escrita, criação concorrente/recuperação e manutenção de índices exigem decisão/plano próprios antes de implantação. O histórico apresentado continua limitado a 20 eventos recentes, com auditoria integral preservada. Os tokens mantêm validade de 15 minutos.
Os seis registos protegidos, a cache bloqueada e o trabalho alheio permanecem intactos. Não houve decisão real, nova concessão pública, reinício de demonstração, publicação, activação de Compras ou checkpoint neste incremento. Revisão visual e validação da capacidade de implantação continuam separadas.
## Repetição deliberada
Usar as ferramentas fixadas e a cópia de regressão existente. `scripts/modular-regression-run.mjs sync` copia a fonte para essa aplicação, preservando a demonstração persistente. Não executar `prepare`, reset ou PHPUnit na base de 8039/instalação local.
Com `C:/laragon/tools/sgf-tempo/node-v24.22.1-win-arm64/node.exe`:
```text
scripts/module-association-compare.mjs
scripts/module-association-compare.mjs plans
scripts/module-association-compare.mjs access
```
O launcher fixa PHP 8.4.27, confere o destino, recupera a baseline do Git para ficheiro privado e guarda relatório/JUnit fora do repositório. Os testes afectados usam o runner existente com `focused --filter "ModuleAssociationReviewTest|ModuleNavigationTest"`. Não há instrução de aplicar os índices ao destino; essa aplicação exige procedimento e evidência próprios. Esta entrega local não presume aceitação do incremento ou checkpoint.
@@ -0,0 +1,79 @@
# Fila de associações — referências, memória e índices isolados
Seguimento: [leituras concorrentes e confirmação individual](MODULE_ASSOCIATION_CONCURRENCY_REVIEW.md), com quatro identidades sintéticas e preservação dos dados anteriores da base de provas. A evidência adicional não constitui validação da capacidade de implantação ou revisão visual.
02/11/2026. Continuação local da [optimização da fila](MODULE_ASSOCIATION_OPTIMIZATION_DELIVERY.md). Foram tratados dois pontos que permaneciam por avaliar: documentos com **100 linhas** e a contribuição do índice de revisão sozinho versus o par experimental. A avaliação encontrou um custo de memória e originou uma melhoria adicional de código, sem alterar dados do destino.
## Alteração funcional
A fila passa a seleccionar apenas ID/versão, nome da raiz e referências explícitas. Para rascunhos, o PostgreSQL extrai os IDs de serviços das linhas com `WITH ORDINALITY`, preservando a ordem; descrições, preços e restantes conteúdos documentais não são transferidos para a cache de descrição da página. Dependências de clientes/serviços seleccionam apenas ID/versão.
O percurso, a deduplicação, os grupos de até 500 IDs, os filtros, as permissões e a forma da resposta continuam iguais. Os IDs calculados são internos e não acrescentam um campo público à API. Nenhuma associação é inferida ou propagada.
**A projecção só se aplica à listagem.** Prévia e confirmação continuam a carregar e a resumir criptograficamente os registos completos, incluindo conteúdo não apresentado na fila. O código desde `preview()` até `confirm()` continua igual ao de `340f3bb`, após normalizar fins de linha. Alterar conteúdo de uma dependência, mantendo as mesmas referências, continua a invalidar uma conferência anterior.
## Ensaio novo, sem repetir a comparação anterior
Base **sgf_tempo_test**, role **sgf_test_runner**, cluster **sgf_modular_regression_2576427d1939**, porta **55439**, PHP **8.4.27**. Foram reutilizados os resultados válidos anteriores; não se repetiu a matriz de 1 000/5 000/10 000 da primeira optimização, a regressão geral ou o build React.
A nova fixture contém **10 000 registos em cada uma das quatro áreas**. As primeiras 100 prestações e os seus 100 rascunhos de facturação têm 100 linhas, com blocos distintos de serviços: uma página de 100 referencia 10 000 serviços. Uma prestação apresenta 101 dependências; um rascunho de facturação, 102. Foram ensaiadas páginas de 25/100 e descrições sintéticas de **128 e 1 000 bytes por linha**.
As quatro variantes usam a mesma fixture por perfil: código anterior à projecção sem índices; projecção sem índices; projecção com índice de revisão; projecção com o par. A fonte anterior foi preservada antes da alteração, fora da raiz web, alterando apenas o nome da classe para a prova. O launcher verifica a integridade da cópia; os hashes original/final constam do resumo. Não se trata de um segundo percurso de produção.
São três amostras quentes e sequenciais por cenário, com recolha de ciclos PHP antes da medição e os mesmos limites diagnósticos: 3 s por SQL, 15 s observados entre consultas, 250 consultas e 192 MiB de memória PHP usada observada entre consultas. A configuração PHP existente é 512M e não foi alterada. Estes limites não são SLA ou quotas de produção.
## Memória incremental por pedido
Máximo observado nas três amostras, em **MiB**, excluindo a memória já usada pelo kernel e pela fixture. A comparação abaixo é sem índices, na mesma fixture antes/depois da projecção.
| Descrição por linha | Área | Página | Antes | Depois |
| ---: | --- | ---: | ---: | ---: |
| 128 bytes | Prestações | 25 | 6,13 | 4,21 |
| 128 bytes | Prestações | 100 | 24,11 | 16,65 |
| 128 bytes | Facturação | 25 | 7,34 | 4,85 |
| 128 bytes | Facturação | 100 | 28,98 | 19,23 |
| 1 000 bytes | Prestações | 25 | 8,28 | 4,21 |
| 1 000 bytes | Prestações | 100 | 32,42 | 16,65 |
| 1 000 bytes | Facturação | 25 | 11,55 | 4,85 |
| 1 000 bytes | Facturação | 100 | **45,49** | **19,23** |
No caso mais pesado, a redução foi de aproximadamente **58%**. A memória após a projecção deixou de crescer com as descrições destes perfis, mas continua a crescer com o número de dependências que a página tem de apresentar. Não se deve aplicar a estimativa anterior de cerca de 1 MiB, obtida com uma linha por rascunho, ao cenário de 100 linhas.
As consultas PDO mantiveram-se iguais antes/depois da projecção: prestações **27/57** e facturação **31/61**, para páginas de 25/100. O crescimento em relação à prova de uma linha deve-se aos grupos necessários para 2 500/10 000 serviços distintos, não a uma consulta por linha. As respostas de 100 registos ficaram perto de **0,79–0,80 MB**, sem descrições documentais e sem diferenças de bytes entre as variantes de cada perfil.
## Tempos e contribuição dos índices
Medianas em ms, descrições de 1 000 bytes por linha:
| Área / página | Antes, sem índices | Projecção, sem índices | Só revisão | Par experimental |
| --- | ---: | ---: | ---: | ---: |
| Prestações / 25 | 668 | 729 | 97 | 226 |
| Prestações / 100 | 2 151 | 2 862 | 341 | 408 |
| Facturação / 25 | 815 | 905 | 112 | 127 |
| Facturação / 100 | 2 721 | 2 481 | 374 | 368 |
O benefício demonstrado da projecção é a memória e o menor conteúdo transportado para o PHP. **Não acelerou todos os casos sem índices**; houve também aumentos de latência, por exemplo nas prestações de 100. As fases têm ordem fixa e o cluster é partilhado com outra base sintética, pelo que três amostras não permitem atribuir toda a variação à alteração de código.
Na condição de 128 bytes, os filtros de clientes sem eventos/associados/retirados ficaram em **109/219/262 ms** com o índice de revisão e **117/235/278 ms** com o par. O segundo índice apareceu nos planos de associados/retirados, mas **não mostrou ganho consistente que justifique recomendá-lo por estes dados**. Isso não demonstra que seja inútil em todas as distribuições de histórico.
O índice de revisão ocupou **14 401 536 bytes (13,73 MiB)**; o segundo acrescentou **17 580 032 bytes (16,77 MiB)**. O par totalizou cerca de **30,50 MiB**. Na primeira condição, criação + `ANALYZE` demoraram cerca de 1,02 s para revisão e 1,84 s para o par. Não são tempos de implantação real nem incluem criação concorrente, carga de escrita ou recuperação.
Para um futuro plano de implantação, o índice de revisão sozinho é o candidato mais parcimonioso a aprofundar. **Não foi aplicado no destino**. Todos os índices desta prova foram criados em savepoints na base sintética e desfeitos por rollback.
## Testes e preservação
- **21 testes / 322 asserções** afectados, aprovados. O novo caso verifica a ordem das referências, deduplicação, ausência do corpo/alias interno na resposta e recusa de confirmação após alteração apenas do conteúdo de uma dependência. Os casos anteriores continuam a verificar permissões, isolamento, versões, concorrência e recuperação.
- **1 ensaio / 25 499 asserções**: 44 cenários, **132 pedidos medidos completos**, sem limites atingidos; respostas completas idênticas entre as quatro variantes em cada perfil. As descrições marcadas da fixture não aparecem na resposta administrativa.
- Impressões digitais das oito tabelas antecedentes e catálogo de índices iguais antes das fixtures/depois do rollback. As sequências não foram repostas. As fixtures do ensaio de 132 pedidos foram desfeitas por rollback, preservando o estado que já existia na base de provas.
[Medições finais](proofs/module-association-projection-fanout-20261102.json) · [resumo, hashes e testes](proofs/module-association-projection-summary-20261102.json) · [diagnóstico inicial que revelou o custo de memória](proofs/module-association-fanout-20261102.json).
O código, os testes afectados e o novo ensaio são locais. Os seis registos protegidos, a cache bloqueada, as alterações alheias e as demonstrações permanecem intactos. Não houve ligação à instalação local/8039, decisão real, concessão pública, publicação, activação de Compras ou novo checkpoint.
## Limitações e repetição
Não se declara validada a capacidade de implantação: não foram medidos utilizadores simultâneos, percentis de cauda, saturação, custo de escrita, implantação/recuperação de índices ou todas as distribuições multi-módulo. Os textos são repetitivos e sintéticos, abaixo do limite de 2 000 caracteres por descrição; não representam todos os payloads. A memória reportada não é a memória PostgreSQL nem uma estimativa por utilizador concorrente.
A resposta e o número de dependências cresceram: 100 rascunhos podem apresentar mais de 10 000 nós. Não se mediu o custo de renderização desse volume no navegador. **Revisão visual permanece separada**, sem tentativa pela via bloqueada.
O launcher fixado aceita `scripts/module-association-compare.mjs fanout`, depois do `sync` da cópia de regressão existente. Requer a fonte anterior e o respectivo hash preservados no directório privado da execução, cuja integridade verifica; não substitui automaticamente essa referência. Não executar `prepare`, reset ou testes na demonstração persistente. Não existe instrução de aplicar índices ao destino. A aceitação deste incremento e um checkpoint continuam a depender de decisão expressa.
+42
View File
@@ -0,0 +1,42 @@
# Devolução de excedente: percurso nativo e observação SGF
02/11/2026 — `NATIVE-WAREHOUSE-UNUSED-RETURN-SIM-v1`. Implementação local sintética, continuação de [Oficina e Stock](WORKSHOP_MATERIAL_CYCLE.md). Código funcional e interface implementados; sem aceitação, checkpoint, publicação ou activação presumidos.
## Percurso implementado
No SGC autónomo, seleccionar uma linha de entrega interna já autorizada, entregue e recebida pelo requisitante. Reutilizam-se artigo, unidade, armazém, documento e fotografias da origem. O destinatário original declara individualmente a quantidade não utilizada e apresenta fundamento/evidência. A preparação mostra a entrega ainda não devolvida e o saldo físico antes/depois; não escolhe uma origem automaticamente.
Outra identidade com competência de armazém confirma a recepção física e apresenta fundamento. O servidor volta a conferir contexto, competências vigentes, identidade, versão, origem, cadastro, livro e quantidade disponível. Uma alteração exige nova proposta. A mudança de unidade é recusada, sem conversão implícita. O preparador pode retirar a proposta e o armazém pode recusá-la; ambas as decisões são imutáveis e não movimentam stock.
Decisão, operação, movimento e auditoria ficam na mesma transacção. O escritor comum `packages/inventory-return` é o mesmo artefacto imutável já ensaiado em SGF, com manifesto SHA-256 `2850a4f5cb678acfe3a9dbc7a7d62eb233bc72722ad0de374681c2679c90557c`. O SGC verifica os ficheiros locais; não depende do servidor ou repositório SGF para funcionar. Não existe segundo saldo. A sinalização de reposição reutiliza `AutomaticPurchases`, uma vez após a decisão dentro da transacção; não aprova nem encomenda por arrasto.
O percurso nativo comprovado é **recepção efectiva 10 → entrega efectiva 5 → saldo 5 → devolução física 3 → saldo 8**, com três movimentos. A observação SGF lê o mesmo movimento por identidade SQL restrita, sem escrita ou cópia local. Esta prova não constitui instalação de um ERP completo nem associação a consumos técnicos SGF. No percurso nativo, “não utilizado” é declaração explícita do destinatário; no percurso de Oficina anterior existem origens verificadas e limites por consumo associado. Não se confundem as duas autoridades.
## Acesso e interface
Direitos novos, configuráveis nos mecanismos existentes: `warehouse_return_read`, `warehouse_return_prepare`, `warehouse_return_confirm`. Preparação exige o destinatário original; confirmação/recusa exige também `warehouse` e identidade distinta. Não há concessão implícita por administrador ou nome de pessoa. Foram atribuídos somente a identidades da base QA isolada; não há concessões reais ou em demonstrações. `config/stock_returns.php` mantém `enabled=false`.
Página `/stock/devolucoes-internas`, ligações condicionais na requisição e no histórico de operações, selecção explícita da origem, declarações e fundamento, prévia, retirada, recusa e confirmação. Histórico paginado no servidor, 25 por página, filtros por estado mais recente e consulta conjunta dos preparadores. A página de 25 numa fixture de 51 propostas fez três SELECTs centrais a `supply_records`; não é uma medição de capacidade.
## Provas consolidadas
[Relatório verificável](proofs/native-warehouse-return-20261102.json), gerado por `scripts/summarize-native-warehouse-return.mjs`: **36 testes distintos / 544 asserções**. São 18 casos nativos (420), um caso adicional da fronteira histórica (20), 16 casos afectados de reversão (81) e um observador SGF (23). Ensaios sobrepostos não foram somados nem repetidos sem necessidade. Os 22/820 anteriores de Oficina permanecem provas separadas.
- Isolamento, acesso indevido, manutenção, expiração, contextos Compras/Pessoas, versões, alteração da origem e declaração física ausente.
- Duas confirmações da mesma proposta: após libertar o bloqueio de empresa, a segunda devolve o resultado original, com um movimento. Duas devoluções de 3 contra entrega de 5: uma confirma e a outra recusa 409.
- Retirada versus confirmação nas duas ordens de bloqueio: uma só decisão terminal. Sem duplicação ou reabertura.
- HTTP real do kernel: bloqueio observado por `pg_blocking_pids`; limite local de dois segundos resulta em **423 `warehouse_return_busy`**, sem efeito parcial. Nova tentativa explícita após libertação termina correctamente.
- Falha após criação do movimento: rollback integral e recuperação sem duplicação. Artefacto indisponível/corrompido somente na cópia privada: 503 e recuperação após reposição dos mesmos bytes.
- Reversão integral da saída após devolução parcial recusada, evitando crédito duplo. Históricos de stock incluem os metadados exigidos pelo componente de apresentação.
Tipos das três páginas e bundle dirigido passaram. PHPStan dirigido às três classes novas passou sem erros. Renderização no servidor dos dados HTTP efectivos do histórico passou. O build integral de assets da cópia QA passou com configuração qualificada: fontes remotas e React Compiler opcional omitidos; não valida o build optimizado predefinido. A primeira tentativa desse build predefinido ficou sem progresso e foi interrompida apenas no processo próprio. Não houve navegador nem revisão visual.
O observador SGF reutiliza uma fixture anterior arquivada pelo hash; os testes nativos seguintes usam novas empresas sintéticas. Uma consulta posterior, em modo só de leitura e com a mesma identidade limitada, confirma os três movimentos, saldo 8 e movimento de devolução original. As permissões temporárias SGF e a constraint foram restauradas. Perfis QA nativos permanecem apenas na base própria para reprodução. Provas anteriores da fila e do leitor de stock mantêm os hashes; não houve novo benchmark desses percursos inalterados.
## Fronteiras ainda abertas
O histórico de planeamento mantém a convenção existente de **saídas brutas `issue`**. No cenário 5 entregues/3 devolvidas, o saldo passa 5→8 e o hash da análise muda, mas o consumo histórico continua 5. A regressão comprova esta diferença; não foi implementada previsão por consumo líquido, nem reescrita de análises aprovadas. Uma futura regra líquida terá de especificar a atribuição temporal da devolução e a revisão de períodos, em vez de deduzir indiscriminadamente do dia da recepção.
Só entregas internas sem lotes, reservas, equipamento/peça, qualidade ou quarentena. Sem compensação de material consumido, correcção de devolução confirmada ou conversão de unidade. A composição operacional instalada, carga de escrita/implantação e revisão visual continuam pendências separadas. O teste demonstra o fluxo e as recusas nas condições sintéticas; não valida capacidade de implantação.
Os seis registos protegidos, cache bloqueada, demonstrações, dados/acessos reais, checkpoints e trabalho alheio foram preservados. Sem novos pagamentos, contabilidade, activação de Compras ou publicação.
+81
View File
@@ -0,0 +1,81 @@
# Decisão de instalação da integração de requisições no SGF
Data: **02/11/2026**. Estado: **proposta para decisão; instalação não autorizada nem executada**.
## Recomendação concreta
**Não confirmar ainda a instalação desta candidata como percurso operacional.** Os mecanismos e provas isoladas permanecem válidos, mas a conferência do destino revelou lacunas de implantação que esses ensaios com roles proprietárias e cadastros sintéticos não cobriam: ligação de migração/privilégios SQL da aplicação e preparação operacional de centros/dotações pela interface.
A operação futura proposta é **instalação técnica de schema e código, inicialmente desactivada**, no destino abaixo, sem outorga automática de direitos, sem dados de Compras e sem mudar o pacote activo 0.1.1. Antes de pedir a confirmação dessa operação, fechar o plano de privilégios e de recuperação do destino. A disponibilização aos utilizadores exige ainda resolver o cadastro/orçamento e a configuração nominativa. Não há autorização para executar `migrate`, `apply`, `cache`, concessões, manutenção ou paragem/reinício de serviços nesta decisão.
## Destino conferido, não uma instalação genérica
| Elemento | Valor |
| --- | --- |
| Projecto SGF local | `C:\laragon\www\sgf-tempo` |
| URL configurada | `http://127.0.0.1:8000` — não é publicação num domínio |
| Ambiente/PHP | `local`; PHP **8.4.27** pelo wrapper do SGF |
| Base efectiva | PostgreSQL **`sgf_tempo_dev`**, `127.0.0.1:55432` |
| Role da aplicação | `sgf_dev_app` — sem CREATE no schema public e sem autoridade para ALTER em permission_grants |
| Proprietário existente da tabela de permissões | `sgf_dev_owner` — LOGIN e CREATE em public confirmados; credenciais não consultadas nem registadas |
| Estado anterior | 87 tabelas public; fundação de identidade presente; nenhum `cb_*`, `ir_*` ou `sgc_installations` da candidata |
| Configuração de integração | Bundle/ficheiro operacional ausentes; manutenção inactiva; configuração Laravel não compilada no instante da leitura |
| Pacote instalado de Compras | **0.1.1**, ponteiro SHA-256 `81899e531e9eec449717e694d8bdc106a9e220a828f5491ce918c1d2dc612787` |
| Revisão Git SGF observada | `fcf0ada22701337acd4c84b404207b8400f490a2`; não substitui a conferência dos ficheiros locais em curso |
Inventário por **transacção PostgreSQL READ ONLY**, sem migrar: [prova da decisão](proofs/sgf-installation-decision-inventory.json). As contagens/impressões digitais preservadas incluem 89 concessões, duas pertenças e 162 eventos de auditoria. Há uma empresa, uma unidade e **uma concessão de administração da empresa**; não foram enumerados nomes, emails ou credenciais. A base `sgf_tempo_test`, a instância modular isolada em 8039/cluster 55439 e as demonstrações anteriores não são este destino e não podem ser reiniciadas/resetadas por arrasto.
O registo antigo de processo web não foi tomado como confirmação de processo actualmente activo. Na janela futura, conferir o PID/executável/instante de arranque e vinculação ao projecto antes de actuar. **Não usar `sgf.ps1 stop` indiscriminadamente**: esse comando também pára o cluster PostgreSQL 55432, partilhado com outras bases.
## Candidata exacta e planos de leitura
| Referência | Valor |
| --- | --- |
| Identidade da candidata | **`OPERATIONAL-CANDIDATE-5fae7cf7f99c42ba`** — versão identificada por conteúdo, não 0.1.2 |
| Directório | `C:\laragon\www\compras\storage\app\private\candidates\OPERATIONAL-CANDIDATE-5fae7cf7f99c42ba` |
| ZIP | `C:\laragon\www\compras\storage\app\private\candidate-archives\OPERATIONAL-CANDIDATE-5fae7cf7f99c42ba.zip` |
| SHA-256 ZIP, reconferido | `d14a3261d5aaab80f96250af781c700ab53376021f4638e3aee43c15ff37ceed` |
| SHA-256 manifesto | `b1ec47f7a9ad87e0b232bac41e402d4a00ee5f03f00a79b93effc692ce8b39a2` |
| Impressão de destino do plano de código | `bab719ee4e08555a8e1de694dd3a93df82680c7aba653613f0714dd76e4065d6` |
| Impressão de destino do plano de schema | `169e6e863f28b67740f07b6e7cbc664fbe585a7760a83dccebc8d482ad8ab792` |
| ID previsto de primeira aplicação | `b1ec47f7a9ad87e0b232bac4` — reconfirmar no retorno real da CLI |
Os dois comandos `plan` passaram no destino e só leram/conferiram estado. Isso **não executa nem valida a capacidade de escrever DDL com a role runtime**, e `schema_prepared=false`. Os hashes são uma fotografia: repetir os planos de leitura imediatamente antes de uma operação aprovada; divergência impede usar esta decisão antiga como autorização para sobrescrever o destino.
## Alterações previstas, sem efeitos já aplicados
**Código:** criar o bundle local `packages/internal-requisitions`; aplicar sobreposições conferidas apenas a `Permissions.php`, `IdentityWorkflow.php`, `BudgetAdapter.php`, `AppServiceProvider.php` e `ModuleNavigation.php`. Guardar backups/journal em `storage/app/private/module-deployments`; tratar os caches padrão. Preservar restantes ficheiros/trabalho local. Não alterar `packages/purchasing/current.json`, activar 0.1.2, publicar ou copiar a base de Compras.
**Schema, revisão 1:** acrescentar **14 tabelas**: sete `cb_*` (`centres`, `origins`, `budgets`, `budget_entries`, `budget_consumptions`, `budget_reinforcements`, `audit`), seis `ir_*` (`requests`, `steps`, `events`, `commands`, `policies`, `policy_versions`) e `sgc_installations`. Sem dados sintéticos iniciais. Alargar `permission_grants.permission` de 40 para 100 e estender o CHECK unitário com os novos valores, preservando a expressão e os registos anteriores. Acrescentar FKs, unicidade e triggers de origem/versão/aprovação independente/histórico imutável. Os dados e decisões existentes não são classificados nem reescritos. **A migração 46 de Compras não é aplicada no SGF.**
**Permissões funcionais:** o catálogo candidato acrescenta seis direitos de requisição (`view`, `prepare`, `configure`, `approve.department_head`, `approve.procurement`, `approve.finance`) e os sete direitos do orçamento comum já desenvolvido. A criação de unidades continua a conceder apenas `unit.view`/`unit.edit`. Instalar o catálogo **não concede** nenhum novo direito a administradores, perfis de desenvolvimento ou outros utilizadores. A atribuição inicial nominativa e auditada exige âmbito habilitado explicitamente; as seguintes usam a administração nativa. Requerente e decisores continuam a exigir identidades distintas. A concessão de `purchasing_budget.record` é necessária para reserva/libertação, sem substituir a autorização de requisição.
**Privilégios PostgreSQL:** são outra camada. `sgf_dev_app` não deve receber CREATE, ownership ou a palavra-passe do proprietário. A execução de DDL exige a ligação de migração autorizada (`sgf_dev_owner` ou principal autorizado equivalente), só nessa execução e sem reescrever `.env` com credenciais privilegiadas. Depois, a aplicação precisa dos privilégios mínimos nas novas tabelas/sequências. **O instalador desta candidata não entrega esses GRANTs à role runtime**; as provas anteriores usaram role proprietária nas bases descartáveis. Falta fechar/ensaiar esse mapa com as duas roles separadas. O plano deve permitir leitura do registo de instalação, operações de requisição/política, append-only do histórico, reserva/auditoria e locks orçamentais necessários, sem UPDATE/DELETE sobre históricos ou grants genéricos sobre todo o schema. Nenhum GRANT é executado nesta análise.
## Bloqueantes e elementos fora do âmbito
| Questão | Classificação e impacto |
| --- | --- |
| Ligação de migração e privilégios SQL runtime | **Bloqueante para executar a instalação tal como está com a ligação normal.** A ligação actual não pode executar o DDL. Definir execução migradora e mapa mínimo de acesso a tabelas/sequências, preservar o runtime restrito e ensaiar a separação antes de aplicação. |
| Centros e dotações de orçamento em instalação vazia | **Bloqueante para disponibilizar o percurso básico neste destino.** Não existem `cb_*`; o formulário candidato só selecciona centros existentes e a configuração exige pelo menos um. Não há no percurso entregue cadastro/associação inicial de centros pela interface. Os ensaios prepararam essas fontes e a dotação aprovada por fixtures; não importar fixtures nem criar SQL manual como configuração comercial. |
| Interface orçamental SGF existente | **Bloqueante para a preparação operacional pela interface sem correcção.** `BudgetWorkspace` consulta `cb_ui_commands` e `cb_consumption_sources`, ausentes no destino e no schema de 14 tabelas. A reserva pelo motor comum foi ensaiada; isso não declara entregue o bootstrap administrativo/orçamental completo. Não ampliar consumo/facturas por arrasto: integrar o recorte necessário ou manter esse percurso fechado até completar a sua composição. |
| Catálogo administrativo de permissões | **Implementado e testado na candidata; ainda não instalado.** No destino, `Permissions::UNIT` continua só com dois direitos. Aplicar a sobreposição resolve a presença/gestão dos novos nomes; não resolve sozinho DCL PostgreSQL, centros/dotações ou atribuições nominativas. Não classificar como falta de implementação do catálogo nem como acessos já configurados. |
| Duas administrações nominativas | **Pendente para entrega/activação**, não condição para copiar código desactivado. O destino tem uma concessão `access.manage`; a regra da entrega exige duas administrações permanentes da empresa. Não criar conta/perfil ou outorgar direitos automaticamente para satisfazer a contagem. |
| Âmbito/configuração e dotação reais | **Pendente para activação:** seleccionar empresa/unidade, centros/fontes, intervenientes, política/limites, responsáveis e dotação aprovada pelas regras usuais. Não retirar a exigência de orçamento para contornar a falta de preparação. |
| Equipamentos/peças | **Fora do âmbito deste percurso básico.** Não impedem consumíveis, serviços e outros de completar requisição/submissão/aprovação/consulta quando as dependências acima estiverem preparadas. Equipamentos/peças não têm o seu percurso técnico SGF entregue; não os registar como `other` para contornar isso. |
| Navegação modular | **Tecnicamente aceite em 02/11/2026** na entrega própria. Não é bloqueante técnico da candidata. Revisão visual/recargas, associações antigas e volume/paginação mantêm o âmbito separado dessa aceitação. Não repetir as suites para resolver a instalação. |
## Backup, restauro e recuperação — procedimento proposto, não executado
1. **Antes de qualquer escrita aprovada:** reconferir raiz, URL/base/roles, hashes e estado dos ficheiros/contas/auditoria. Guardar o código/configuração anterior e documentos/ficheiros externos. Reservar directório privado por execução em `C:\laragon\data\sgf-tempo\backups\purchasing\<data-id>`, fora da raiz pública e sem sobrescrever backups anteriores. O backup de configuração pode conter segredos; não o distribuir com o ZIP.
2. **Backup integral apenas de `sgf_tempo_dev`:** PostgreSQL 17 `pg_dump --format=custom` com host `127.0.0.1`, porta `55432`, ligação autorizada e ficheiro privado. Registar hash, instante de corte, código/manifesto/schema, inventário das 87 tabelas e ACLs/roles pertinentes. Credenciais por mecanismo privado como PGPASSFILE; nunca nos argumentos/logs. Não parar o cluster inteiro nem exportar/substituir outras bases.
3. **Restauro para base nova vazia:** criar `sgf_tempo_dev_restore_<id>` pelo procedimento DBA autorizado, restaurar o dump e conferir dados, documentos externos, tabelas, constraints/triggers, ACLs, contagens/digests de acessos/pertenças/auditoria e arranque com roles distintas. Os ensaios anteriores provaram restauro isolado, mas **não substituem o ensaio desta base e dos seus privilégios**. `pg_restore --list` só lê o índice. Se usar `--no-owner --no-privileges`, repor/validar explicitamente as ownerships/ACLs, incluindo CONNECT/USAGE, antes de ligar o runtime. Não converter o runtime em proprietário para fazer o ensaio passar.
4. **Janela de aplicação, só depois dos bloqueantes e da confirmação:** manutenção, parar apenas serviços de escrita desse projecto; preparar schema pela ligação migradora; aplicar o mapa SQL aprovado; conferir preservação. Aplicar código e compilar caches pelas CLIs aprovadas, com destino/manifesto reconferidos. Não outorgar direitos funcionais, habilitar âmbitos ou abrir o módulo por arrasto. Reiniciar/conferir serviços próprios mantendo o acesso fechado até decisão de activação.
5. **Falha de schema antes do commit:** rollback transaccional e conferência com o inventário anterior. Se a ligação se perder durante o commit, inspeccionar revisão/schema antes de repetir. Não executar migrações `down` ou apagar histórico para forçar retry.
6. **Falha de código/aplicação parcial:** manter serviços parados/manutenção; `sgf-code-deploy.php rollback` para o ID devolvido/registado; conferir backups/hashes. A rotina repõe ficheiros/bundle anterior, recusa alterações locais e não reverte dados/schema/concessões. Depois de cache nativo recompilado, invalida-o; executar `cache` para a versão reposta, quando houver bundle anterior, e reiniciar/conferir antes de reabrir. Na primeira instalação, voltar ao host sem bundle não cria uma versão anterior de requisições. O ponteiro 0.1.1 continua preservado.
7. **Corrupção ou incompatibilidade de dados/schema:** preservar também o estado que falhou; restaurar para outra base, nunca por cima da base activa. Reconciliar operações posteriores ao backup, configurações e revogações para não perder decisões ou reabrir direitos. Só trocar a ligação da aplicação após conferência e decisão registada; uma base restaurada com outro nome requer nova impressão de destino operacional e caches recompilados. Conservar a base anterior para diagnóstico. Rollback de código não é restauro de dados.
Os comandos parametrizados e contratos das CLIs estão em [transferencia-sgf.md](PURCHASING_UPDATES_DELIVERY.md). **Não pedir confirmação para executar um procedimento ainda incompleto:** primeiro resolver os bloqueantes identificados, actualizar/ensaiar a candidata e apresentar os novos hashes se houver alteração. O ZIP actual permanece imutável e disponível como evidência, não aprovado para implantação operacional.
Actualiza??o de 02/11/2026: a proposta desactivada anterior foi substitu?da pela candidata utiliz?vel 401ce31ae5f2dd20, ainda N?O instalada. Fonte vinculativa actual: C:/laragon/www/sgf-tempo/docs/PURCHASING_INSTALLATION_PROPOSAL.md. Mant?m-se 0.1.1, aus?ncia de concess?es e decis?o posterior de instala??o/configura??o.
+148
View File
@@ -0,0 +1,148 @@
# SGF-IR-USABLE-401C-20261102 — proposta final sintética
**Estado: proposta para uma confirmação; NÃO executada.** Esta revisão substitui o destino/configuração da proposta anterior. A confirmação antiga 5fae não se aplica. Não instalar em sgf_tempo_dev nem alterar a demonstração 8039. O arquivo PURCHASING_INSTALLATION_PROPOSAL_401C_PRE_SYNTHETIC.md é histórico e não deve ser executado.
## Destino único proposto
| Elemento | Valor |
| --- | --- |
| Aplicação SGF de desenvolvimento | `C:/laragon/data/sgf-tempo/run/ir-usable-401c-20261102/app` |
| Ambiente / HTTP | `local`, `http://127.0.0.1:8041`, só loopback |
| Cluster PostgreSQL novo | `sgf_ir_401c_20261102`, dados em `C:/laragon/data/sgf-tempo/run/ir-usable-401c-20261102/postgres`, loopback **55441** |
| Base nova | `sgf_ir_dev_401c_20261102` |
| Migrador / runtime novos | `sgf_ir_owner_401c` / `sgf_ir_app_401c` |
| Credenciais | Novas, aleatórias e privadas fora do Git/raiz web; não alterar nem divulgar credenciais existentes |
| Backups privados | `C:/laragon/data/sgf-tempo/backups/SGF-IR-USABLE-401C-20261102` |
| Bundle na cópia | `packages/internal-requisitions` |
| Versão instalada de Compras | **0.1.1**, antes/depois, em original e cópia; candidata operacional separada |
A base real contém dados/configuração da Tempo e não é o destino desta operação. A instância sintética existente em 8039 já permite separação de empresas/unidades, mas a sua role é proprietária de users/permission_grants e tem CREATE no schema. Para preservar essa demonstração e garantir runtime sem propriedade/DDL, propõe-se nova base e cluster, sem alterar a role existente. Portas/pastas/nomes devem estar livres; se houver conflito, parar e rever a proposta, não escolher outro destino silenciosamente.
Fonte exclusivamente sintética: aplicação `C:/laragon/data/sgf-tempo/run/modular-regression-2576427d1939/development-app`, base `sgf_modules_dev_2576427d1939`, cluster 55439. Cópia consistente dos seus dados sintéticos com pg_dump e restauro sem owner/ACL no novo cluster; sem copiar linhas da Tempo ou de sgf_tempo_dev. Não copiar sessões, cookies, caches, credenciais, logs ou uploads indiscriminadamente. APP_KEY, cookie, storage e caches próprios; outbound mail/integrações externas desligados. Não arrancar workers/scheduler nem efectuar operações reais.
## Candidata e integridade
- Candidata: **OPERATIONAL-CANDIDATE-401ce31ae5f2dd20**, formato tempo.operational-review.v1, schema **revisão 2**. Não é release comercial 0.1.2.
- ZIP: `C:/laragon/www/compras/storage/app/private/candidate-archives/OPERATIONAL-CANDIDATE-401ce31ae5f2dd20.zip`.
- SHA-256 ZIP: `59dbdc64c4d9f14dfb4025a6177b829d136a4e2cb633ca036b10b5ae3197e703`.
- SHA-256 manifesto: `a6478223e17a5430652f0fcbf31a44a931ae2a99cd90b151c98d2df5df43c10b`.
- SHA-256 migração: `4ca4f5827c46e5ca29cb329c667df0b996ecbf5e318c0b157091c94e9d44ae92`.
Artefacto permanece inalterado. Os nove ficheiros de baseline da candidata foram conferidos por leitura na aplicação sintética existente: todos compatíveis. O código funcional modular continua identificado por **2a4169162bb4621a42a2ea1df627d52f860e7176**; fcf0ada é documental. Preservar seis módulos, Início e Opções gerais/configuração separados.
Na cópia nova, a identidade exacta da guarda TestingDatabaseGuard será adaptada de 55439/base/role antigas para 55441/base/role novas, sem aceitar curingas ou remover verificações. Registar hashes antes/depois; não adaptar guardas do original ou dos demais serviços para lhes abrir capacidades. Perfil de descoberta continua sintético, por user:tenant:company, sem conceder operações. Os antigos hashes de plano destinados a sgf_tempo_dev NÃO se aplicam: calcular novos planos vinculados à cópia/base exactas depois do provisionamento e antes de migrar; conferir destino, baseline e manifesto, sem trocar os hashes do artefacto.
## Contexto e valores de teste — todos sintéticos
Reutilizar, somente na cópia, o tenant **1** «Cliente de demonstração», empresa **1** «Empresa Horizonte — Demonstração» e unidade **1** «Unidade Central — Demonstração». Estes IDs são locais à base sintética, não identificam a Tempo. Preservar as empresas/unidades alternativas para testes de recusa; não lhes activar Compras internas.
| Configuração | Valor exacto proposto |
| --- | --- |
| Centro novo | `SYN-IR-401C`, exclusivamente empresa/unidade 1/1 |
| Departamento | `SYN-OPER`, centro e intervenientes associados explicitamente |
| Dotação | **50 000,00 MZN**, exercício **2026**, natureza `operating`, **inclui imposto** |
| Preparação / aprovação da dotação | Preparador sintético #1 / Revisor sintético #2, identidades distintas |
| Política inicial | Versão 1, enabled=true, budget_required=true, approval_includes_tax=true |
| Primeiro limite | **10 000,00 MZN** = 1 000 000 unidades menores |
| Segundo limite | **20 000,00 MZN** = 2 000 000 unidades menores |
| Motivo | «SINTÉTICO SGF-IR-401C — exercício de desenvolvimento; sem validade orçamental empresarial» |
Até 10 000 inclusive: responsável de departamento. Acima de 10 000 até 20 000 inclusive: departamento e Compras. Acima de 20 000: departamento, Compras e Financeiro, nessa ordem, por três aprovadores distintos e distintos do requerente. Sem auto-aprovação ou repetição do aprovador entre etapas. Nenhum limite representa uma decisão da Tempo.
O campo técnico rules_provisional é gravado como false pelo circuito existente ao guardar a política; significa configuração explícita desta política de teste, NÃO aprovação empresarial/fiscal real. Não alterar o motor ou inventar um valor não suportado para esse campo.
Exemplo de requisição: consumível 2 UN × 50,00 com imposto sintético de 16% = 116,00; serviço 1 UN × 25,00 a 0% = 25,00; outro 1 UN × 10,00 a 0% = 10,00. Base 135,00, imposto 16,00, total/reserva **151,00 MZN**, saldo disponível **49 849,00 MZN**. A taxa é um dado de ensaio, sem conclusão fiscal. Data pretendida: data local da execução +10 dias, registada na evidência. Equipamentos/peças rejeitados; não disfarçar como outros.
## Identidades e concessões exactas
Reutilizar #1 `gestor-modular-f40d500a09@example.test` (Desenvolvimento — Preparador), #2 `consulta-modular-f40d500a09@example.test` (Desenvolvimento — Revisor) e #3 `limitado-modular-f40d500a09@example.test` (Desenvolvimento — Consulta), preservando os seus direitos prévios na cópia. A origem e as contas reais permanecem intactas. #1 já possui access.manage no cenário modular; não remover esse direito histórico, mas não usá-lo como autoridade administrativa deste incremento.
Criar apenas na base nova três contas sintéticas: `admin-ir-401c@example.test`, `compras-ir-401c@example.test`, `financeiro-ir-401c@example.test`. IDs gerados serão registados e conferidos, não presumidos como 4/5/6. Senhas novas privadas, distintas; sem entrega em relatório. Cada conta nova: pertença só ao tenant/empresa 1/1, company.view nessa empresa e unit.view só na unidade 1. Administrador novo recebe também access.manage na empresa 1; as restantes contas novas não recebem administração.
Na tabela, R significa purchasing_requisitions e B significa purchasing_budget. Todas as concessões novas R/B são unitárias no âmbito **1:1:1**:
| Identidade | Direitos novos exactos |
| --- | --- |
| Preparador #1 | R.view, R.prepare; B.view, B.create, B.record |
| Revisor #2 / responsável de departamento | R.view, R.approve.department_head; B.view, B.approve, B.record |
| Consulta #3 | R.view, B.view |
| Compras novo | R.view, R.approve.procurement; B.view, B.record |
| Financeiro novo | R.view, R.approve.finance; B.view, B.record |
| Administrador novo | R.view, R.prepare, R.configure, R.approve.department_head, R.approve.procurement, R.approve.finance; B.view, B.create, B.approve, B.record |
Administrador recebe estes dez direitos porque a gestão nativa só permite delegar direitos próprios; não existe um direito separado de delegação. Portanto tem capacidade funcional acumulada, explicitamente declarada, mas não será utilizado para preparar/aprovar os exemplos. A separação do percurso é #1 → #2 → Compras novo → Financeiro novo; não alegar que o administrador é tecnicamente impedido de efectuar essas funções. B.record permite reserva/libertação pelo processo, inclusive rejeição; não concede movimentos directos, pagamentos ou consumo.
Não conceder B.consume, B.reinforcement.propose/review, unit.edit, direitos financeiros adicionais ou novos direitos noutras empresas/unidades. Não atribuir descoberta de desenvolvimento às contas novas por arrasto. #3 continua só de consulta. Não conceder novos direitos a #1/#2/#3 na origem 8039 nem a qualquer conta em sgf_tempo_dev.
Bootstrap: na base nova, criar/auditar as três identidades e permissões-base delimitadas; configurar temporariamente initialisation_scopes=["1:1:1"]; o novo administrador inicializa **apenas a sua própria autoridade** com os dez direitos enumerados, depois delega pelo ecrã Acessos os direitos exactos da tabela. Fechar initialisation_scopes=[] ao terminar. Registar concessões/auditoria e confirmar ausência de extras.
Membros da política: #1, #2, Compras novo e Financeiro novo associados a SYN-OPER; administrador/consulta sem papel aprovador na política. Centro criado pelo administrador; dotação preparada por #1 e aprovada por #2, pelas interfaces existentes. Sem SQL para fabricar centros, dotação ou decisão de requisição.
## Migração e mapa SQL mínimo incluídos na confirmação proposta
A fonte sintética tem **93 tabelas**, sem cb_*, ir_* ou sgc_installations (leitura confirmada). A migração revisão 2 adiciona **16**, resultando em **109 tabelas**, não 103. As provas anteriores 87→103 continuam válidas no seu âmbito; a instalação nova terá verificação própria 93→109.
Novas: cb_centres, cb_origins, cb_budgets, cb_budget_entries, cb_budget_consumptions, cb_budget_reinforcements, cb_audit, cb_ui_commands, cb_consumption_sources; ir_requests, ir_steps, ir_events, ir_commands, ir_policies, ir_policy_versions; sgc_installations. Alargar campo/constraint permission_grants, preservar dados; constraints/triggers/recibo. Não executar migrações genéricas de Compras ou down destrutivo.
Owner e runtime novos: NOSUPERUSER, NOCREATEDB, NOCREATEROLE, NOBYPASSRLS, sem filiação entre roles. Owner possui a base/objectos e executa DDL; runtime tem CONNECT/USAGE, sem propriedade ou CREATE/ALTER. No cluster novo, restringir PUBLIC/pg_hba para que as roles de aplicação/migração só se liguem à base nova; não alterar HBA/ACL de clusters existentes. Administração técnica do novo cluster é separada das contas funcionais.
Nos 93 objectos anteriores restaurados, repor para runtime apenas o mapa DML necessário já inventariado da ligação SGF sgf_dev_app (SELECT/INSERT/UPDATE/DELETE onde existente), USAGE das sequências e EXECUTE das funções exigidas. Não copiar propriedade/DDL da role sintética antiga; não GRANT ALL, TRUNCATE, administração ou DEFAULT PRIVILEGES globais. Conferir separadamente os seis objectos que excedem o schema 87 antes de lhes conceder acesso; começar sem privilégios runtime nesses seis se não forem dependências deste percurso. Qualquer dependência adicional exige revisão, não concessão silenciosa.
Nos **16 novos objectos**, aplicar o mesmo mapa mínimo anteriormente apresentado, emitido para **sgf_ir_app_401c** (não para sgf_dev_app):
| Tabelas | Runtime |
| --- | --- |
| cb_centres, cb_origins, cb_budget_entries, cb_audit, cb_ui_commands | SELECT, INSERT |
| cb_budgets | SELECT, INSERT, UPDATE |
| cb_budget_consumptions, cb_budget_reinforcements, cb_consumption_sources, sgc_installations | SELECT |
| ir_requests, ir_steps, ir_policies | SELECT, INSERT, UPDATE |
| ir_events, ir_commands, ir_policy_versions | SELECT, INSERT |
| Sequências das tabelas de inserção | USAGE apenas |
REVOKE herdados runtime/PUBLIC só nos objectos novos antes do GRANT mínimo; sem DELETE/TRUNCATE de histórico ou DDL. O gerador e contrato são os mesmos; o JSON antigo com sgf_dev_app é referência histórica e não deve ser executado neste destino. A confirmação incluirá explicitamente este mapa para a role nova.
## Sequência única após confirmação — ainda não executar
1. Conferir artefacto, disponibilidade de caminhos/portas, fonte exclusivamente sintética e fingerprints dos originais/8039. Fazer snapshot consistente da fonte sintética e backup privado do seu código/configuração, sem alterar ou parar a origem.
2. Provisionar só cluster/base/roles/aplicação novos e restaurar a cópia sintética com owner novo. Isolar storage/sessões/credenciais/ligação. Aplicar apenas a adaptação de identidade exacta da guarda na cópia; registar hashes. Host novo começa em manutenção, operacional desactivado e sem servidor acessível externamente.
3. **Antes de qualquer migração da candidata**, fazer backup fresco do destino novo já restaurado (`before.dump`), código/configuração/ACLs/sequências e SHA-256. Restaurar efectivamente em `sgf_ir_restore_401c_pre` restrita no cluster novo; comparar as 93 tabelas, dados, schema, constraints/triggers/sequências e ACLs. Não migrar se falhar. A fonte sintética não substitui este backup do destino.
4. Recalcular os planos read-only para nova identidade exacta, validar nove baselines/manifesto e migrar com sgf_ir_owner_401c, backup e hashes conferidos. Aplicar mapa SQL mínimo à role nova. Conferir 93→109, recibo revisão 2 e preservação das linhas anteriores. Não usar os hashes de plano de sgf_tempo_dev.
5. Fazer prepared.dump e prova efectiva em `sgf_ir_restore_401c_post`, reconciliar 109 tabelas/contrato/ACLs. Aplicar código/assets com journal sob manutenção; manter ponteiro Compras 0.1.1. Sem caches globais partilhados; caches/sessões apenas desta cópia.
6. Activar a composição **apenas nesta aplicação/base sintéticas**: purchasing-operational.enabled=true; purchasing-internal.candidate_enabled=true; âmbito orçamental permitido apenas 1:1:1; modules.companies["1:1"] inclui Compras contratado/activo. Não activar empresas alternativas. Inicializar administrador/delegações exactamente como acima, fechar autoridade inicial, criar centro/dotação/política pela interface.
7. Verificar loopback, roles/DDL negado, permissões e isolamento entre empresa/unidade/módulo, CSRF/contexto/revogação; executar o exemplo 151 MZN com reserva única e aprovação por #2; testar recusas de auto-aprovação, tipos excluídos e saldo insuficiente sem escrita. Os percursos de múltiplas etapas usam as identidades distintas propostas. Reutilizar provas anteriores válidas; testes novos afectados pela identidade/configuração são necessários, sem repetir suites globais por rotina.
8. Fazer backup configurado, restaurar numa base de recuperação restrita e conferir origem/decisão/reserva. Retirar só a manutenção nova após checks; disponibilizar 8041 exclusivamente para desenvolvimento. Recomparar snapshots do original e 8039. Não tocar em serviços/dados de outras demonstrações nem parar clusters existentes.
## Recuperação e limites
Código: journal/backups dos nove overlays, manifesto e bundle anterior; rollback sob manutenção recusa divergências locais e não altera dados. Na nova instância, pode manter-se desactivado o percurso em falha sem afectar original/8039.
Schema: falha de DDL reverte transacção; após commit manter schema aditivo compatível ou aplicar correcção deliberada. Não executar down, apagar histórico ou supor que rollback de código remove schema.
Dados: usar before/prepared/configured.dump conforme o ponto de recuperação, restaurar em base alternativa restrita, reconciliar e reconfigurar ACLs mínimas. Troca da aplicação só para cópia conferida da própria base sintética; operações posteriores exigem reconciliação. Não sobrescrever sgf_tempo_dev, a base 8039 ou dados posteriores por automatismo. Guardar bundles não recupera dados.
Provas reutilizadas: 157 controlos integrados, 17 React/assets, 54 deployment, restauro efectivo de 103 tabelas da reprodução anterior, navegação 185/3220 + 8/90. Não são provas já executadas do novo cluster/destino proposto. Revisão visual permanece separada, sem nova tentativa pela via bloqueada. Associações antigas continuam sinalizadas e sem atribuição automática; volume/paginação pendentes. Sem equipamentos/peças, pagamentos, stock, emissão, contabilidade ou publicação no domínio.
## Texto da confirmação única proposta
«Confirmo SGF-IR-USABLE-401C-20261102 exclusivamente sintético: criar a cópia SGF no caminho indicado, cluster 55441/base sgf_ir_dev_401c_20261102 e roles separadas; reutilizar só as identidades/dados sintéticos da demonstração 8039 sem a alterar; aplicar a candidata 401ce31ae5f2dd20 e hashes indicados, migração revisão 2 e mapa SQL mínimo para sgf_ir_app_401c; configurar o centro, dotação fictícia de 50 000 MZN/2026, política/limites e concessões exactas desta proposta, com identidades distintas e autoridade inicial encerrada; efectuar backup fresco e restauros conferidos antes/depois, testes afectados e abertura apenas em loopback 8041. Preservar sgf_tempo_dev, Tempo, direitos públicos, alterações locais, navegação e Compras 0.1.1. Sem publicação; em divergência parar e recuperar no âmbito sintético.»
## Esclarecimento vinculativo do encerramento — ainda não autorizado
«Encerrar a autoridade inicial» terá DOIS efeitos obrigatórios: (1) configurar initialisation_scopes=[] e reiniciar apenas a instância nova para descarregar a configuração temporária; (2) revogar pelo circuito nativo auditado, exclusivamente de admin-ir-401c@example.test em 1:1:1, os seis direitos temporários abaixo, antes de abrir a demonstração:
- purchasing_requisitions.prepare;
- purchasing_requisitions.approve.department_head;
- purchasing_requisitions.approve.procurement;
- purchasing_requisitions.approve.finance;
- purchasing_budget.approve;
- purchasing_budget.record.
O administrador conservará SOMENTE: company.view e access.manage na empresa 1; unit.view, purchasing_requisitions.view, purchasing_requisitions.configure, purchasing_budget.view e purchasing_budget.create na unidade 1. Assim pode configurar política/centro e preparar dotações, mas não preparar/submeter requisições, aprovar dotações/requisições ou reservar/libertar pelo processo. Não é uma conta só de administração: B.create continua funcional e explícito. Se for necessária outra separação futura, exige decisão própria.
A revogação é individual via API/ecrã nativo, enquanto ainda detém cada direito a retirar, com motivo e auditoria. Não apagar grants por SQL para contornar auditoria. Verificar o conjunto final exacto e recusas por HTTP; se qualquer retirada/verificação falhar, conservar manutenção. Fechar scopes sozinho NÃO revoga direitos. Não retirar company.view/unit.view nem usar revogação em cascata. A autoridade inicial já auditada não é reaberta ou apagada.
Depois do encerramento, o administrador não poderá delegar nem revogar direitos que deixou de possuir pelo circuito normal; access.manage não contorna essa regra. Não haverá reatribuição temporária automática. Uma gestão futura desses direitos requer proposta explícita de autoridade compatível. Os direitos anteriormente delegados aos actores sintéticos mantêm-se. O access.manage histórico do preparador #1 na cópia permanece, conforme preservação anterior; este perfil não é usado como substituto administrativo deste incremento. Nada é revogado na demonstração 8039 ou no SGF real.
Plano SQL das identidades PostgreSQL: [novas roles/base](proofs/sgf-ir-401c-new-roles.sql), sem credenciais no ficheiro. Plano SQL final dos 16 objectos novos: [mapa dirigido a sgf_ir_app_401c](proofs/sgf-ir-401c-new-objects.sql), transaccional e condicionado a base/porta/migrador/revisão exactos. As contas funcionais continuam a ser criadas/delegadas/revogadas pelo bootstrap delimitado e circuito auditado, não recebem roles PostgreSQL individuais. Nenhuma alteração aos 93 objectos restaurados além do mapa DML anteriormente delimitado; os seis wc_* não recebem privilégios runtime. Os dois ficheiros SQL são propostas, não foram executados.
**Nenhuma das duas propostas está autorizada.** O texto de confirmação anterior só é válido se incluir também este esclarecimento e os planos SQL finais. Sem confirmação posterior do pacote completo, não provisionar, migrar, conceder, revogar, instalar ou activar. Preservar 8039 e sgf_tempo_dev intactos.
@@ -0,0 +1,102 @@
# Proposta revista SGF-IR-USABLE-401C-20261102
**Candidata utilizável ensaiada; instalação, activação e publicação NÃO executadas nem autorizadas.** Substitui a proposta de instalação técnica desactivada SGF-IR-INSTALL-5FAE-20261102, que não deve ser executada. Entrega para decisão posterior. O pacote instalado continua em **0.1.1**.
## Artefacto e destino proposto
| Elemento | Valor vinculativo |
| --- | --- |
| Candidata | `OPERATIONAL-CANDIDATE-401ce31ae5f2dd20`, formato `tempo.operational-review.v1`, schema revisão **2**; sem nova versão comercial |
| ZIP privado | `C:/laragon/www/compras/storage/app/private/candidate-archives/OPERATIONAL-CANDIDATE-401ce31ae5f2dd20.zip` |
| SHA-256 ZIP | `59dbdc64c4d9f14dfb4025a6177b829d136a4e2cb633ca036b10b5ae3197e703` |
| SHA-256 manifesto | `a6478223e17a5430652f0fcbf31a44a931ae2a99cd90b151c98d2df5df43c10b` |
| Raiz futura | `C:/laragon/www/sgf-tempo`, ambiente `local` |
| Base futura | **`sgf_tempo_dev`**, `127.0.0.1:55432` — não alterada nesta entrega |
| Aplicação / migrador | `sgf_dev_app` / `sgf_dev_owner`, ligações distintas existentes; credenciais mantidas |
| Bundle futuro | `packages/internal-requisitions`; não substitui `packages/purchasing/current.json` |
| Preparação / backup futuros | `C:/laragon/data/sgf-tempo/install/SGF-IR-USABLE-401C-20261102` / `C:/laragon/data/sgf-tempo/backups/SGF-IR-USABLE-401C-20261102` |
| Plano de código, só leitura | `d29833b1c48b9d666522d20d87040d5ad30370cf114c9a70f272cd041eea59e9` |
| Plano de schema, só leitura | `169e6e863f28b67740f07b6e7cbc664fbe585a7760a83dccebc8d482ad8ab792` |
Os dois planos passaram no destino sem escrita. Não se instalará a antiga candidata 5fae nem se activará esta candidata por consequência do ensaio. Não foi criado checkpoint nem publicado artefacto.
## O que fica utilizável na candidata
Percurso administrativo e funcional integrado: ecrã nativo **Acessos** com catálogo/rótulos do servidor e opções limitadas aos direitos próprios; criação de centro por formulário; preparação de dotação; aprovação por outra identidade; configuração versionada de departamentos, intervenientes, limites e exigência orçamental; requisição de **consumíveis, serviços e outros**, edição de rascunho, submissão com uma reserva transaccional, aprovação independente e consulta/histórico. Não são necessárias fixtures ou inserções SQL para criar centros/dotações.
O acesso inicia-se pelo módulo Compras e pelos links de requisições/preparação orçamental. O catálogo não concede direitos. A gestão normal continua a exigir autoridade administrativa, pertença e os direitos próprios de quem delega; a inicialização de autoridade continua explícita, nominativa e limitada ao âmbito configurado. Nenhum utilizador ou direito foi atribuído no destino.
As dependências `cb_ui_commands` e `cb_consumption_sources` passam a integrar o pacote e a migração. Reutiliza-se o núcleo orçamental existente; a preparação/aprovação usa as APIs existentes. Movimentos orçamentais directos continuam bloqueados nesta composição: a reserva nasce da requisição, sem segundo motor nem forma alternativa de consumo. O catálogo inclui capacidades futuras que não ficam operacionais só por estarem listadas.
## Navegação e alterações locais
Referência funcional: **`2a4169162bb4621a42a2ea1df627d52f860e7176`**. `fcf0ada22701337acd4c84b404207b8400f490a2` é documental. Os 19 ficheiros conferidos continuam byte a byte iguais no host ao inventário anterior; não houve instalação sobre o código aceite.
Preservar Comercial, Compras, Stock, Oficinas, Financeiro e Contabilidade; **Início e Opções gerais/configuração permanecem separados**, conforme as permissões. Não existe compromisso de criar um menu literal único «Configuração». Contexto não concede direitos; associações antigas não são preenchidas.
O manifesto da nova candidata prevê **nove sobreposições exactas**: Permissions, IdentityWorkflow, BudgetAdapter, BudgetWorkspace, AppServiceProvider, ModuleNavigation, `resources/js/app.jsx`, `resources/js/PurchasingHome.jsx` e `public/build/manifest.json`. A interface foi reconstruída numa cópia privada, com as dependências já instaladas. JS/CSS compilados e hashes viajam no próprio bundle; não se alteram dependências do host. As rotas estáticas servem exclusivamente os assets empacotados, inclusive antes da autenticação. O instalador recusa ficheiros locais divergentes e a recuperação inclui o manifesto anterior. Não usar reset/checkout/limpeza global nem sobrepor trabalho alheio.
## Schema e privilégios para decisão
Migração aditiva transaccional **revisão 2**: sete tabelas do orçamento comum, duas dependências de interface (`cb_ui_commands`, `cb_consumption_sources`), seis tabelas `ir_*` e recibo `sgc_installations`: **16 tabelas novas, 87 → 103**. Amplia o campo/constraint do catálogo em `permission_grants`, sem modificar os registos. Cria constraints/triggers de integridade/imutabilidade; tabelas de negócio começam vazias. Recusa schema parcial ou recibo incompatível; não há `down` destrutivo. Não aplicar migrações genéricas de Compras autónomo.
O migrador precisa de CONNECT, USAGE/CREATE no schema e propriedade dos objectos que altera (`permission_grants` e novos objectos/funções). O ensaio utilizou owner **NOSUPERUSER, NOCREATEDB, NOCREATEROLE, NOBYPASSRLS**. O runtime apenas CONNECT/USAGE e DML explícito; CREATE e ALTER foram efectivamente recusados. A leitura anterior do owner real confirmou propriedade e CREATE numa transacção read-only; não se alteraram credenciais ou privilégios reais.
**Alteração SQL necessária, apenas proposta para decisão:** os defaults actuais do destino dão arwd em tabelas novas e rU nas sequências. Isso excede o mínimo. O plano `SqlPrivileges::plan('sgf_dev_app')` revoga privilégios herdados do runtime/PUBLIC **apenas nos 16 objectos novos**, e repõe:
| Objectos | Runtime |
| --- | --- |
| cb_centres, cb_origins, cb_budget_entries, cb_audit, cb_ui_commands | SELECT, INSERT |
| cb_budgets | SELECT, INSERT, UPDATE |
| cb_budget_consumptions, cb_budget_reinforcements, cb_consumption_sources, sgc_installations | SELECT |
| ir_requests, ir_steps, ir_policies | SELECT, INSERT, UPDATE |
| ir_events, ir_commands, ir_policy_versions | SELECT, INSERT |
| Sequências das tabelas de inserção | USAGE apenas |
Sem DELETE/TRUNCATE, DDL, propriedade, superuser, concessões globais ou alteração dos DEFAULT PRIVILEGES. Objectos anteriores conservam ACLs. O plano é emitido por `sgf-internal-install.php privileges-plan <host> sgf_dev_app`; **não é executado automaticamente** pela instalação. O ensaio reproduziu e reduziu os privilégios herdados, e comparou as ACLs das 87 tabelas anteriores.
Catálogo reconhecido: `purchasing_requisitions.view/prepare/configure/approve.department_head/approve.procurement/approve.finance` e `purchasing_budget.view/create/approve/record/consume/reinforcement.propose/reinforcement.review`. **Concessões a utilizadores do destino: zero.** Para futura abertura são necessários âmbito/autoridade e responsáveis concretos aprovados, política e dotação configuradas pelas interfaces. A candidata resolve a preparação; não inventa a decisão empresarial nem importa os actores/valores sintéticos.
## Ensaio e recuperação
[Prova consolidada](proofs/sgf-requisition-usable-candidate.json): **157 verificações integradas**, **17 verificações React/render/assets**, **54 verificações de aplicação/interrupção/recuperação de código**. As 87 comparações individuais de ACL estão incluídas nos 157 controlos; estes números não são uma nova suite global. Exportou-se apenas o schema actual do SGF, **zero linhas do destino**. Foram criadas bases e roles aleatórias restritas no cluster local de QA, com limpeza confirmada. Dados/contas/concessões usados no percurso são exclusivamente sintéticos.
Verificado: DDL interrompida faz rollback; instalação vazia; autenticação/contexto/CSRF nativos; catálogo e delegação/recusa/revogação; centro idempotente; dotação com aprovação distinta; requisição com os três tipos suportados; submissão e reserva única; auto-aprovação recusada; decisão e histórico; módulo não contratado/desactivado recusado; código sucessor compatível aplicado e recuperado sem alterar qualquer tabela; backup custom efectivamente restaurado numa segunda base, **103 tabelas reconciliadas**, schema/triggers/decisão/origem/reserva preservados e leitura com runtime restrito.
- **Código:** journal, hashes, cópia dos ficheiros/manifesto e bundle anterior; recuperação sob manutenção recusa alterações locais desconhecidas. Uma falha conserva manutenção. Actualização com mudança de contrato/schema é recusada e exige plano próprio.
- **Schema:** transacção para falhas de DDL; depois do commit, manter schema aditivo compatível ou migração correctiva conferida. Recuperar código não remove tabelas nem inverte constraints.
- **Dados:** dump real, restauro noutra base e reconciliação de todas as tabelas/sequências/schema/ACLs. O ensaio reconciliou os 103 conjuntos de linhas e a assinatura de constraints/triggers; o runtime voltou a ler decisão/reserva. Guardar bundles antigos não recupera dados. Não restaurar backup antigo por cima de operações posteriores sem reconciliação e decisão específica.
As provas anteriores válidas de navegação (185/3220 + 8/90), isolamento/requisições/concorrência, núcleo comum e Compras são reutilizadas no seu âmbito. Não foram repetidas as suites globais. Build/SSR/HTTP não constituem revisão visual.
## Operação única proposta para futura decisão
**Não executar agora.** Esta é a sequência técnica revista, e não uma ordem de instalação desactivada. A decisão futura terá de fixar também a abertura/configuração pretendida; sem destinatários/âmbitos aprovados não existe autorização implícita para concessões ou activação.
1. Conferir ZIP/manifesto e nove baselines; executar novamente só os planos read-only com os hashes acima. Qualquer divergência obriga a reconciliar a proposta antes de escrever. Extrair fora da raiz web, sem sobrepor tentativas anteriores.
2. Inventariar serviços/ambientes; preservar código local completo, estado Git, configurações/caches/uploads e ACLs em pasta privada. Parar apenas escritores do destino e colocar em manutenção. Não usar `sgf.ps1 stop`, não parar PostgreSQL nem demonstrações alheias.
3. Fazer backup fresco `before.dump` custom e hashes; restaurar numa base privada vazia `sgf_restore_ir_401c_pre`, comparar dados/schema/sequências/ACLs do corte real. A prova sintética desta entrega não substitui esse backup do dia.
4. Com ligação exclusiva `sgf_dev_owner`, executar `sgf-internal-install.php migrate <host> <schema-target> <before.dump> <backup-sha> <operador> <manifest-sha>`; conferir revisão 2, 16 tabelas novas, recibo e preservação de dados/acessos. Aplicar somente o mapa SQL novo se expressamente incluído na decisão; nenhuma concessão funcional a utilizadores por arrasto.
5. Fazer `prepared.dump`, restaurar em `sgf_restore_ir_401c_post` e conferir as 103 tabelas e contrato. Não avançar se restauro falhar.
6. Sob serviços escritores parados, executar `sgf-code-deploy.php apply <host> <bundle> <manifest-sha> <code-target> <operador> --offline`. A CLI regista journal e mantém manutenção; conferir os nove overlays e os assets incluídos. Compras mantém 0.1.1.
7. Não criar caches globais de configuração/rotas/eventos neste host partilhado com demonstrações em ambientes diferentes. O instalador invalida caches conhecidos; preservar/reiniciar os serviços com os ambientes próprios. Não executar rebuild global por rotina.
8. Antes de qualquer abertura futura, aplicar somente a configuração/autoridade explicitamente decididas, usando interfaces e separação de identidades. Verificar isolamento tenant/empresa/unidade/módulo, direitos/revogação, guardas reais, rotas/assets e navegação aceite. Sem configuração autorizada, conservar guardas, sem declarar o destino utilizável. Restabelecer apenas serviços identificados e manutenção conforme estado inicial após verificações; guardar evidência privada.
Em falha: manter manutenção, recuperar código pelo deployment id e conferir os ficheiros; conservar schema/dados. Para perda/corrupção, restaurar para base alternativa restrita, reconciliar e só depois decidir a troca. Nenhuma eliminação da base de destino ou reposição de dados automática faz parte desta proposta.
## Pendências e preservação final
| Pendência | Estado/efeito |
| --- | --- |
| Duas tabelas da interface | Resolvidas na revisão 2 e comprovadas no schema reproduzido |
| Administração dos direitos | Resolvida no ecrã nativo/catálogo/servidor, sem concessões no destino |
| Centros/dotações | Preparação e aprovação independentes utilizáveis; valores reais continuam por configurar |
| Equipamentos/peças | Fora do incremento, rejeitados por servidor; não bloqueiam consumíveis/serviços/outros; não disfarçar como outros |
| Instalação/activação/privilégios SQL/autoridades reais | A decidir posteriormente; não executados nesta entrega |
| Revisão visual | Pendente, separada; nenhuma tentativa pela via bloqueada |
| Associações antigas | Continuam pendentes/sinalizadas, sem atribuição automática |
| Volume/paginação | Pendente; sem alegar prova de carga ou paginação integral |
Destino preservado por leitura final: **87 tabelas**, **89 concessões**, **2 pertenças**, **162 registos da auditoria de identidade**; fingerprints e guardas iguais aos anteriores, ponteiro Compras 0.1.1 intacto. Nenhuma publicação, instalação, activação, credencial ou privilégio do destino alterado. As alterações locais e o trabalho paralelo foram preservados.
Hash SHA-256 do contrato de migra??o: `4ca4f5827c46e5ca29cb329c667df0b996ecbf5e318c0b157091c94e9d44ae92`. [Mapa SQL m?nimo exacto, proposta n?o executada](proofs/sgf-requisition-minimal-sql-plan.json). Integridade final: 49 ficheiros de suporte conferidos e 42 PHP verificados por lint; ZIP/manifesto inalterados. Snapshot do destino igual ao anterior.
+130 -2
View File
@@ -1,5 +1,105 @@
# Transferência de Compras e actualizações do SGF
## Decisão de instalação — proposta sem execução, 02/11/2026
O âmbito escolhido pelo proprietário é **decidir a instalação, sem a executar**. A [decisão concreta](PURCHASING_INSTALLATION_DECISION.md) identifica projecto/base efectivos, candidata/hashes, schema/catálogos, bloqueantes e backup/restauro/recuperação. Os planos de leitura de código/schema passaram e o ZIP foi reconferido. O [inventário do destino](proofs/sgf-installation-decision-inventory.json) foi obtido em transacção PostgreSQL READ ONLY; nenhuma suite foi repetida.
**Recomendação: não instalar esta candidata como percurso operacional ainda.** O destino `C:\laragon\www\sgf-tempo`, base `sgf_tempo_dev` em `127.0.0.1:55432`, tem 87 tabelas e usa `sgf_dev_app`, sem CREATE/ALTER necessários. Faltam a execução migradora/mapa de privilégios mínimos runtime e a preparação operacional de centros/dotações: não existem tabelas `cb_*`, a interface candidata apenas selecciona centros existentes e a interface orçamental actual depende de duas tabelas ausentes do schema candidato. As provas isoladas com role proprietária/cadastros preparados não cobriam esses aspectos do destino. Preservar o ZIP aprovado como evidência e resolver essas lacunas antes de propor a operação executável; novos bytes exigem novos hashes/provas.
**Catálogo administrativo:** implementado/testado na candidata, ainda não instalado; não é falta de implementação, mas não constitui direitos já atribuídos. **Equipamentos/peças:** fora do recorte básico de consumíveis/serviços/outros, não são o seu bloqueio. Há uma concessão de administração da empresa no destino; a regra de dois administradores permanece pendente para entrega/activação, sem criar conta ou atribuir direitos por conveniência. A eventual instalação técnica desactivada é diferente de abrir o percurso aos utilizadores.
**Navegação modular: tecnicamente aceite em 02/11/2026**, conforme [registo próprio do SGF](../../sgf-tempo/docs/MODULAR_NAVIGATION_DELIVERY.md). Manter separadas revisão visual/recargas, associações antigas e volume/paginação. Essa aceitação não autoriza instalar a candidata, alterar direitos públicos ou publicar. O SGF continua em **0.1.1**. Não foram executados `migrate`, `apply`, `cache`, backups, concessões, manutenção ou paragem/reinício de serviços.
## Reconciliação com a entrega modular do SGF — 02/11/2026
A conferência documental posterior encontrou uma entrega própria de navegação modular no SGF: [implementação e estado](../../sgf-tempo/docs/MODULAR_NAVIGATION_DELIVERY.md), [conclusão técnica](../../sgf-tempo/docs/MODULAR_NAVIGATION_COMPLETION.md) e [conferência de 02/11/2026](../../sgf-tempo/docs/proofs/modular-navigation-recheck-20261102.json). Portanto, **a indicação anterior «sem resultado apresentado» fica sucedida por «entrega técnica documentada, com encerramento pendente»**. Não repetir implementação ou testes já registados com base naquele estado histórico.
Segundo essa entrega, os módulos são Comercial, Compras, Stock, Oficinas, Financeiro e Contabilidade; Início e Opções gerais estão separados do módulo activo. A entrega regista 185 testes/3.220 asserções de regressão, 8 testes/90 asserções focados e três perfis sintéticos num ambiente próprio. A conferência registada comparou 184 ficheiros com a cópia validada, confirmou hashes de JUnit e preservação de concessões/pertenças/auditoria/guarda/ponteiro, sem repetir testes ou provisionamento. Esta retoma de Compras **leu e reconciliou essas provas**, não executou novamente essa conferência nem as suites. Instância isolada documentada: `http://127.0.0.1:8039`.
Continuam separados: [revisão visual pendente](../../sgf-tempo/docs/MODULAR_NAVIGATION_VISUAL_REVIEW.md), incluindo recargas de páginas autónomas; reconciliação humana das associações antigas; avaliação de volume/paginação antes de implantação. A interface usa «Opções gerais», não um submenu único literalmente chamado «Configuração». Não declarar aceitação visual, cobertura operacional dos módulos em preparação ou disponibilização comercial integral.
Esta entrega modular não instala a candidata de requisições nem substitui as suas provas de código/schema/caches. A integração candidata continua preparada e verificada no âmbito descrito abaixo; o SGF de destino permanece em 0.1.1. **Não houve instalação, activação, alteração de código/permissões ou nova tentativa de navegador nesta reconciliação.** A decisão de instalar continua separada, conforme instrução do proprietário.
## Actualização entre bundles e caches nativos — 02/11/2026
**Concluído neste incremento candidato:** transição de código entre bundles já instalados, reversão para o anterior e compilação/recuperação dos caches Laravel nativos. **32 controlos novos aprovados**, sem repetir as suites anteriores. Prova e hashes em [proofs/sgf-update-cache-delivery.json](proofs/sgf-update-cache-delivery.json). A candidata é `OPERATIONAL-CANDIDATE-5fae7cf7f99c42ba`, com [ZIP de revisão](../storage/app/private/candidate-archives/OPERATIONAL-CANDIDATE-5fae7cf7f99c42ba.zip); SHA-256 do ZIP `d14a3261d5aaab80f96250af781c700ab53376021f4638e3aee43c15ff37ceed` e do manifesto `b1ec47f7a9ad87e0b232bac41e402d4a00ee5f03f00a79b93effc692ce8b39a2`. Não foi publicado no canal, instalado ou activado no destino. SGF mantém **0.1.1**.
As pendências históricas de transição entre versões e ensaio dos caches padrão, registadas nas secções seguintes, são sucedidas por este resultado. Não se altera o âmbito das provas anteriores nem se declara concluída a reorganização modular do SGF.
### Transição com proveniência local
`plan` reconhece a versão de código seleccionada pelo registo privado `storage/app/private/module-deployments/current.json`, distinto do ponteiro `packages/purchasing/current.json` que permanece intacto. Confere o journal, os bytes e o manifesto do bundle instalado; rejeita alterações locais, conteúdo extra, bundle sem proveniência, mudança de baseline/composição dos ficheiros nativos ou diferenças nos ficheiros de preparação do schema/catálogo. A transição implementada cobre código sob o **mesmo contrato de schema**. Alterar esse contrato exige plano/revisão de migração próprios; não executa uma migração implicitamente.
`apply` guarda o bundle anterior na instalação, troca o código sob manutenção/serviços parados e actualiza atomicamente o registo privado da versão seleccionada. `rollback` repõe o bundle, ficheiros nativos e proveniência anteriores, sem depender da pasta de Compras, base de desenvolvimento ou ficheiros da origem. Recusa reversão fora de ordem e replay de uma versão que já não está seleccionada. Uma nova tentativa depois de uma reversão recebe outro ID; os journals anteriores permanecem preservados. A repetição de uma reversão já concluída não volta a alterar código/caches da versão anterior.
O registo privado é criado pela rotina actual. Uma cópia antiga/manual de bundle, sem esse registo, não é adoptada automaticamente: exige reconciliação explícita da proveniência. Este requisito preserva os ficheiros existentes e não atribui direitos funcionais. Continua a não haver outorga automática, alteração do perfil ou importação de dados de desenvolvimento.
### Compilação nativa e recuperação de caches
A CLI tem agora a acção `cache`, que usa o mesmo PHP fixado para executar **`config:cache`, `route:cache` e `event:cache` no próprio host**, com manutenção/serviços parados. Arquiva os caches anteriores em armazenamento privado, invalida-os antes de arrancar Artisan e regista comandos/resultado/hashes dos ficheiros produzidos, incluindo resultados parciais quando uma compilação falha. Assim, um `config.php` truncado não impede a CLI de o preservar e reconstruir a configuração a partir das fontes actuais. Os logs e cópias compiladas ficam privados e não são incluídos no ZIP cliente.
Se tiver havido compilação registada, a reversão invalida esses caches e conserva-os em arquivo privado; não repõe silenciosamente valores compilados antigos sobre configuração posterior. Depois de repor o bundle anterior, executar `cache` para o ID dessa versão e reiniciar os seus serviços antes de reabrir. Se não tiver havido recompilação, mantém-se a reposição exacta dos caches anteriores já ensaiada. Alterações aos caches após a compilação registada continuam a bloquear uma reversão cega e exigem reconciliação. Caches com caminhos personalizados continuam fora do contrato actual e são recusados antes de aplicação/recuperação.
```text
powershell.exe -NoProfile -ExecutionPolicy Bypass -File "<raiz-SGF>/scripts/sgf.ps1" php "<candidata>/scripts/sgf-code-deploy.php" plan "<raiz-SGF>" "<candidata>" <manifest-sha256>
powershell.exe -NoProfile -ExecutionPolicy Bypass -File "<raiz-SGF>/scripts/sgf.ps1" php "<candidata>/scripts/sgf-code-deploy.php" apply "<raiz-SGF>" "<candidata>" <manifest-sha256> <target-codigo-sha256> "<operador>" --offline
powershell.exe -NoProfile -ExecutionPolicy Bypass -File "<raiz-SGF>/scripts/sgf.ps1" php "<candidata>/scripts/sgf-code-deploy.php" cache "<raiz-SGF>" <deployment-id-seleccionado> "<operador>" --offline
powershell.exe -NoProfile -ExecutionPolicy Bypass -File "<raiz-SGF>/scripts/sgf.ps1" php "<candidata>/scripts/sgf-code-deploy.php" rollback "<raiz-SGF>" <deployment-id-a-reverter> "<operador>" --offline
```
Para uma actualização: conferir a origem aprovada, os hashes e o plano; preservar o destino e parar os serviços em manutenção; aplicar o bundle; compilar os caches para o ID devolvido; reiniciar apenas os serviços dessa instalação e conferir o seu arranque; reabrir só pela decisão de activação separada. Para reverter: parar serviços em manutenção, reverter o ID seleccionado, compilar os caches da versão anterior reposta e reiniciar/conferir antes de reabrir. Dados/schema/permissões não são restaurados por estes comandos. A preparação de schema continua no executor separado, apenas quando houver uma migração prevista e ensaiada.
### Âmbito exacto das novas provas
Ensaiada transição real entre a candidata anterior `10dce6cd57fa1f31` e a nova, recuperação de falha entre preservação/troca dos bundles, reversão e nova tentativa com histórico distinto. Confirmadas recusas de origem desconhecida, schema divergente, alteração local/conteúdo extra e reversão fora de ordem. A segunda cópia inclui aplicação e dependências, sem `.env` ou dados reais; para acelerar o ensaio, as dependências imutáveis usam hardlinks **apenas para uma cópia descartável anterior**, nunca para o vendor do SGF de destino. Não se executam comandos Composer que alterem essas dependências.
Na cópia isolada foram executados os três comandos de cache nativos, falha injectada após `config:cache`, recuperação de cache inválido pela CLI e reinícios efectivos do servidor PHP local de teste. A rota em cache manteve autenticação (401 para anónimo), manutenção manteve bloqueio (503) e o host voltou a responder após reversão, sem a rota retirada (404) e com healthcheck 200. Os reinícios cobrem o servidor de teste, **não certificam todos os gestores de serviços de clientes**. Nenhum serviço, base, direito público ou ponteiro do SGF de destino foi alterado. Nenhuma contratação para terceiros foi incluída.
O ZIP contém código/manifesto locais com integridade conferida, sem base, credenciais, documentos, cache de cliente ou dependências copiadas de desenvolvimento. Pode ser transportado e extraído para uma pasta de preparação no cliente; conferir hashes e executar as ferramentas pelo PHP do próprio SGF. Não extrair directamente sobre a raiz do host. A aprovação do canal de confiança e a decisão de instalar/activar continuam separadas; a preparação do ZIP não é publicação ou autorização de implantação.
## Aplicação e reversão offline do código — 02/11/2026
Implementadas `integrations/sgf/operational/CodeDeployment.php` e CLI `scripts/sgf-code-deploy.php`, incluídas na candidata `OPERATIONAL-CANDIDATE-10dce6cd57fa1f31`. **42 controlos novos aprovados** com PHP 8.4.27 fixado do SGF, apenas sobre cópias descartáveis de ficheiros; sem abrir bases, reiniciar serviços ou repetir suites anteriores. Ver [proofs/sgf-code-deploy-delivery.json](proofs/sgf-code-deploy-delivery.json). O SGF instalado continua em **0.1.1** e nenhuma aplicação/reversão foi executada nesse destino.
A rotina distingue `plan` read-only, `apply` e `rollback`. Confere manifesto e conteúdo, hashes anteriores dos ficheiros do host e impressão do destino, mantém lock exclusivo e prepara cópias anteriores em `storage/app/private/module-deployments/<id>`. O journal durável é escrito antes de começar a substituir código; cada ficheiro é preparado e trocado por rename no seu directório e o bundle é preparado separadamente antes da troca. **Isto não é uma transacção de filesystem sobre todos os ficheiros:** a consistência visível exige manutenção e serviços de escrita parados durante toda a implantação/recuperação. Uma interrupção deixa o journal para recuperação explícita, sem reabrir o serviço automaticamente.
`apply` exige manutenção Laravel baseada em `storage/framework/down` e `--offline`, que é a declaração do operador de que parou web/workers/schedulers responsáveis por escritas. A rotina não detecta nem termina processos. Guarda os caches padrão `config.php`, `events.php`, `packages.php`, `services.php` e `routes*.php` existentes em `bootstrap/cache`, invalida-os e preserva outros ficheiros. Os backups de configuração compilada podem conter segredos e ficam exclusivamente no armazenamento privado local, com permissões restritas do sistema; não integram o artefacto distribuído. Caches configurados por `APP_*_CACHE` fora das localizações padrão são recusados antes da aplicação: não são apagados nem presumidos cobertos.
`rollback` confere código, backup e caches antes de restaurar; recusa alterações locais desconhecidas e caches recriados, em vez de sobrescrever trabalho ou configuração posterior. Repõe os bytes anteriores dos ficheiros/caches e retira o bundle para arquivo privado de diagnóstico. Recupera igualmente aplicação interrompida a meio dos ficheiros ou depois da troca do bundle. Não apaga schema, dados, recibos de negócio, permissões ou operações posteriores. Conserva o ponteiro `packages/purchasing/current.json` e deixa manutenção activa. A existência de `restart_required=true` é uma obrigação operacional, não prova de reinício automático.
### Sequência de implantação, após decisão separada
1. Produzir/conferir a candidata e manifesto por canal de confiança. Executar `plan` de schema e `plan` de código e registar as duas impressões de destino. Conferir o destino e preservar dados/documentos/configuração. A rotina de código não substitui o backup/restauro de PostgreSQL.
2. Entrar em manutenção pelo procedimento do host (`artisan down`, driver de ficheiro) e parar os serviços de escrita daquela instalação. Não usar comandos de demonstração que também parem outras instalações. Não executar `apply` com serviços em funcionamento.
3. Executar a preparação de schema `sgf-internal-install.php migrate`, com backup/manifesto/destino conferidos, conforme secção própria. Nenhuma concessão é atribuída por essa preparação.
4. Executar `sgf-code-deploy.php apply` com o hash do manifesto, impressão do plano de código, operador nominativo e `--offline`. Registar `deployment_id`. A rotina confere e aplica apenas código/bundle e invalida caches conhecidos; não activa configuração comercial nem concede direitos.
5. Mantendo a manutenção, conferir os ficheiros e o journal, configurar explicitamente o destino/âmbitos e os acessos aprovados pelo percurso administrativo, e reiniciar os processos persistentes pelo gestor de serviços daquela instalação para descartar código/opcache antigo. A atribuição administrativa que requer HTTP terá de usar uma janela controlada depois do arranque; não contornar os middlewares nem inserir concessões por SQL para evitar essa etapa. Remover a manutenção e abrir aos utilizadores só depois de conferir a instalação e da decisão de activação. Estas acções de serviços/configuração/abertura são do operador e não são executadas pela CLI.
6. Em falha de código, manter/parar novamente os serviços em manutenção, executar `rollback` com o ID registado, conferir a reposição, reiniciar os serviços e só então decidir reabrir. Se houver código ou caches alterados depois da aplicação, a rotina recusa a recuperação: preservar esses estados e reconciliar explicitamente antes de tentar novamente. Não executar `down` de migrações nem restaurar backup de dados por efeito de rollback de código.
CLI pelo PHP fixado do host; exemplos com parâmetros, **não executados no SGF de destino**:
```text
powershell.exe -NoProfile -ExecutionPolicy Bypass -File "<raiz-SGF>/scripts/sgf.ps1" php "<candidata>/scripts/sgf-code-deploy.php" plan "<raiz-SGF>" "<candidata>" <manifest-sha256>
powershell.exe -NoProfile -ExecutionPolicy Bypass -File "<raiz-SGF>/scripts/sgf.ps1" php "<candidata>/scripts/sgf-code-deploy.php" apply "<raiz-SGF>" "<candidata>" <manifest-sha256> <target-codigo-sha256> "<operador>" --offline
powershell.exe -NoProfile -ExecutionPolicy Bypass -File "<raiz-SGF>/scripts/sgf.ps1" php "<candidata>/scripts/sgf-code-deploy.php" rollback "<raiz-SGF>" <deployment-id> "<operador>" --offline
```
**Limites exactos:** esta versão cobre primeira instalação sobre o baseline conferido e recusa um bundle já existente ou ficheiros nativos divergentes. Ainda não implementa transição entre versões do novo bundle; o updater anterior de código 0.1.1 conserva apenas o seu âmbito já demonstrado. Os controlos de caches deste incremento verificam invalidação e restauro byte a byte dos ficheiros padrão, não regeneração de todos os caches em Laravel nem automação de gestores de serviços. A prova HTTP anterior de 27 controlos mantém o seu âmbito; não foi repetida sobre cada combinação de caches. Não declarar disponibilização comercial completa nem aceitar actualizações futuras sem a respectiva transição/compatibilidade. A reorganização modular permanece entrega distinta.
## Arranque e integração HTTP em cópia isolada — 02/11/2026
Preparada a candidata `OPERATIONAL-CANDIDATE-4b25f81932efd69d`, preservando os artefactos anteriores. A composição já inclui sobreposição do provider nativo para carregar o bundle local e registar as rotas, sem registo manual de rotas pelo harness HTTP. O bundle fica em `packages/internal-requisitions`, com classes e ficheiros próprios; a sobreposição do SGF reconhece `purchasing_requisitions.view` como autorização de descoberta do módulo Compras, sem conceder direitos nem substituir o catálogo/controlo funcional.
`RuntimeContext` é acrescentado às rotas do bundle **depois** dos middlewares nativos de sessão/autenticação/empresa. Confere opção operacional habilitada, destino/schema/âmbito, módulos adquiridos e habilitados, selecção explícita de Compras e geração de contexto nos APIs. A atribuição inicial permanece no âmbito de Administração: não exige um direito funcional de requisição que ainda não foi outorgado, mas exige módulo adquirido, âmbito habilitado e os controlos nominativos/administrativos já implementados. Não cria autoridade a partir da selecção do módulo. A composição desactivada recusa a execução das rotas.
O ensaio `scripts/sgf-composition-proof.php` usa uma instalação descartável com código, dependências e packages **copiados**, provider/configuração/rotas do próprio SGF e bootstrap nativo, sem `.env`, contas, documentos ou dados empresariais copiados. Usa base `sgc_composition_<12hex>` e role próprias, ambiente `production`, sessões privadas e acesso HTTP loopback com login/CSRF reais. A preparação de dados sintéticos e a activação ocorrem exclusivamente nessa cópia/base; não são passos aplicados ao SGF de destino. O router de teste só entrega o pedido ao kernel: não regista rotas, não substitui autenticação e não carrega classes da instalação original.
Resultados efectivos, caminho do artefacto e verificações em [proofs/sgf-composition-delivery.json](proofs/sgf-composition-delivery.json). A prova verifica o incremento de composição/HTTP, incluindo autoridade inicial, administração nativa, contexto, submissão/reserva/aprovação/consulta e revogação; não repete as suites anteriores nem declara revisão visual por navegador. Os resultados históricos seguintes conservam o seu âmbito.
**Resultado final: 27 controlos novos aprovados.** Confirmados provider e adaptador efectivamente carregados da cópia isolada; `plan` aceite pelo verificador de integridade do novo bundle; acesso anónimo e CSRF bloqueados; autoridade inicial sem direitos funcionais prévios; atribuição pela administração nativa; selecção explícita de Compras; recusa de token antigo, modalidade diferente, revogação, módulo não adquirido e composição desactivada; rascunho → submissão com uma reserva existente → aprovação por outra identidade → consulta com três versões/eventos. Base e role descartáveis removidas. Nenhum registo de dados ou direito do SGF de destino alterado.
**Limites de entrega:** esta composição ainda não foi aplicada ao destino. Falta a rotina operacional de aplicação atómica das sobreposições/código, preservação/reversão dos ficheiros do host e gestão dos caches/reinício de serviços. O ensaio usa configuração sem cache; não declara validada a activação com cache de rotas/configuração pré-existente. As alterações de configuração da prova foram seguidas de reinício do serviço PHP. `plan`/`migrate` continuam a preparar/conferir schema, sem aplicar estas sobreposições ou activar rotas. Não substituir esse procedimento por extracção cega do bundle. SGF de destino mantém **0.1.1**, sem schema, permissões, provider ou rotas alterados. Activação continua dependente da decisão separada. A reorganização modular posterior é uma entrega distinta, não concluída por este incremento.
## Objectivo e estado em 01/11/2026
O foco autorizado pelo proprietário é transferir as capacidades de Compras para o SGF e levar as melhorias seguintes por versões verificáveis. Não é sincronizar bases de desenvolvimento nem manter duas implementações. O SGC autónomo conserva todas as suas funcionalidades; no SGF, Pessoas e contratações destina-se apenas ao uso interno. Cada cliente recebe as capacidades adquiridas, com configuração e permissões próprias.
@@ -26,11 +126,12 @@ Estados: **Transferido** identifica a capacidade exacta instalada e executada no
| Cálculo de projecção de reposição | **Transferido** | Mesmo motor de consumo manual, média racional, reservas/entregas e lotes; sem persistência própria | Carregamento local independente do checkout de Compras; não concede acesso a dados | Sem novo ecrã; capacidade de cálculo instalada | Pacote activo `0.1.1`, dois testes SGF e prova de cliente independente |
| Orçamento de Compras no núcleo comum | **Parcialmente transferido** | `packages/budget-control` comum anterior; mesmo motor de reserva | Composição operacional candidata com destino/schema/âmbito explícitos; adaptador instalado continua QA | Interface anterior e candidata de requisições; arranque/rotas operacionais ainda não integrados | 20 controlos novos de preparação; restauro em production/base fora do prefixo QA verificado; sem instalação/activação no destino |
| Preparação de schema da integração | **Parcialmente transferido — candidata não instalada** | Migração transaccional, contrato do orçamento, registo imutável de revisão/hashes/operadores/backup | CLI `plan`/`migrate` local ao host, sem cópia de dados sintéticos ou concessões | Sem ecrã ou activação implícita; CLI de preparação não substitui instalação de código/rotas | Prova nova `sgf-operational-delivery.json`; destino 0.1.1 preservado |
| Aplicação/actualização/reversão do código da nova integração | **Parcialmente transferido — candidata não instalada** | Journal/backups e registo privado da versão, lock, preservação do bundle anterior; sem efeitos de dados/schema | CLI `plan/apply/cache/rollback`, com proveniência e contrato de schema iguais; serviços parados pelo operador | Transição, falhas e reversão ensaiadas; caches nativos compilados e servidor isolado reiniciado; nenhuma abertura automática no cliente | 32 controlos novos em `sgf-update-cache-delivery.json`, além das provas anteriores; caches personalizados e migrações futuras exigem plano próprio; destino 0.1.1 |
| Factura conferida → obrigação a fornecedor | **Parcialmente transferido** | Núcleo comum de obrigações anterior, com origem única | Adaptador SGF e API no âmbito sintético; sem passagem automática de tabelas/IDs de Compras | Consulta/decisão do percurso anterior; sem workflow integral de recepção/conferência de facturas de Compras | `SupplierPayables` conserva guarda de ensaio; fornecedor de histórico SGF não concluído conforme entregas anteriores |
| Pagamentos e afectações a fornecedores | **Parcialmente transferido** | Núcleo comum e entregas anteriores preservados | Adaptadores/autorizações delimitados nas respectivas entregas; não representam migração de contas ou histórico de cliente | Percurso anterior existe no âmbito documentado; integração completa com novas origens de Compras pendente | `SUPPLIER_SETTLEMENT_DELIVERY.md` e limites de histórico/origens; não afirmar financeiro integral |
| Identidade, empresa/unidade, perfis e módulos adquiridos | **Parcialmente transferido** | Fundações próprias existentes nos dois hosts; não se fundiram tabelas-base | SGF mantém tenant/empresa fiscal/unidade/concessões; correspondência explícita com o contexto Purchasing por concluir | Sessão/contexto SGF existentes; selector SGC não foi incorporado automaticamente | Sem associação por igualdade de nome, email ou ID; parametrização comercial e permissões continuam distintas |
| Reorganização modular do SGF pedida posteriormente | **Pendente — sem resultado apresentado** | Entrega distinta da integração candidata de requisições | Não avaliada nem concluída por esta conferência | Não inferir reorganização entregue a partir dos ecrãs candidatos | Exige apresentação própria do âmbito, alterações e resultado; não executada por arrasto |
| Requisição interna: rascunho, submissão, aprovação independente e consulta | **Parcialmente transferido — candidata; não activa** | Motor único `InternalRequisitions`, adaptadores dos dois hosts; recibos, versões e histórico; reserva existente na mesma transacção | Contexto interno, empresa/unidade, autorização renovada, identidade independente e fontes explicitamente associadas; sem novas concessões no destino | Rascunho/edição, lista, submissão, decisão, histórico e parametrização na candidata; sem novo menu/rota activa no SGF | HTTP, concorrência, revogação, falha/recuperação e schema em bases isoladas; equipamentos/peças e instalação comercial pendentes; destino 0.1.1 |
| Navegação modular do SGF, entrega própria | **Tecnicamente aceite — 02/11/2026** | Seis módulos, Início/Opções gerais separados; não equivale a todos os processos comerciais concluídos | Provas SGF próprias de contexto, autorização e perfis sintéticos; sem outorga adicional por escolha de módulo | Revisão visual/recargas, associações antigas e volume/paginação mantêm pendências próprias | Aceitação expressa em `MODULAR_NAVIGATION_DELIVERY/COMPLETION`; 185 testes/3.220 asserções preservados; não autoriza a instalação da candidata |
| Requisição interna: rascunho, submissão, aprovação independente e consulta | **Parcialmente transferido — candidata; não activa** | Motor único `InternalRequisitions`, adaptadores dos dois hosts; recibos, versões e histórico; reserva existente na mesma transacção | Contexto interno, empresa/unidade, autorização renovada e identidade independente; composição no provider e associação do novo direito de consulta ao módulo preparadas | Ecrãs e percurso integrados na cópia isolada pelo arranque nativo; nenhuma rota/menu novo activo no destino | Provas anteriores preservadas; novo ensaio de composição HTTP em `sgf-composition-delivery.json`; aplicação operacional do código/caches e equipamentos/peças pendentes; destino 0.1.1 |
| Planeamento de compras | **Pendente** | Itens, marcos e associação a requisições permanecem em Compras | Adaptar unidades, centros, intervenientes e vínculos de origem no SGF | Planeamento e acompanhamento de marcos SGF do roteiro de Compras pendentes | Não gerar requisições duplicadas nem inferir reserva/decisão a partir de um plano |
| Fornecedores, documentos e dados bancários | **Pendente** | Cadastros/versionamento de Compras ainda não extraídos | Definir correspondências autorizadas de fontes e permissões, sem fundir entidades por nome | Cadastro, validações e consulta SGF de todo o percurso pendentes | Preservar fotografias utilizadas e validação bancária independente |
| Cotações, descontos e comparação económica | **Pendente** | Descontos e pontuação foram preparados na origem/candidata `0.1.2`; SGF activo não contém estas classes | Elegibilidade, conflitos, avaliações autorizadas e decisão continuam no host; adaptador do processo SGF não implementado | Recepção de cotações, grelha, empates, recomendação e decisão SGF pendentes | Testes locais não equivalem a transferência. Candidata não instalada; nenhuma adjudicação automática |
@@ -230,3 +331,30 @@ O manifesto exige `database_changes=false` e o formato não aceita pastas de mig
- Fachada e motor comum passaram análise PHP dirigida. Fonte do mecanismo e artefactos SGF conferidos em `packages/module-updates/runtime-manifest.json`.
**Limitação central:** este mecanismo actualiza as capacidades já extraídas para o pacote; não transfere automaticamente melhorias ainda confinadas aos controladores/serviços/ecrãs de Compras. Continuar a migração pela matriz acima, sem declarar todo o SGF actualizado só porque a versão do pacote mudou. Não há publicação no domínio ou conclusão de integração de RH nesta entrega.
## Candidata utilizável de requisições — 02/11/2026
Esta secção actualiza a matriz para a candidata `OPERATIONAL-CANDIDATE-401ce31ae5f2dd20`, schema revisão 2, e substitui apenas as lacunas administrativas/orçamentais identificadas na proposta anterior. A distribuição instalada mantém **0.1.1**; não houve instalação/activação/publicação.
| Capacidade | Candidata / prova | Destino |
| --- | --- | --- |
| Dependências da interface orçamental | cb_ui_commands e cb_consumption_sources incluídas, estruturas existentes reutilizadas; 16 tabelas novas no total | Não migrado |
| Administração de direitos | Acessos React usa catálogo/rótulos do servidor, filtro por direito próprio e unidade; servidor valida delegação/revogação | Sem concessões |
| Centros e dotações | Formulário de centro, preparação pela API comum, aprovação independente; sem fixtures necessárias | Sem dados novos |
| Requisição básica | Consumível/serviço/outro → submissão e reserva única → aprovação distinta → consulta/histórico | Não activado |
| Equipamentos/peças | Rejeitados; fora do incremento | Não activado |
| Privilégios mínimos | Roles separadas, CREATE/ALTER negados ao runtime; mapa restringe ACLs herdadas só em objectos novos | Apenas proposta; não aplicada |
| Recuperação | Sucessor de código + rollback sem alterações de dados; dump restaurado e 103 tabelas reconciliadas, schema/decisão/reserva preservados | Sem restauro/mudança |
| Navegação | Código funcional 2a4169162bb4621a42a2ea1df627d52f860e7176 preservado; Início/Opções gerais separados | 19 hashes inalterados |
Provas afectadas: **157 controlos integrados + 17 React/render/assets + 54 aplicação/interrupção/recuperação de código**. Não são testes de carga ou revisão visual. As suites anteriores válidas são reutilizadas; as 87 comparações de ACL integram os 157 controlos. Bases/roles sintéticas removidas. Ver [prova consolidada](proofs/sgf-requisition-usable-candidate.json) e [proposta única revista](PURCHASING_INSTALLATION_PROPOSAL.md), com hashes/recuperação de código, schema e dados separados.
Pendências mantidas: revisão visual sem nova tentativa pela via bloqueada; associações antigas sem atribuição automática; volume/paginação; decisão posterior de instalação, mapa SQL e configuração/autoridades do destino. A candidata não inclui pagamentos/recepções/ordens/stock ou direitos reais por arrasto.
## Revisão da proposta para desenvolvimento sintético — 02/11/2026
A proposta SGF-IR-USABLE-401C-20261102 foi completada, sem execução: destino novo em C:/laragon/data/sgf-tempo/run/ir-usable-401c-20261102/app, HTTP8041, cluster55441/base sgf_ir_dev_401c_20261102, owner/runtime novos separados. Origem exclusivamente sintética 8039 preservada; as nove baselines são compatíveis. Fonte contém 93 tabelas (incluindo seis wc_* fora deste incremento), portanto migração nova será 93→109, não 87→103. Perfis #1/#2/#3 reutilizados somente na cópia; três contas sintéticas novas de administração/Compras/Financeiro propostas. Dotação fictícia 50 000 MZN/2026, limites 10 000/20 000, concessões exactas na proposta. Mapa SQL mínimo dirigido à role nova, não sgf_dev_app. Nenhum provisionamento, concessão, migração ou activação executados. Provas antigas reutilizadas sem declarar o destino novo testado. Ver PURCHASING_INSTALLATION_PROPOSAL.md e proofs/sgf-ir-synthetic-installation-proposal.json. A versão anterior da proposta ficou arquivada e não deve ser executada.
## Execução autorizada em 8039 — 02/11/2026
Concluída/conferida exclusivamente na demonstração existente 8039/base sgf_modules_dev_2576427d1939/55439/contexto1:1:1: 14 direitos (8/4/2), centro SINTETICO-REPRO/OPER, dotação 10 000 MZN/2026 por #1 aprovada por #2 e requisição de 100 MZN com reserva única e aprovação independente. Direitos/contas anteriores preservados, sem GRANT/REVOKE SQL ou novas contas. A proposta8041 permanece adiada. Ver SGF_REQUISITIONS_8039_DELIVERY.md e provas associadas. Consulta #3 tem listagem acessível mas 404 no registo de outro autor pela visibilidade existente; nenhuma ampliação de direitos/código foi feita. Backup anterior conferido; restauro efectivo deste backup não é declarado nesta passagem. SGF real/Tempo e 0.1.1 preservados; revisão visual/associações antigas/volume-paginação separados.
+121
View File
@@ -0,0 +1,121 @@
# Preparação dos módulos e do fluxo integrado SGF
Continuação financeira SGF: [recibo histórico de Compras para o núcleo comum](SGF_PAYABLE_HISTORY_RECEIPT_DELIVERY.md), implementado somente em bases novas de ensaio, com 10 cenários/56 asserções e 17 verificações HTTP. A fotografia histórica não constitui fonte viva, cutover operacional ou Financeiro completo; mantém paginação/carga financeira e implantação pendentes.
Continuação SGF mais recente: [encerramento individual de propostas Oficina → Stock](WORKSHOP_STOCK_PROPOSAL_CLOSURE.md), com retirada/recusa sem efeito físico e protecção contra confirmação concorrente. Não encerra as etapas financeiras/contabilísticas ainda em falta ou as pendências de implantação/visuais.
Continuações locais sintéticas posteriores: [recepção nativa no livro comum](STOCK_RECEIPT_LINK_DELIVERY.md), [saída por origem de Oficina](WORKSHOP_STOCK_DELIVERY.md), [ligação a entrega existente](WORKSHOP_DELIVERY_LINK.md), [repartição e devolução verificadas](WORKSHOP_MATERIAL_CYCLE.md) e [devolução nativa com observação SGF](NATIVE_WAREHOUSE_RETURN_DELIVERY.md). Estes incrementos superam partes da preparação inicial abaixo; não declaram todos os módulos completos nem uma composição operacional instalada. A última entrega consolida 36/544 provas próprias, preservando revisão visual e implantação como pendências separadas.
Primeira execução posterior: [leitor comum de Stock, API e interface SGF](STOCK_READ_DELIVERY.md), funcional exclusivamente com bindings sintéticos de teste. Entrega parcial: sem movimentos, sem actualização de demos ou segunda composição HTTP de Compras. As restantes etapas deste plano permanecem por implementar/ligar.
02/11/2026 — `SGF-MODULE-FLOW-PREPARATION-v1`. Pedido: começar a preparar as capacidades em falta para ligar etapas sem duplicar efeitos, criar gargalos evitáveis ou perder evidência. **Entrega desta passagem: inventário técnico verificável, mapa de ligações, contrato de evidência proposto e primeiro incremento delimitado. Não é a implementação dos motores operacionais em falta.**
Reutiliza o [plano de núcleo comum](PURCHASING_COMMON_CORE_PLAN.md), a [demonstração integrada](PRODUCT_DEMO.md), os percursos financeiros sintéticos existentes e a [consolidação de carga/concorrência/HTTP](MODULE_ASSOCIATION_LOAD_CONSOLIDATION.md). Não reabre aceitações nem apresenta menus como módulos operacionais completos.
## 1. Inventário actual e decisão de construção
| Área | Base a preservar/reutilizar | Preparação para completar |
| --- | --- | --- |
| Compras | Requisições básicas em 8039; processos, recepção e conferência existentes em Compras | Transferir por incrementos completos, com contexto e direitos explícitos; não activar candidatas por arrasto |
| Stock | `StockWorkflow`, `ReceiptWorkflow`, `InventoryLots`, `InventoryCounts`, `InventoryDispositions`, `InventoryReversals`, `WarehouseReservations` em Compras | Leitura comum paginada primeiro; depois escritor único/adaptadores e ligação a consumidores SGF |
| Oficinas | Ordem/autorização, apontamentos verificados, custo e conversão comercial existentes | Ligar consumo físico por origem e versão, sem transformar observações anteriores em movimentos |
| Comercial | Cadastro, rascunhos, B1, cálculos e emissão/PDF de teste | Preservar revisão comercial e origens; completar ligações e validação fiscal própria antes de uso real |
| Financeiro | Núcleos comuns de orçamento e obrigações; recebimentos, pagamentos/afectações e reversões sintéticos | Compor os percursos, delimitar reconciliação e fontes históricas; não criar um segundo saldo |
| Contabilidade | Classificação, perfis fiscais e menus | Motor de lançamentos, períodos, razão, fecho e relatórios com fontes rastreáveis; implementação ainda em falta |
**Actualização importante face ao menu antigo de Stock:** a inspecção actual encontrou código de lotes, contagens, devoluções/abates, reservas e estornos em Compras. A ausência dessas ligações no SGF não significa ausência na origem. Os hashes e caminhos estão no [inventário de preparação](proofs/module-flow-preparation-20261102.json). São evidência de existência de fonte, **não prova de execução, cobertura integral ou activação dessas capacidades**. A extracção deverá seguir essas dependências, não copiar apenas `StockWorkflow` isoladamente ou reconstruir funcionalidades já existentes.
O [manifesto do fluxo](integration/sgf-flow-plan.json) identifica seis módulos, treze etapas, um responsável por efeito, fontes, evidências de saída e lacunas. A verificação `scripts/inspect-module-flow-plan.mjs` confere caminhos/hashes, referências, responsáveis e ausência de ciclos nas dependências obrigatórias. Não carrega aplicações, não executa PHP nem consulta bases. Uma estrutura consistente não demonstra que a integração funcione.
## 2. Fluxo com ramos independentes
O desenho abaixo descreve o percurso sintético a construir, não ligações todas já activas. Os critérios específicos de cada documento permanecem nos serviços responsáveis.
```mermaid
flowchart LR
R[Requisição e ordem aprovadas] --> Q[Recepção e aceitação física]
Q --> S[Stock: movimento único]
R --> F[Factura de fornecedor conferida]
Q -. referências quando exigidas .-> F
F --> O[Financeiro: obrigação única]
O --> P[Pagamento confirmado e afectação]
W[Oficina autorizada e apontamentos verificados] --> C[Consumo de material da empresa]
S --> C
W --> D[Rascunho comercial revisto]
W --> K[Custo validado ou incompleto explícito]
C -. origem futura de quantidade/custo .-> K
D --> V[Factura de venda elegível]
V --> A[Conta a receber e recebimentos]
O -. efeito elegível .-> L[Contabilidade: lançamento e comprovativo]
P -. liquidação distinta .-> L
V -. efeito elegível .-> L
A -. recebimento distinto .-> L
S -. apenas com valorização definida .-> L
```
Regras para não criar dependências artificiais:
- A recepção aceite gera quantidade física; a factura não repete a entrada. Factura/obrigação não esperam pelo pagamento. Compras de serviços não passam obrigatoriamente pelo stock.
- Quantidade recebida e aceite são diferentes; as regras existentes de recepção parcial, rejeição, devolução e elegibilidade da factura são preservadas. A seta da recepção para a factura é condicional às regras existentes, não uma autorização para as omitir.
- A oficina não exige que um novo processo de compra seja aberto para usar stock já elegível. Material do cliente não é saída do stock da empresa. Apontamento técnico, consumo físico, custo e cobrança são efeitos separados.
- Custo incompleto fica incompleto; não bloqueia por decisão técnica toda a preparação comercial, nem é usado como preço de venda. A elegibilidade comercial continua explícita.
- A contabilidade consome cada efeito elegível individualmente. Não espera que toda a cadeia esteja liquidada, nem trata documento, dívida e pagamento como três reconhecimentos do mesmo principal. As regras de reconhecimento e contas ainda terão de ser delimitadas.
- Vencimento desconhecido é pendência documental visível; não é zero, data inventada ou bloqueio universal do reconhecimento. A fila de associações não atribui módulos automaticamente para desbloquear estas etapas.
## 3. Comprovativo exigido em cada passagem
| Passagem | Responsável único pelo efeito | Evidência necessária para o consumidor | Recusa/pendência que tem de ficar visível |
| --- | --- | --- | --- |
| Compra → recepção | Compras confere o documento físico | Origem/versão, linhas recebidas/aceites, qualidade, artigo/armazém explicitamente mapeados | Origem ou mapeamento ausente, quantidade incompatível, recepção parcial |
| Recepção → stock | Inventory grava uma vez; a fachada de recepção delega na mesma transacção | ID do movimento, origem única, quantidades/unidade, versão do livro, fotografia | Repetição incompatível, lote/âmbito inválido; sem segunda entrada por factura |
| Factura conferida → obrigação | Payables | Fotografia conferida, principal/moeda, origem e comprovativo de reconhecimento, responsabilidade histórica | Fonte incompleta/incompatível; ausência de vencimento sinalizada separadamente |
| Pagamento → afectação | Financeiro | Evidência factual, confirmação distinta, saldo disponível, comprovativo de afectação | Sem dinheiro inventado; afectação não equivale a execução bancária |
| Oficina → consumo | Inventory, a pedido da oficina | Ordem elegível, origem do material/versão, artigo/armazém, comprovativo de saída | Material do cliente, origem já consumida ou falta de stock/âmbito |
| Oficina → custo/rascunho | Custos valida custo; Comercial cria rascunho | Apontamentos verificados, versões de taxa/preço próprias, revisão exacta | Taxa ausente ≠ zero; custo ≠ preço; sem duplicar material/tempo |
| Documento/efeito → lançamento | GeneralLedger futuro | Origem elegível, regra de contas vigente, período aberto, débitos/créditos equilibrados | Classificação isolada não é lançamento; não usar menu/rascunho como prova de operação |
| Livro → relatório | Serviço de leitura do domínio | Âmbito, filtros/data de corte, versão da fonte, ligação aos comprovativos | Fonte indisponível não é saldo zero; relatório definido não é relatório gerado |
O contrato proposto no manifesto exige contexto/actor, origem por sistema/tipo/ID/versão/hash, tipo de efeito, decisão/data/fundamento, chave de repetição, correlação, âmbito de autorização e estado anterior/posterior. Quantidades usam a representação exacta do domínio (milésimos no stock); moeda e política de arredondamento acompanham efeitos monetários. Evidência original é identificada por referência protegida, sem copiar documentos privados para logs/relatórios técnicos.
**Este contrato ainda não está implementado como motor transversal.** Os comprovativos e auditorias existentes continuam a ser autoridade nos seus percursos. O consumidor terá de conferir autenticidade/âmbito/origem/versão, não apenas confiar nos campos enviados pelo browser. Uma correlação facilita rastreio, mas não substitui unicidade: a chave de efeito deverá incluir empresa, origem factual estável e tipo de efeito. Uma alteração de versão não autoriza repetir a mesma entrada; correcção/compensação tem origem própria ligada ao original. Nenhum ID igual entre aplicações prova correspondência empresarial.
## 4. Continuidade, falha e concorrência
Cada comando deve terminar com comprovativo ou pendência explícita. Antes da execução mostra a origem/versão e o impacto; na confirmação revalida permissões, contexto, versões e dependências. Evidência insuficiente impede apenas a operação dependente, conservando o restante trabalho e permitindo consulta/correcção.
Na mesma base, efeito, recibo de repetição e auditoria têm de ficar na mesma transacção. Uma fachada não deve chamar dois escritores concorrentes. Se houver envio posterior a outro domínio, a intenção e o resultado têm de ser duráveis, com estado consultável e repetição idempotente; não acrescentar broker remoto ou executor global antes de existir necessidade concreta. Os registos/outbox já existentes não passam a executar contabilidade por esta preparação.
Perda de resposta: consulta por chave/origem recupera o resultado. Mesma chave com conteúdo diferente recusa. Versão antiga exige nova conferência. Falha entre efeitos não pode apresentar o próximo como concluído. Corrigir não apaga o original: acrescenta decisão/compensação e exige a revisão aplicável. Não prolongar transacção durante o tempo humano de leitura/confirmação; não chamar serviços externos mantendo locks.
## 5. Evitar repetir os gargalos observados
O `StockController` de origem pagina movimentos, mas também lê todos os artigos/armazéns/saldos e consulta resumo de lotes por par. Isso é **um risco encontrado no código, não uma medição nova de lentidão**. A futura consulta SGF não deve copiar esse padrão integral para cada página.
- Paginar/filtar no servidor com ordenação estável; carregar metadados e referências necessárias, sem corpos documentais ou catálogos completos em cada resposta.
- Agregar movimentos/saldos/lotes para os pares da página em conjunto, sem uma consulta por linha. Filtros por saldo têm de ser aplicados antes de paginar, sem alterar os totais.
- Usar uma fotografia de leitura coerente e limitar o tempo de transacção. Revisão do livro e critérios de corte explícitos; versões por par não são substituídas por uma versão global arbitrária.
- Conservar por enquanto a ordem de locks e a protecção de saldo vazio da origem. A experiência da fila mostrou serialização por empresa; não remover esse lock apenas para melhorar um benchmark. Medir depois por tipo de escrita e dependência real.
- Medir tempo, consultas e memória por página; separar fonte, adaptador e renderização. Índices só na base sintética durante o ensaio e com ganho identificado separadamente. Não transportar automaticamente o índice da auditoria para o livro de stock.
Não se garante ausência de gargalos antes das medições. Estes são critérios de construção/verificação para os encontrar cedo, sem confundir provas locais com capacidade de implantação.
## 6. Ordem de entrega preparada
| Incremento | Resultado a demonstrar | Condição de avanço |
| --- | --- | --- |
| I1 — `SGF-STOCK-READ-SIM-v1` | Fonte comum/adaptador de consulta de artigos, armazéns, existências e movimentos | Âmbito delimitado em [STOCK_READ_SCOPE.md](STOCK_READ_SCOPE.md); fonte ausente, recusas, totais e paginação comprovados |
| I2 — recepção → stock | Mesmo escritor e origens de Compras nas duas composições | Paridade, atomicidade, idempotência e concorrência; sem migração de dados antigos por replay |
| I3 — oficina → consumo | Ligação explícita por origem/versão, com comprovativo físico | Sem saída duplicada; cliente/empresa separados; falta de saldo e correcção comprovadas |
| I4 — composição financeira | Reutilizar obrigação, liquidação e recebimentos existentes | Um responsável pelo saldo; histórico e evidências recuperáveis sem conciliação bancária presumida |
| I5 — primeiro lançamento sintético | Uma classe de efeito, regra de contas e período delimitados | Motor com equilíbrio, versão, unicidade, compensação e histórico; sem declarar contabilidade geral completa |
| I6 — relatórios e fecho | Leituras reconciliadas e depois fecho/reabertura delimitados | Relatórios rastreáveis ao livro; política de período/correcção antes de fechar |
O desenvolvimento destas capacidades pode correr por etapas com fontes sintéticas explícitas; não precisa de esperar por pessoas/dados reais, revisão visual pendente ou publicação. Uma etapa seguinte não deve usar uma simulação oculta como se fosse efeito operacional da anterior. A implementação de I1 é o próximo trabalho delimitado; esta passagem não a declara executada.
## 7. Prova e preservação desta preparação
Executar com o Node fixado: `C:/laragon/tools/sgf-tempo/node-v24.22.1-win-arm64/node.exe scripts/inspect-module-flow-plan.mjs`. O resultado é um inventário estático de fontes e consistência do desenho, não teste funcional ou ensaio de carga. Nenhuma suite válida anterior precisa de repetição nesta passagem documental.
Não se alteraram rotas, navegação, motores, configurações, dependências, schema ou direitos. Não se consultaram bases, manifestos privados ou credenciais. Os seis registos protegidos, a cache bloqueada, 8039 e outras demonstrações foram preservados. Compras foi lido apenas como fonte; sem alteração/activação de candidata. Sem publicação, push, checkpoint ou aceitação presumidos.
**Pendências independentes:** implementação das ligações delimitadas; provas funcionais por incremento; revisão visual; validação de capacidade/implantação; decisões individuais das seis associações. O inventário de fontes não encerra nenhuma delas.
@@ -0,0 +1,55 @@
# Compras → Financeiro SGF: recibo histórico de ensaio
02/11/2026 — `SGF-PAYABLE-HISTORY-RECEIPT-SIM-v1`. Adaptador SGF funcional sobre o núcleo comum existente. Entrega exclusivamente sintética, desactivada por defeito. Não é uma passagem operacional de responsabilidade financeira nem ligação histórica em tempo real.
## Lacuna e implementação
O núcleo `packages/payables` já incorporava pagamentos originais e o adaptador de Compras já fornecia esse histórico. O adaptador SGF não tinha fornecedor histórico nem rotas para preparar/validar essa incorporação. Agora `SupplierHistoryReceipts` lê recibos históricos explicitamente reconciliados com uma origem SGF, e `SupplierPayables` fornece-os ao mesmo `Payables`. Não se copiou o motor de saldo ou de dedução.
`POST /api/supplier-payables/prepare_history` e `.../validate_history` reutilizam o controlador, os fundamentos, a repetição, os direitos `prepare`/`validate` de `pa_access` e `supplier_payables.view`. A validação mantém identidade/pessoa distinta, bloqueios, revisão documental e hash histórico exactos. Nenhum novo direito ou acesso real foi concedido. A consulta e a página existentes apresentam a capacidade apenas quando ligada no ensaio. A interface identifica expressamente a fotografia de origem e a ausência de passagem operacional validada.
`config/supplier_payable_history.php` mantém `synthetic_enabled=false`, sem variável de activação operacional. A guarda SGF permanece limitada a `payable-testing` e bases `payable_sgf_<12 hex>`. O schema novo existe apenas na preparação explícita de uma base QA nova; não há migração, criação de tabela por acesso, publicação de recibos ou instalador operacional.
## Contrato do recibo
`pa_source_histories` guarda empresa/unidade SGF, origem local, versão positiva, payload, checksum e data, com unicidade por âmbito/origem/versão e protecção append-only. A leitura escolhe a versão mais recente **da origem e contexto exactos** e exige:
- Contrato `SGF-PAYABLE-HISTORY-RECEIPT-SIM-v1`, versão do payload igual à linha e checksum canónico íntegro.
- Identidade factual completa da origem (`instance/company/document`) e revisão documental iguais à factura local explicitamente mapeada. IDs iguais entre aplicações não são usados como correspondência automática.
- Histórico completo, sem pagamentos repetidos, com empresa/documento/moeda compatíveis, montantes exactos, estados e auditorias originais válidos.
- Hash da captura calculado pelo próprio `HistoricalPayments`, sem novo cálculo de saldo no adaptador.
Os hashes demonstram integridade/coerência, **não autenticam sozinhos um remetente externo**. Neste incremento, o produtor é a preparação QA controlada. Não existe endpoint público para inserir/alterar recibos, descoberta automática de dados antigos, sincronização nativa ou mecanismo de confiança/cutover para implantação. Uma futura publicação operacional terá de resolver essa autoridade e a actualidade dos factos, sem manter dois escritores da mesma dívida.
Recibo ausente, divergente ou antigo recusa o comando. Numa obrigação já reconhecida, divergência mantém o principal/histórico consultáveis e o saldo **indeterminado (`null`)**, sem converter falta de evidência em saldo zero ou bloquear toda a página. Uma captura diferente após preparação exige nova conferência. Confirmar pagamentos pendentes importados continua indisponível no SGF; não se instalou `pa_payment_decisions` nem se acrescentou essa rota.
## Cenário de origem efectiva e resultado
O ensaio criou duas bases novas com roles próprias no cluster de regressão 55439. Em Compras, reutilizou `PaymentFixture`, recepção, registo/conferência de factura e os workflows originais de pagamentos/banco sintético. Não simulou uma factura conferida apenas preenchendo um estado:
1. Factura de **60,00 MZN**, imposto documental zero conforme a fixture existente.
2. Pagamentos originais de **30,00 confirmados**, **10,00 pendentes** e **5,00 rejeitados**, com registo e decisões independentes pelos mecanismos existentes.
3. Preparação histórica pelo núcleo nativo, sem reconhecer uma obrigação comum na base de origem. Exportação apenas dos campos documentais e da captura histórica autorizada, sem conta bancária/referências cifradas.
4. Origem e recibo mapeados explicitamente na base SGF nova. Preparação e validação distintas reconhecem principal **60,00**, dedução histórica **30,00**, saldo **30,00**. Pendentes/rejeitados preservam estado e não abatem.
Vencimento e dias de atraso continuam nulos; atraso indeterminado. Não se recalcula imposto, executa transferência, confirma pendente ou cria lançamento/novo movimento de stock/orçamento por esta passagem.
As duas bases são composições de ensaio distintas. O facto de o SGF apresentar o saldo correcto **não comprova que instalações nativas e SGF operadas em simultâneo partilham uma autoridade financeira**. Não houve bloqueio/cutover operacional da origem; não se autoriza usar esta fotografia como fonte viva. Os originais da base nativa foram conferidos depois em transacção só de leitura: mesmos hashes e estados, zero obrigações comuns nativas reconhecidas.
## Provas e recuperação
[Relatório consolidado e hashes](proofs/sgf-payable-history-receipt-20261102.json): **10 cenários dirigidos / 56 asserções**, mais **17 verificações HTTP pelo kernel real**, sem navegador. Suites anteriores de Oficina, Stock, associações e financeira geral não foram repetidas. O núcleo financeiro não foi alterado; a apresentação comum recebeu apenas o aviso condicional específico do recibo SGF. A alteração é PHP/HTML e não exige novo build JavaScript.
Cobertura: configuração desligada e recusa no percurso antigo, principal integral/dedução única, independência, repetição da mesma chave e outra chave, integridade/identidade/versão do recibo, omissão/duplicação/empresa/moeda/auditoria, alteração histórica entre preparação e validação, revogação de competências, troca de pessoa/contexto, append-only, rollback integral e recuperação após falha de importação, consulta com saldo indeterminado e delegação pelo controlador existente.
Dois processos efectivamente concorreram pela mesma confirmação. O bloqueio da primeira transacção na empresa foi identificado por `pg_blocking_pids`; após o commit, a segunda operação terminou com o resultado original, sem duplicação. Resultado final: uma obrigação, uma incorporação, três pagamentos originais, um evento de reconhecimento e um de incorporação.
HTTP confirmou a mesma posição financeira/HTML, recusa de escrita pelo leitor, contexto obsoleto 409, CSRF ausente 419, injecção de contexto 422, repetição sem segunda dívida e configuração sem decisão de pendentes. O servidor temporário escutou apenas em loopback 8047; a prova encerrou somente o processo que criou. Credenciais, cookies e configurações ficaram na pasta privada, fora do relatório versionável.
Para nova prova: executar `scripts/payable-history-sgf-run.mjs` com o Node fixado; depois `scripts/payable-history-sgf-http.mjs <tag>`, postchecks `post,native-post` e `scripts/summarize-payable-history-sgf.mjs <tag>`. O runner cria novas bases/roles; não usar a regressão sobre a fixture cujo reconhecimento final foi preservado, nem fazer reset. Retomas nomeadas servem apenas para fases ainda não executadas e consultas posteriores. Evidências anteriores e diagnósticos ficam preservados, sem apagar bases.
## Limites e preservação
Pendentes: produtor/importador operacional autenticado, frescura/cutover/responsabilidade financeira, composição instalada, paginação/carga do leitor financeiro existente, revisão visual e capacidade de implantação. A listagem financeira herdada continua integral; este incremento não declara optimização de volume dessa área nem Financeiro completo. Pagamentos novos, decisões de pendentes importados, reconciliação bancária e contabilidade continuam fora deste recorte.
Os seis registos protegidos, cache bloqueada, demonstrações, bases/acessos reais, provas/checkpoints anteriores e trabalho alheio foram preservados. Sem publicação, activação de Compras, migração/concessão real ou checkpoint presumidos.
+41
View File
@@ -0,0 +1,41 @@
# Requisições internas — demonstração 8039
02/11/2026. Execução autorizada exclusivamente na demonstração persistente existente; estado final conferido por leitura, reutilizando as provas HTTP da própria execução sem repetir concessões ou operações. A proposta 8041 permanece adiada, não executada. Esta autorização específica prevalece sobre os textos anteriores de proposta pendente apenas no âmbito aqui descrito.
## Destino e resultado
Aplicação `C:/laragon/data/sgf-tempo/run/modular-regression-2576427d1939/development-app`, HTTP `http://127.0.0.1:8039`, cluster `sgf_modular_regression_2576427d1939`, base `sgf_modules_dev_2576427d1939`, porta 55439, role existente `sgf_modules_qa_2576427d1939`, contexto 1/1/1. São a empresa/unidade/contas sintéticas preexistentes, não a Tempo.
- Exactamente **14 direitos novos**: oito ao Preparador #1, quatro ao Revisor #2, dois à Consulta #3, conforme a tabela autorizada em `C:/laragon/www/compras/docs/proposta-desenvolvimento-sgf.md`. Comparação contra o backup confirmou preservação integral dos direitos anteriores e das contas; nenhuma conta criada.
- Centro **SINTETICO-REPRO**, referência/departamento **OPER**, centro ID1.
- Dotação ID1, **10 000,00 MZN**, exercício 2026, operating, inclui imposto; preparada por #1 e aprovada por #2.
- Política versão1 activa, orçamento obrigatório, limites com imposto de 10 000/20 000 MZN, vinculada ao contexto e centro autorizados. A demonstração só tem autoridade para a primeira etapa; não se acrescentaram identidades/direitos para etapas superiores.
- Requisição ID1, **100,00 MZN**, sem imposto, preparada/submetida por #1 e aprovada por #2; estado approved, versão3, histórico de três eventos.
- **Uma única reserva de 100,00 MZN** e uma única requisição; repetição da submissão não duplicou a origem. Disponível após reserva: **9 900,00 MZN**; não há consumo/pagamento por arrasto.
- Inicialização fechada (`initialisation_scopes=[]`). Os oito direitos autorizados do Preparador permanecem: a retirada dos seis direitos discutida para 8041 NÃO faz parte desta autorização.
Candidata 401ce31ae5f2dd20; ZIP SHA256 59dbdc64c4d9f14dfb4025a6177b829d136a4e2cb633ca036b10b5ae3197e703, manifesto a6478223e17a5430652f0fcbf31a44a931ae2a99cd90b151c98d2df5df43c10b. Código/schema preparados apenas nesta demonstração pelo procedimento próprio. Compras mantém 0.1.1, ponteiro preservado. A base sintética tem schema revisão2; as 16 tabelas adicionadas não alteram a instalação real.
## Verificações e limitação de consulta
As provas HTTP registam autenticação das três identidades, aprovação independente de dotação/requisição, recusa de auto-aprovação e recusa ao perfil Consulta de criação de centro, aprovação de dotação, configuração, preparação, submissão, decisão e administração de acessos. Preparador/Revisor consultam decisão/histórico.
**Limitação explícita:** Consulta #3 acede à listagem de requisições, mas a regra existente de visibilidade de registos devolve **404** para a requisição criada por #1. `purchasing_requisitions.view` não concede consulta transversal por si só. Não foram acrescentados direitos de aprovação/configuração nem alterado o código para abrir essa visibilidade. Caso se pretenda consulta transversal, exige âmbito/decisão próprios; não está entregue por esta autorização.
A conferência adicional foi READ ONLY: confirmou identidade física, 14 novos grants exactos, grants anteriores iguais, contas iguais, centro/dotação/política, aprovação #2, reserva única e configuração restrita. Não repetiu as operações válidas. Provas globais anteriores e testes de concorrência/recuperação continuam reutilizados, sem nova suite integral ou navegador.
## Recuperação preparada
Pasta privada: `C:/laragon/data/sgf-tempo/run/modular-regression-2576427d1939/private/requisitions-recovery`. Contém before.dump anterior à alteração, baseline, ficheiros/configuração anteriores e journal da aplicação.
SHA256 conferido do backup: `2eed6d9f775d8d5dc8c7b1606e230b8782c09a69098d31e659d9ad28a4d608fa`. O procedimento registou o dump e conferiu o seu índice. **Não se declara restauro efectivo deste backup nesta passagem**; as provas anteriores de restauro permanecem válidas no respectivo âmbito.
Em falha: manutenção apenas em 8039 e parar só o seu escritor identificado, sem parar PostgreSQL nem outras demonstrações; desactivar a composição nesta aplicação antes de recuperar código pelo deployment id/journal. Rollback de código não reverte schema/dados. Depois do commit, conservar schema aditivo compatível ou preparar correcção deliberada. Recuperação de dados exige restauro do dump numa base alternativa, reconciliação e decisão sobre operações posteriores; não sobrescrever automaticamente esta demonstração nem a Tempo. Não usar provisionadores destrutivos, reset da base ou GRANT/REVOKE para recuperar. Se for necessária outra base/comando fora do âmbito autorizado, parar e apresentar essa alteração.
## Preservação e pendências
Sem novos GRANT/REVOKE SQL, roles, contas, 8041 ou publicação. A role proprietária existente foi reutilizada: separação owner/runtime e privilégio mínimo SQL **não são propriedades desta demonstração**. Esse limite permanece explícito, sem aplicar os planos SQL da proposta adiada.
Snapshot do SGF real igual ao anterior: 89 grants, duas pertenças, 162 eventos de identidade, guarda e ponteiro 0.1.1 inalterados. Sem alterações à Tempo ou sgf_tempo_dev. Navegação modular e alterações locais preservadas. Revisão visual, associações antigas e volume/paginação continuam separados; nenhuma associação antiga automática ou tentativa pela via de navegador bloqueada.
Evidências: [execução](proofs/sgf-demo-8039-delivery.json), [HTTP](proofs/sgf-demo-8039-http.json), [reconciliação final](proofs/sgf-demo-8039-reconciliation.json). Credenciais existentes permanecem no registo privado development.json, sem as publicar ou alterar.
+2
View File
@@ -1,5 +1,7 @@
# Menu de Stock no SGF
Preparação posterior, 02/11/2026: [fluxo integrado](SGF_MODULE_FLOW_PREPARATION.md) e [consulta comum delimitada](STOCK_READ_SCOPE.md). A inspecção actual encontrou também fontes `InventoryLots`, `InventoryCounts`, `InventoryDispositions`, `InventoryReversals` e `WarehouseReservations` em Compras. As ausências identificadas no inventário histórico abaixo não devem ser usadas para reconstruir essas capacidades sem conferir a fonte actual. Isto não declara a sua integração/activação no SGF: o menu continua informativo.
29/10/2026. Implementada a estrutura de navegação do documento **Menu Stock.docx**, com estado de disponibilidade explícito. **Não está entregue um motor operacional de stock no SGF.** A composição SGF ainda não tem fonte de armazéns/saldos/movimentos ligada. Compras conserva a sua implementação e os seus dados.
## Referência e leitura do existente
+52
View File
@@ -0,0 +1,52 @@
# Stock comum — consulta ligada às duas aplicações
Continuação posterior: [recepção aceite → movimento comum → consulta do mesmo livro pelo SGF](STOCK_RECEIPT_LINK_DELIVERY.md). Ficou comprovado o recorte nativo de recepção/escrita e observação SGF em QA; a preparação/confirmação de recepções na composição ERP SGF e o consumo da oficina continuam pendentes. As provas desta consulta abaixo conservam o âmbito original.
02/11/2026. `COMMON-STOCK-READ-COMPOSITION-SIM-v1`, continuação funcional da [consulta SGF](STOCK_READ_DELIVERY.md). **As APIs SGF e Compras foram ligadas ao mesmo leitor e ao mesmo protocolo de leitura**, com prova de equivalência no kernel HTTP real de cada aplicação e autorização própria. Não se declara integração operacional de recepções, consumo de oficina, contabilidade ou implantação real.
## Código e composição
`packages/inventory-read/src/InventoryReader.php` mantém exactamente o hash da entrega anterior e continua a ser a única implementação da consulta. O protocolo de transacção READ ONLY / REPEATABLE READ, referência cifrada de dez minutos e recusa por mudança foi extraído do controlador SGF para `InventoryReadSession.php`, no mesmo pacote. O adaptador SGF delega nesse protocolo; não se criou outra consulta ou versão de saldo para Compras.
Compras recebeu `CommonStockReadController` e `GET /api/stock-read`, dentro do grupo existente de autenticação, organização, empresa configurada e contexto de trabalho. O adaptador recarrega o actor e reutiliza as funções nativas Admin/Armazém/Procurement/Finanças da consulta de Stock; revalida perfis configurados, recusa manutenção e exige mapeamento explícito dos armazéns por tenant/actor. **Não foram criados direitos funcionais novos em Compras.** A origem não pode indicar outro tenant. Não se identificam contas ou empresas entre aplicações por nomes ou IDs coincidentes.
Cada aplicação tem bindings vazios por omissão e guardas QA próprias. O SGF mantém `stock.view` na unidade e token de contexto/módulo. Compras admite esta ligação experimental apenas em `testing`, numa base `stock_read_compras_<12 hex>`, role própria correspondente, porta 55439 e cluster de regressão conferido. Não foi aberto o percurso real pela remoção de guardas.
## Uma fonte de código e artefacto verificável
Fonte canónica: `sgf-tempo/packages/inventory-read`. Distribuição local para Compras: `packages/inventory-read/releases/0.1.0`, com três ficheiros e manifesto imutável. A cópia é um artefacto do mesmo código, não um segundo motor mantido separadamente. `scripts/package-inventory-read.mjs` recusa substituir uma versão com conteúdo diferente.
Manifesto SHA-256: **bbd97f63b0eeb671bd3ad57bbd62bd34fcf67b8e943320423715d514a2a2c19c**. Compras verifica o hash esperado do manifesto e os hashes dos três ficheiros antes de carregar o pacote local. A prova também compara todos com a fonte canónica. O pacote de Compras não aponta para a pasta SGF em runtime; não há consulta remota ou leitura cruzada de bases. A versão 0.1.0 deste leitor **não é uma versão/candidata de Purchasing**; o apontador de Compras instalado não foi alterado.
## Provas executadas
| Prova | Resultado |
| --- | --- |
| Aplicação Compras: middleware, API e autoridade nativa | **1 teste / 73 asserções** |
| SGF: casos funcionais afectados pela extracção do protocolo | **2 testes / 77 asserções** |
| Comparação entre as aplicações | **1 teste / 48 asserções**, **12 cenários equivalentes** |
| Pós-checks | Role Compras sem superuser/criação de base/role/replicação/bypass; SGF com zero grants Stock temporários e restrição original reposta |
A composição Compras arrancou numa cópia privada da aplicação real com os seus providers, rotas, modelos, autorização e middleware. Usou uma **base nova e role nova restrita**, separadas de `compras_dev`, das demonstrações e da regressão SGF. O SGF usou apenas a sua regressão isolada existente, com âmbito/actores/schema novos. Ambos no cluster QA 55439. Não se executou migração/reset de qualquer base existente.
O primeiro arranque da cópia Compras falhou antes de preparar tabelas por faltar um pacote já exigido pelo seu provider. Copiaram-se para a cópia QA as dependências locais existentes de Purchasing, orçamento e Payables; retomou-se **a mesma base ainda vazia**, sem a apagar. O teste impede adoptar uma base com tabela `users` já existente. A versão do leitor foi conservada e verificada; nenhuma dependência Composer foi actualizada/instalada.
Os 12 cenários comparam **hashes exactos das linhas e paginação**, excluindo tokens específicos da aplicação: quatro consultas × páginas 25/100, segunda página de existências, última página do catálogo, armazém autorizado sem movimentos e pesquisa selectiva. Fixtures equivalentes, separadas, com 100 artigos com movimentos, um sem movimentos, dois armazéns autorizados e ruído de armazém/tenant inacessível. Saldo de 10−2=8 unidades exactas por artigo. Não são cópias de dados reais.
Compras verificou sessão sem actor (401), função indevida (403), armazéns fora do mapeamento (403), filtros arbitrários (422), token inválido/antigo (409), actualização após nova linha, fonte ausente/incompatível (503), recuperação e revogação/restauro de permissão num perfil configurado. O SGF verificou novamente os seus casos funcionais e recusou o token da composição Compras. Nenhum documento privado ou snapshot bruto foi devolvido.
As sessões de teste são pré-autenticadas com identidades sintéticas (`actingAs`); os pedidos atravessam os kernels HTTP reais das duas aplicações. **Não se afirma que tenham sido testados login/MFA, rede, servidor HTTP implantado ou navegador.** Também não se afirma sincronização entre bases: cada instalação lê o seu livro, com a mesma implementação.
## Desempenho e preservação
Não houve novas medições de carga. O SQL do leitor não mudou; as 72 leituras de 1 000/5 000/10 000 da entrega anterior permanecem válidas para a fonte e condições então medidas. A extracção foi coberta por testes funcionais/paridade. Não atribuir os tempos antigos ao middleware de Compras, que não foi medido neste incremento. Sem índices novos, alterações de UI ou repetição de build/navegador/suites alheias.
Grants `stock.view` e extensão de restrição SGF foram temporários no ensaio, com reposição final; nenhum direito público/real foi concedido. A nova base Compras, as suas identidades e as fixtures SGF foram retidas como evidência sintética; não se declara rollback de toda a preparação. Segredos e o token de comparação permanecem no directório privado e não integram a [prova sanitizada](proofs/stock-read-composition-20261102.json).
Os seis registos protegidos, a cache bloqueada, demos, dados/configurações anteriores, alterações alheias e provas válidas foram preservados. Sem activação de candidata, publicação, checkpoint ou aceitação presumidos. Os endpoints existentes de stock/movimentos em Compras não foram substituídos.
## Próximo ponto funcional
A pendência **API de consulta da segunda composição** fica coberta neste recorte. Permanecem: ligar a página nativa de Compras à consulta comum se for esse o destino escolhido; disponibilizar demonstração persistente própria; extrair/delegar recepção → escritor único de movimentos; depois ligar consumo de material da oficina por origem/versão. A consulta não pode confirmar entradas ou diminuir stock. Reservado/bloqueado/disponível, valorização e documentos de origem completos continuam fora deste incremento.
**Revisão visual e capacidade de implantação continuam pendentes e separadas.** Para repetir deliberadamente: `stock-read-composition.mjs` cria uma nova composição QA; só admite retoma de base vazia através do identificador privado. Depois `stock-read-regression.mjs cross <prova privada nativa>` compara o SGF. Não apontar estes testes a clientes ou demos. O artefacto é distribuído pelo script próprio, sem modificar o apontador de Purchasing.
+76
View File
@@ -0,0 +1,76 @@
# SGF — primeira ligação funcional de consulta de Stock
Continuação posterior: [API de consulta ligada às duas aplicações](STOCK_READ_COMPOSITION_DELIVERY.md). A pendência da segunda composição de consulta ficou coberta no recorte sintético de API; a página nativa Compras, a demonstração persistente e os escritores/recepção/consumo continuam separados. Os resultados abaixo conservam as fontes e condições da primeira entrega.
02/11/2026. `SGF-STOCK-READ-SIM-v1`, **entrega parcial sintética** do [âmbito preparado](STOCK_READ_SCOPE.md). Existe agora código funcional de consulta comum e adaptador/interface SGF. Não estão entregues as operações de stock, a ligação oficina/recepção nem a segunda composição HTTP de Compras. Não se declara o módulo integral concluído.
## O que ficou implementado
- Pacote `packages/inventory-read`: projecção de leitura do modelo de artigos, armazéns e livro físico existente em Compras. Sem copiar `StockWorkflow`, novo escritor de movimentos ou tabela de saldos concorrente.
- `GET /api/stock-read`, pertencente ao módulo Stock: artigos, armazéns, existências físicas por par e movimentos, com pesquisa, filtro por armazém e páginas de 25/100. Ordenação e totais calculados no SQL; sem carregar catálogos/livro completos no PHP ou consulta por linha.
- Interface de consulta em **Stock → Existências**, apenas quando a identidade tem `stock.view` na unidade. A consulta apresenta os quatro percursos, pesquisa, páginas, origem/referência de movimento, unidade exacta e referência de leitura. Os restantes ecrãs continuam informativos; não surgem comandos de entrada/saída.
- Fonte ausente/incompatível devolve indisponibilidade explícita (503), sem transformar ausência em saldo zero. Reservado, bloqueado, disponível e valorização não são inferidos. Só se apresentam pares com movimentos elegíveis; artigo sem movimentos continua consultável no catálogo.
**Estado de ligação:** a fonte operacional está vazia por omissão. O adaptador admite exclusivamente `APP_ENV=testing`, guarda física de base QA e schemas sintéticos próprios; não liga à pasta/base Compras em runtime. As fixtures reproduzem o recorte de leitura do schema de origem. Isso permite desenvolver o leitor e o consumidor SGF sem alterar o escritor existente, mas **não comprova recepção → movimento entre as duas aplicações nem paridade entre dois hosts HTTP autenticados**. A incorporação comum na composição de Compras permanece trabalho seguinte.
## Isolamento, permissão e coerência
Direito proposto no âmbito: **`stock.view` na unidade**. Não concede cadastro, movimento, custo ou todos os armazéns. O adaptador exige ainda contexto/módulo Stock e token de geração actual. Cada contexto é mapeado explicitamente para tenant da fonte e lista de armazéns; os IDs da fonte não são assumidos iguais aos IDs SGF. Company view, administração ou direitos de oficina não substituem Stock.
A base tinha uma restrição SQL que ainda não reconhecia esse direito. No ensaio foi estendida **apenas a restrição da base de regressão**, criados grants para actores novos QA e, no final de cada teste, retirados esses grants e reposta a definição anterior. **Não há migração de destino, nova concessão real ou activação em 8039.** O pós-check READ ONLY confirmou zero `stock.view` remanescentes, restrição sem o direito e zero bindings activos fora da configuração de teste. Antes de usar noutro ambiente será preciso um incremento de schema/direitos e fonte delimitado, não simplesmente retirar a guarda testing.
Cada pedido usa transacção própria **READ ONLY / REPEATABLE READ**, com 3 s de limite SQL apenas nessa transacção. Não usa locks de escritor. A página e os seus totais/revisão provêm da mesma fotografia. O token cifrado vincula actor, contexto, mapeamento, filtros/tamanho de página e revisão; expira após dez minutos. Mudança de catálogo, movimentos, âmbito ou token provoca **409**, exigindo consulta actualizada. Não é um arquivo histórico as-of: qualquer alteração relevante invalida a continuação. Contagem/max do livro pressupõem fonte append-only, como no modelo de origem e no trigger da fixture; não deve ser ligada uma fonte mutável sem rever o protocolo.
Quantidades são `quantity_milli`, somadas em SQL e devolvidas como cadeias exactas; o frontend usa `BigInt`, sem float. A resposta exclui o snapshot bruto, custos e documentos privados, mantendo identificador/referência segura do movimento. A proveniência documental completa/consulta do documento original permanece dependente do futuro adaptador de origem; esta leitura não a inventa.
## Provas executadas e reutilizadas
Só a base **sgf_tempo_test / sgf_test_runner / porta 55439 / cluster sgf_modular_regression_2576427d1939** foi usada. Guarda física conferida antes de mutações. Schemas novos `sgf_stock_read_<12 hex>` e identidades novas foram conservados exclusivamente na regressão; sem reset, migração dos dados antigos ou limpeza das fixtures anteriores. Os grants temporários foram removidos e a restrição reposta; não se declara rollback de toda a preparação sintética.
| Prova | Resultado |
| --- | --- |
| Primeira suite Stock | 3 testes / 465 asserções aprovados, incluindo carga/percurso de páginas |
| Casos funcionais finais, após tratar fonte incompatível e ampliar recusas | 2 testes / 77 asserções aprovados; substituem os dois casos anteriores, não são cobertura adicional a somar |
| Carga válida conservada dessa suite | 1 teste / 398 asserções; 24 perfis, 72 pedidos medidos; percurso integral das páginas de existências nas três escalas |
| Navegação afectada pela propriedade do endpoint | 8 testes / 90 asserções aprovados |
| Frontend | Compilação Vite aprovada; renderização estática, direitos separados e quantidades exactas aprovados |
| Pós-check e provas anteriores | Zero grants Stock temporários, restrição reposta, bindings vazios; hashes das provas da fila preservados |
Cobertura: 10−2=8 unidades físicas por artigo; duas unidades/armazéns elegíveis contra ruído restrito e de outro tenant; catálogo sem movimentos; origem/documento privado excluído; pesquisa literal `%`; acesso indevido; parâmetro de contexto arbitrário; POST sem rota; versão de catálogo/livro antiga; contexto antigo; revogação; fonte ausente/incompatível e recuperação. Comparação directa com o leitor comum usa a mesma fixture autorizada; **não é a segunda composição de Compras**.
Uma tentativa inicial foi desfeita por a restrição SQL recusar o direito novo, levando à extensão QA temporária com reposição. Na ampliação do teste, uma ordem incorrecta de pedidos deixava o cabeçalho antigo activo antes de testar validação 422; corrigiu-se o teste e repetiram-se apenas os dois casos funcionais. A matriz válida não foi repetida. A primeira tentativa SSR atingiu timeout com os plugins da aplicação; o check foi isolado da configuração de desenvolvimento e passou. A cache bloqueada não foi limpa nem usada para contornar esse resultado.
## Medições novas deste leitor
Três amostras por perfil, kernel HTTP aquecido em processo, sem concorrência. N significa **N artigos com movimentos**, mais um artigo sem movimentos; N pares elegíveis de saldo, **2N movimentos elegíveis**, dois armazéns autorizados e ruído inacessível. Não significa N armazéns. A preparação ficou fora da medição; sem experiências de índices, além das chaves primárias das tabelas QA. Os filtros e as tabelas diferem da fila de associações: estes tempos não são um antes/depois daquela optimização.
| N | Consulta | Página | Mediana ms | Consultas instrumentadas | Memória incremental máxima KiB |
| ---: | --- | ---: | ---: | ---: | ---: |
| 1 000 | Existências | 25 | 28,570 | 15 | 79,09 |
| 1 000 | Existências | 100 | 32,412 | 15 | 197,31 |
| 5 000 | Existências | 25 | 99,207 | 15 | 79,09 |
| 5 000 | Existências | 100 | 92,208 | 15 | 197,31 |
| 10 000 | Existências | 25 | 143,295 | 15 | 79,09 |
| 10 000 | Existências | 100 | 146,565 | 15 | 197,31 |
| 1 000 | Movimentos | 25 | 27,426 | 15 | 80,78 |
| 1 000 | Movimentos | 100 | 25,314 | 15 | 207,86 |
| 5 000 | Movimentos | 25 | 96,232 | 15 | 80,78 |
| 5 000 | Movimentos | 100 | 76,294 | 15 | 207,86 |
| 10 000 | Movimentos | 25 | 122,667 | 15 | 80,78 |
| 10 000 | Movimentos | 100 | 121,913 | 15 | 207,86 |
As 15 consultas incluem sessão/contexto/permissões, controlo da transacção e leitura; o leitor faz cinco operações SQL (três de revisão/metadados, total e página), independentemente do número de linhas devolvidas. Sem N+1 observado neste recorte. Memória incremental não inclui todo o processo ou PostgreSQL. Artigos/armazéns e todas as amostras/picos/tamanhos constam da [medição completa](proofs/stock-read-load-20261102.json).
A revisão ainda varre/agrega metadados da fonte no SQL; contagem e soma dos movimentos também crescem com o histórico. O aumento de latência nas escalas está visível, não escondido por cache. Antes de ampliar, avaliar planos/filtros e índice específico do livro em ensaio próprio, separando esse ganho; não criar cache persistente ou saldo paralelo como atalho. Não foram medidos cauda, escritores concorrentes ou saturação.
O tratamento final de erro de fonte foi acrescentado depois da medição. O leitor e o percurso SQL de sucesso ficaram iguais; os hashes do controlador medido e final são registados separadamente no [resumo](proofs/stock-read-summary-20261102.json), com os testes finais. Não atribuir ao ramo de falha uma medição que não foi feita.
## Continuidade e limites
Próximo incremento: preparar o adaptador de consulta da composição Compras sobre **este mesmo leitor**, demonstrando equivalência com autenticação/contexto próprios. Depois, recepção → escritor único e, separadamente, oficina → consumo físico. A operação de movimento não será construída dentro do leitor nem executada ao consultar o saldo. Financeiro e Contabilidade conservam os seus efeitos e pendências no [plano de ligações](SGF_MODULE_FLOW_PREPARATION.md).
O código é local. Nenhum servidor/demonstração foi actualizado ou reiniciado nesta entrega; a configuração de fonte é exclusivamente de teste e não fica acessível em 8039 por consequência do código. Ficam pendentes a demonstração persistente própria, a segunda composição e a integração operacional. Não se liga esta fonte à instalação real apenas editando configuração.
Os seis registos protegidos, a cache bloqueada, alterações alheias e provas válidas foram preservados. Não se alterou Compras, activou candidata, concedeu direito público, publicou ou criou checkpoint. **Revisão visual e capacidade de implantação permanecem pendentes**, separadas das provas de API, renderização estática e build.
Ferramentas: `scripts/stock-read-regression.mjs` (suite nova), opção `functional` (apenas casos funcionais), `scripts/stock-read-ui-check.mjs` (SSR sem configuração de servidor) e `scripts/stock-read-state.php` (pós-check READ ONLY). Usar PHP/Node fixados e `sync` da cópia de regressão; não `prepare/reset` ou PHPUnit em demonstrações.
+59
View File
@@ -0,0 +1,59 @@
# SGF-STOCK-READ-SIM-v1 — primeiro incremento preparado
Actualização de implementação, 02/11/2026: [consulta funcional comum e adaptador SGF entregues parcialmente em ensaio sintético](STOCK_READ_DELIVERY.md). Fonte/rotas de Compras, duas composições HTTP e demonstração persistente própria continuam pendentes. O âmbito abaixo conserva o critério da entrega completa; não se declara todo executado.
02/11/2026. Estado: **âmbito técnico preparado, implementação não iniciada nesta entrega**. Parte da [preparação do fluxo integrado](SGF_MODULE_FLOW_PREPARATION.md). Não activar o menu operacional até existir fonte e prova; o estado informativo actual permanece verdadeiro.
## Resultado pretendido
Permitir que uma identidade sintética autorizada consulte artigos, armazéns, existências e movimentos no SGF a partir de uma capacidade comum reutilizada de Compras. Não copiar o motor de stock nem criar um segundo saldo. A composição autónoma conserva os seus percursos e dados. A consulta não depende da pasta de desenvolvimento Compras em runtime: essa pasta é fonte de extracção, não fornecedor remoto de dados.
A primeira implementação deverá separar contexto/autorização, repositório de leitura e apresentação. Reutilizar o schema/modelo de movimentos e quantidades existentes em ensaio isolado; não executar `StockController` da outra aplicação sobre a base SGF nem equiparar tenant Compras com tenant/empresa SGF. A extracção ficará num pacote comum com adaptadores locais; a fronteira final só pode ser fechada após inventariar modelos/scopes e dependências.
## Incluído e excluído
Inclui pesquisa paginada de artigos/armazéns, existências por artigo/armazém e histórico de movimentos; filtros no servidor, página/data de corte, origem e versão do livro. Valores nulos ou fonte indisponível são apresentados como tal, não como zero. A falta de autorização não devolve nomes, quantidades, existência de outra empresa ou custos.
Sem criação de artigos/armazéns pela interface, recepções, saídas, transferências, contagens, ajustes, devoluções ou estornos neste primeiro incremento. Sem replay de movimentos históricos, saldos iniciais reais, valorização inventada, ligação automática à oficina, emissão, pagamentos ou lançamentos. Lotes/reservas só aparecem quando a fonte já consegue demonstrar a sua semântica e autorização; não calcular disponível como físico menos zero por ausência de fonte de reservas. Funções fora do recorte permanecem explicitamente indisponíveis.
## Contexto e direitos propostos — não concedidos
Reutilizar sessão/contexto SGF, direitos administrativos existentes para a sua própria função e verificações no servidor. `company.view` e ver o menu de Stock não autorizam consultar armazéns. Antes de implementar/conceder, fechar a proposta:
| Direito candidato | Âmbito proposto | O que não concede |
| --- | --- | --- |
| `stock.view` | Empresa e unidades/armazéns explicitamente elegíveis | Cadastro, movimento, custo ou acesso implícito a todos os armazéns |
| Direito específico de custos, nome a delimitar | Separado, só se uma etapa futura incluir valorização | Não faz parte da consulta inicial nem é herdado de `stock.view` |
Se o mecanismo de grants SGF não representar armazéns, a primeira etapa limita os armazéns por relação explícita com empresa/unidade e nega qualquer correspondência ambígua; não inventar concessões de armazém em campos sem suporte. A decisão precisa de estar no adaptador e em testes, não em comparação de nomes/IDs. Contas QA próprias recebem apenas direitos sintéticos do ensaio; nenhuma concessão pública/real ou em demos existentes.
## Consulta e evidência
Página 25 por omissão, opção 100 e limite 100, ordenação por identificador estável com desempate quando necessário. Artigos/armazéns usam selecção pesquisável e paginada. Totais respeitam todos os filtros e o isolamento. Não retornar todo o livro para paginar em PHP/browser.
Para existências, agregar no SQL e seleccionar apenas os pares da página; totais de pares/filtros não podem ser calculados a partir de uma página de movimentos. Para o histórico, página ordenada, referência à origem elegível e versão/corte consultados. Quantidades em `quantity_milli` são inteiros exactos; unidade não é inferida de moeda ou descrição. A API devolve metadados mínimos; fotografias/documentos completos têm consulta protegida própria quando necessária.
Não adicionar cache entre pedidos que esconda revogações ou alterações. Paginação normal sobre livro que muda não garante percurso integral sem repetição/omissão: escolher corte/revisão e provar essa semântica. Uma página com novo contexto não pode reutilizar a resposta do contexto anterior. Não adquirir locks de escritor para simples leitura; usar coerência de snapshot/corte conforme o repositório.
## Cenário sintético e provas a executar na implementação
Preparar base e identidades próprias, fisicamente isoladas da demonstração e dos seis registos protegidos, sem `prepare/reset` em clusters existentes. Dois âmbitos empresariais, duas unidades, armazéns autorizados e reservados; artigo com movimentos e outro sem movimentos elegíveis. Preparação controlada da fixture não é endpoint operacional de entrada.
| Caso | Evidência de conclusão exigida |
| --- | --- |
| Fonte inexistente/incompatível | Estado explícito de indisponibilidade, sem saldo zero fabricado ou leitura cruzada |
| Consulta exacta | Soma de entradas/saídas e versão coincidem com o livro sintético; sem float |
| Filtros/páginas | 1 000/5 000/10 000 registos, páginas 25/100; totais, ordem, última página e cobertura exactos num corte fixo |
| Isolamento | Outra empresa/unidade/armazém recusados; sem dependências ou nomes expostos |
| Revogação/contexto | Pedido seguinte revalida o acesso; resposta antiga ignorada pelo cliente |
| Livro em alteração | Snapshot/corte demonstrado; nenhuma mistura silenciosa de saldo e revisão incompatíveis |
| Carga | Tempo, número de consultas, memória incremental/pico e tamanho da resposta; mesmos dados/condições; sem consulta por linha |
| Índices | Ganho separado de batching/projecção; só ensaio sintético, plano/catálogo preservados |
| Falha/retoma | Falha de leitura não grava movimento; reentrada recupera consulta sem alterar o livro |
| Duas composições | Mesma fonte comum e resultados equivalentes no recorte, sem exigir vendas SGF no Compras autónomo |
Não executar esta matriz antes de existir o adaptador. As provas válidas da fila não comprovam desempenho de Stock. A revisão visual terá o seu guião quando houver interface funcional, sem repetir a via de navegador bloqueada. Capacidade de implantação exige servidor/recursos/carga e política próprios; não se declara a partir da fixture.
## Critério de entrega
Código de leitura comum/adaptadores, interface honesta, provas de equivalência/isolamento/retoma, medições comparáveis e limitações documentadas. Sem migração ou concessão de destino por consequência do ensaio. Se a fonte só estiver disponível numa composição, declarar parcial; não apresentar dois motores ou fixtures desconexas como integração concluída.
+68
View File
@@ -0,0 +1,68 @@
# Recepção aceite → movimento único → consulta SGF
Continuação delimitada: [Oficina → saída física conferida](WORKSHOP_STOCK_DELIVERY.md). A prova de recepção deste documento mantém o seu âmbito; a continuação usa outro cenário sintético e não representa um percurso integral instalado.
02/11/2026. `COMMON-RECEIPT-STOCK-SIM-v1`. **Primeiro fluxo de escrita ligado e comprovado:** o circuito real de recepção de Compras valida e confirma uma recepção sintética, delega a gravação física no núcleo comum e o SGF consulta o mesmo movimento no livro de origem. Não se copiou o saldo para outro livro nem se criou uma recepção fictícia no SGF.
Continua a [consulta nas duas composições](STOCK_READ_COMPOSITION_DELIVERY.md) e o [plano entre módulos](SGF_MODULE_FLOW_PREPARATION.md). É um incremento delimitado: **a preparação/confirmação de recepções na interface SGF ainda não está entregue**; a autoridade de recepção exercitada é a implementação existente de Compras. O ensaio não equivale à instalação completa do módulo de Compras no ERP.
## Implementação e responsabilidades
`packages/inventory-write/src/ReceiptMovementWriter.php` extrai a gravação antes feita directamente em `ReceiptWorkflow`. Há agora uma chamada única pelo adaptador nativo `ReceiptStockMovement`; não há fallback para outro escritor de recepções. O pacote é distribuído como artefacto local verificado em Compras, `packages/inventory-write/releases/0.1.0`. Manifesto SHA-256 **f0b99e591f9a4df135e685f64ceffad77bed259222debe0f34c20f95e3cad800**. A distribuição compara os dois ficheiros com a fonte e recusa substituir uma versão imutável com conteúdo diferente. Não depende da pasta SGF em runtime.
O circuito nativo mantém: ordem emitida, recebedor autorizado distinto do emissor, conflito de interesses, quantidades cumulativas, qualidade/rejeição, unidade, mapeamento artigo/armazém, equipamento/peça quando aplicável, lotes, sinais existentes e auditoria. Não foram substituídos por regras sintéticas no motor. A fixture prepara as etapas anteriores como origem sintética; **não comprova novamente todo o procurement anterior à ordem**.
O escritor comum exige a transacção do host e uma callback de autorização. Lê a linha/recepção no âmbito certo, confere quantidade física aceite e recebedor original, obtém o hash da origem, bloqueia e revalida esse hash antes de gravar. Usa a unicidade existente de `goods_receipt_item_id`; não precisa de migração de stock nova ou outra tabela de saldos.
A fotografia do movimento conserva os campos anteriores e acrescenta referência documental e `inventory_source_hash`. O hash representa a versão dos factos da linha/recepção, não uma versão inventada da ordem. Número/estado final do pai ficam fora do hash porque a finalização ocorre depois na mesma transacção. Mesmo hash/origem recupera o movimento; hash antigo ou movimento histórico incompatível recusa, sem reescrever/adoptar o original. A repetição de recepções antigas pelo circuito existente conserva a sua resolução prévia; não houve importação/replay de histórico.
O writer **não faz commit**: recepção, itens, entrada física, lotes, finalização e auditoria continuam na transacção nativa. Não confirma facturas, obrigações, pagamentos ou lançamentos por arrasto. Os restantes movimentos de `StockWorkflow` mantêm os seus serviços existentes; este incremento só extraiu entradas por recepção.
## Ligação ao SGF sem duplicar o efeito
O adaptador de consulta SGF recebeu um binding de fonte exclusivamente QA. Para o ensaio, liga ao livro nativo local através de uma **role técnica nova com SELECT apenas em artigos, armazéns e movimentos**, sem leitura das recepções/auditoria, sem escrita, sem poderes de criação de bases/roles, replicação ou bypass. A role tem leitura por omissão e cada consulta usa READ ONLY / REPEATABLE READ. O teste também tentou uma escrita inócua (`DELETE ... WHERE false`) e confirmou recusa, sem alterar dados.
Guardas conferem ambiente `testing`, identidade física do SGF, host loopback, porta 55439, nome da base nativa de regressão, role correspondente e cluster. O contexto SGF é mapeado explicitamente para tenant/armazém da origem. A referência cifrada é vinculada também à base/role/cluster efectivos, não só ao nome lógico da ligação. Não se inferem identidades ou empresas por igualdade de números. Parâmetro de armazém fora do binding é recusado.
**Isto é uma ligação de observação do ensaio local, não um conector remoto obrigatório do produto.** Permite provar que o consumidor vê o movimento realmente produzido pela recepção, em vez de o simular noutra fixture. A composição final continua a exigir instalação/adaptadores locais do núcleo comum e namespace/contexto delimitados. Nenhuma configuração de origem operacional foi activada; os bindings por omissão permanecem vazios.
Falha da ligação/fonte devolve 503 genérico sem SQL, credenciais ou stack trace; depois de reposta, a consulta recupera. A referência/hash da fonte anterior exige actualização quando o livro/contexto muda. A API continua somente de leitura e não tem comando de recepção ou saída física.
## Cenário, evidência e concorrência
| Evento sintético na ordem de 10 unidades | Recebido | Aceite | Rejeitado | Efeito físico |
| --- | ---: | ---: | ---: | --- |
| Primeira recepção com reservas e fundamento | 6 | 4 | 2 | Um movimento de +4 |
| Repetição idêntica | Mesmo evento | — | — | Mesmo comprovativo; nenhum movimento/auditoria adicional |
| Segunda recepção, totalmente não conforme | 2 | 0 | 2 | Sem movimento |
Saldo final desse âmbito: **4 unidades**, um movimento, duas confirmações de recepção auditadas (a aceite parcialmente e a totalmente rejeitada). O pós-check verificou autor/data nas duas auditorias e hash de origem no movimento. O SGF devolveu o ID/referência do **mesmo movimento** e 4 000 milésimos; os contadores do livro de origem e do livro QA SGF não mudaram pela consulta. Reservado, bloqueado e disponível não foram presumidos.
Uma falha injectada imediatamente depois do INSERT comum desfez recepção, linhas, movimento e auditoria. A nova tentativa concluiu com um movimento. Num cenário separado, dois processos PHP reais confirmaram a mesma recepção/chave: observou-se a espera `transactionid` e o PID do bloqueador, libertou-se a primeira transacção com commit, e o segundo recuperou o mesmo ID; ficou uma recepção e um movimento. Não se fez confirmação real nem se decidiu qualquer associação protegida.
Esta versão preserva a serialização por empresa da origem. Não a remove nem declara maior débito de escrita. Hash/locks/revalidação introduzem trabalho por linha confirmada; esse custo e a duração de locks em recepções grandes **ainda não foram medidos**. Não substituir essa evidência por tempos de listagem nem apresentar a ausência de N+1 na consulta como prova de escalabilidade das escritas.
## Testes e limites da prova
| Verificação | Resultado |
| --- | --- |
| Fluxo nativo, hash/repetição, rollback/retoma e concorrência entre processos | **1 teste / 33 asserções** |
| Regressão afectada de recepções/Stock | **31 testes / 193 asserções** |
| Recortes de recepção sob controlo de lotes/política | **3 testes / 20 asserções** |
| Repetição com o adaptador final sem segundo efeito | **1 teste / 8 asserções** |
| Consulta SGF funcional afectada | **2 testes / 77 asserções** |
| SGF sobre o livro realmente produzido, RO, falha da ligação e recuperação | **1 teste / 31 asserções** |
Passaram também sintaxe e verificação de whitespace. Os casos de lotes cobrem quarentena, repetição exacta, vencimento com rollback e regra de recepção vigente para chegadas futuras. Não se repetiram as suites alheias, os 72 pedidos de carga anteriores, a matriz de associações ou o build: não houve alteração de interface nesta passagem.
Foi preciso ajustar o launcher Pest para carregar o `Pest.php` da cópia QA, e não o do caminho de origem; a primeira tentativa falhou na inicialização do teste, antes da fixture. Retomou-se apenas essa prova afectada, na sua base QA. Os testes de recepção e lotes usam bases descartáveis novas próprias e as migrações existentes apenas nelas. Os cenários e a base de ligação foram conservados. O dispatch do adaptador explicita o driver; **a prova deste incremento é PostgreSQL**, sem afirmar validação noutros drivers.
[Prova sanitizada, hashes, contadores e pós-checks](proofs/stock-receipt-link-20261102.json). Tokens, credenciais, inputs dos trabalhadores e referências completas da fixture ficam no directório privado. O núcleo de leitura não mudou, pelo que a prova de carga anterior conserva as suas condições/fontes; não mede este fluxo de escrita nem a ligação QA adicional.
## Preservação e próximo incremento
Somente bases/roles novas QA e a regressão SGF foram usadas; não se consultaram bases de cliente/demos para este fluxo. O pós-check SGF confirmou zero `stock.view` temporários, restrição anterior reposta e bindings por omissão vazios. Os seis registos protegidos, a cache bloqueada, demonstrações e alterações alheias ficaram intactos; os hashes das provas válidas anteriores foram conferidos. Sem migração/concessão real, activação de candidata Purchasing, publicação, checkpoint ou aceitação presumidos.
Próximo incremento: **oficina → consumo de material da empresa**, reutilizando autorização/origem verificada e o escritor de saídas existente, com stock suficiente, material do cliente separado, origem única e correcção por compensação. Permanecem também a preparação/confirmação de recepção na composição ERP SGF, a demonstração persistente própria e a extracção dos restantes movimentos. O ensaio de observação não encerra essas pendências.
**Revisão visual e capacidade de implantação continuam pendentes e independentes.** A prova cobre API/kernel e serviços com actores sintéticos, não login/MFA/rede/servidor implantado ou experiência visual. Não se voltou à via de navegador bloqueada.
+2
View File
@@ -1,5 +1,7 @@
# Obrigação a fornecedor — entrega técnica em verificação
Continuação SGF de 02/11/2026: [adaptador de recibo histórico sintético](SGF_PAYABLE_HISTORY_RECEIPT_DELIVERY.md) implementado e provado, reutilizando o núcleo. Supera a ausência absoluta de fornecedor histórico apenas no ensaio por recibos explicitamente reconciliados; não instala fornecedor vivo, migração histórica operacional ou passagem de responsabilidade validada. As limitações históricas abaixo permanecem aplicáveis à implantação e às demonstrações preservadas.
**Evolução posterior no projecto Compras:** [passagem explícita do histórico de pagamentos](../../compras/docs/passagem-historico-pagamentos.md), `PAYABLE-HISTORY-IMPORT-v1`, implementada na fonte comum com migração 000022 preparada e activação separada desligada por omissão. Principal integral, dedução única de confirmados, pendentes/rejeitados preservados sem abatimento, revisor distinto e unicidade. Prova PostgreSQL histórica e regressão anterior nas duas composições aprovadas; não aplicada às bases habituais/demos. O adaptador SGF anterior permanece sem fornecedor de histórico; não se declara essa ligação entregue no SGF. Sem novos pagamentos, reconciliação, stock/orçamento ou contabilidade por arrasto.
29/10/2026. `COMMON-PAYABLE-SOURCE-SIM-v1`, [especificação e regras aprovadas](SUPPLIER_PAYABLE_SCOPE.md). **Implementado apenas em QA, sem aceitação ou checkpoint de encerramento presumidos.** O exemplo executado é o aprovado mais recentemente: base **10 000 MZN**, imposto documental **1 600 MZN**, principal **11 600 MZN**. Exemplos anteriores de 1 160 MZN na especificação são históricos; não são os valores desta entrega.
+51
View File
@@ -0,0 +1,51 @@
# Oficina → entrega já abatida: ligação sem novo movimento
Continuação posterior: [repartição de entregas, devolução não consumida e histórico paginado](WORKSHOP_MATERIAL_CYCLE.md). As pendências descritas abaixo registam o âmbito inicial; a continuação tem provas e limites próprios.
02/11/2026. `WORKSHOP-DELIVERY-LINK-SIM-v1`. Continuação da [saída individual conferida](WORKSHOP_STOCK_DELIVERY.md): um consumo verificado pode agora ser ligado individualmente a uma saída física já existente. **O efeito físico da confirmação é zero.** A saída anterior e a respectiva fotografia permanecem intactas.
## Tratamento entregue
A interface permite escolher explicitamente entre saída nova e ligação de uma entrega já registada. Não há opção escolhida por omissão. A preparação de ligação exige movimento, armazém, origem/versão, fundamento e evidência. A prévia identifica o movimento original, a quantidade ligada, o saldo antes/depois e a nova saída igual a zero. Outra identidade confirma o tratamento no endpoint existente, com novo fundamento.
`POST /api/workshop-stock/prepare-delivery` reutiliza as propostas imutáveis, os direitos `workshop_stock.view/prepare/confirm`, o isolamento e o circuito de confirmação. Não cria outro motor de Stock nem altera o pacote escritor ou o circuito nativo de Compras. Não foram necessários direitos novos. Nenhuma concessão real foi aplicada.
A elegibilidade é uma configuração QA explícita de movimento → ordem, além da correspondência de recurso/unidade/armazém e da elegibilidade da ordem já exigidas. Não se inferem vínculos a partir de nomes, referências ou proximidade de datas. Isto **não constitui importação de histórico** ou reconciliação automática de entregas antigas.
## Revalidação e unicidade
Para a ligação, a origem continua a exigir consumo autorizado de material da empresa, versão actual e verificação técnica independente. A entrega deve ser uma saída simples anterior ao consumo, da mesma fonte/artigo/armazém e com a quantidade integral exactamente igual. A fotografia do movimento deve conter o hash íntegro da operação gerada pelo escritor comum. Sem essa evidência, exige-se um percurso histórico próprio.
O livro admitido neste recorte contém entradas `receipt_in` e saídas `issue`. Estornos, ajustes e transferências recusam a ligação: não se presume que uma saída revertida continua disponível para consumo. Lotes, reservas, peças e conversões continuam fora do recorte. Não é exigido saldo suficiente para uma nova saída, porque a entrega já foi abatida; foi comprovado o caso de saldo esgotado.
Na confirmação, o servidor volta a conferir direitos/contexto, fonte/versão/verificação, mapa, elegibilidade, operação/movimento e revisão/saldo do livro. A alteração exige nova conferência. Usa a transacção e o bloqueio de empresa existentes; bloqueia também os registos de origem e entrega. A unicidade da origem, movimento, operação e proposta impede uma segunda associação. O replay devolve a associação/movimento original.
Só é inserida a associação append-only, com autor da preparação/confirmação, datas, versão, fundamentos, evidência preservada na proposta, hash e antes/depois iguais. A auditoria distingue `delivery_prepared` e `delivery_linked`. Não se inserem operações/movimentos nem se editam os anteriores. Uma falha na associação desfaz a decisão e permite retoma sem duplicação.
## Provas e preservação
Resultados e hashes: [workshop-delivery-link-20261102.json](proofs/workshop-delivery-link-20261102.json). A regressão usa apenas novas ordens, identidades e esquemas em `sgf_tempo_test`, no cluster isolado/porta 55439. Sem reset. A entrega anterior e os ensaios nativos de Compras são provas separadas; não foram repetidas suites nativas porque o pacote e o adaptador nativo não mudaram.
| Casos afectados aprovados | Testes | Asserções |
| --- | ---: | ---: |
| Saída nova, versões, isolamento e concorrência existentes | 6 | 222 |
| Ligação integral, recusas, saldo zero, retoma e concorrência | 5 | 163 |
| Fotografia original e acesso por outra empresa | 2 | 47 |
| Total seleccionado | **13** | **432** |
Uma passagem intermédia teve três erros de carregamento do pacote na fixture dos casos novos. Esses casos não foram contados como provas aprovadas; corrigiu-se o carregamento explícito, executaram-se os casos de ligação afectados e reutilizaram-se apenas os casos anteriores aprovados. O relatório identifica os XML e os hashes, sem declarar uma suite intermédia integralmente aprovada.
O caso principal usa o escritor comum para criar uma entrega sintética de 2 UN: saldo 10 → 8. A confirmação liga o consumo à entrega e mantém **8 → 8**, os dois movimentos totais (entrada e saída), uma operação e uma associação. O mesmo movimento e a sua fotografia permanecem intactos. A consulta de Stock observa 8 no mesmo livro.
Os casos afectados abrangem repetição, autoconfirmação recusada, propostas concorrentes sobre a mesma entrega, quantidade diferente, movimento não elegível, livro alterado, elegibilidade/direitos revogados, falha/retoma e saldo zero. Dois processos PHP foram observados em bloqueio real: após a primeira transacção libertar a linha da empresa, a segunda termina com replay e o mesmo movimento, sem segunda associação. As provas anteriores de versões, isolamento e saída nova foram executadas na passagem afectada e os casos aprovados reutilizados.
O render estático verifica a apresentação de efeito zero e do movimento/quantidade ligados; a verificação de fonte confirma escolha explícita de tratamento. Build aprovado. Isto não demonstra interacção no navegador nem substitui a revisão visual.
O pós-ensaio verifica que os direitos temporários foram removidos, a constraint original foi restaurada e nenhuma fonte operacional ficou configurada. Seis registos protegidos, cache bloqueada, dados/acessos reais, demonstrações e alterações alheias preservados. Sem activação de Compras, publicação ou checkpoint.
## Pendências
- Repartição de uma entrega entre vários consumos, consumo parcial e entrega com quantidade diferente: recusados; ainda não entregues.
- Devoluções, compensações físicas e revisão de uma ligação já confirmada: continuam separadas. Corrigir a origem não gera movimento nem desfaz a ligação automaticamente.
- Configuração/instalação operacional das tabelas e fontes, composição única desde procurement/recepção até consumo, outros drivers, carga da escrita e capacidade de implantação: não validados por estes ensaios.
- Revisão visual permanece pendente; não se repetiu a via de navegador bloqueada.
+52
View File
@@ -0,0 +1,52 @@
# Oficina e Stock — repartição, devolução e histórico
Continuação SGF: [retirada e recusa de propostas](WORKSHOP_STOCK_PROPOSAL_CLOSURE.md), sem efeito físico, com decisões imutáveis, concorrência e histórico paginado. Implementação posterior; os números e hashes desta entrega inicial permanecem como prova histórica.
Continuação posterior: [percurso nativo de devolução e observação SGF](NATIVE_WAREHOUSE_RETURN_DELIVERY.md) implementado e comprovado em base isolada. A limitação histórica abaixo sobre comando nativo foi superada nesse incremento, sem modificar esta prova anterior ou declarar composição operacional instalada.
02/11/2026. `WORKSHOP-MATERIAL-CYCLE-SIM-v1`. Continuação local sintética da [ligação integral a uma entrega](WORKSHOP_DELIVERY_LINK.md). Foram acrescentadas a repartição entre consumos distintos, a devolução física de material ainda não consumido e a consulta paginada do histórico. Não foram activadas demonstrações ou capacidades reais.
## Fluxo e responsabilidade
O mesmo livro físico mantém entradas, saídas e devoluções; não há segunda tabela de saldos. O percurso comprovado é: saldo inicial 10 UN → saída física de 5 → saldo 5 → associação de 2 ao consumo, sem novo débito → entrada física de 3 devolvidas → saldo 8. A entrada inicial é uma fixture; a prova anterior de recepção nativa de Compras continua separada. Não se declara um ERP único instalado desde procurement até Oficina.
`POST /api/workshop-stock/prepare-allocation` confere uma origem integral de consumo contra a quantidade ainda não associada de uma entrega. Vários consumos podem partilhar a entrega; uma origem não é fraccionada por várias entregas. Cada origem mantém decisão, fundamento, evidência, preparador/confirmador e versão próprios. A prévia mostra o saldo físico inalterado e a quantidade ainda não associada antes/depois.
`POST /api/workshop-stock/prepare-return` exige uma ocorrência própria `returned`, material da empresa e verificação técnica independente. Não transforma um consumo em devolução. Limita a quantidade por **entregue − associado a consumo − já devolvido**. A confirmação exige outra identidade, fundamento e `received_in_warehouse=true`, declarado expressamente na interface. O relato técnico sozinho não gera entrada. A fotografia da operação conserva essa declaração e a origem/verificação/evidência.
O escritor canónico `packages/inventory-return/src/DeliveryReturnWriter.php` participa na transacção do host, exige autorização, fotografa/revalida a operação e a entrega original, bloqueia armazém/artigo/operação/entrega, verifica revisão do livro e quantidade cumulativa devolvida e grava uma única entrada `workshop_return_in`. Repetições recuperam o movimento. Não faz commit independente. O host conserva a regra mais restritiva de quantidade ainda não consumida/associada.
Artefacto local imutável preparado em Compras, `packages/inventory-return/releases/0.1.0`, manifesto SHA-256 `2850a4f5cb678acfe3a9dbc7a7d62eb233bc72722ad0de374681c2679c90557c`. **A existência do artefacto não equivale à integração do comando de devolução nativo de Compras**, que permanece por adaptar. O leitor comum consulta o mesmo livro e vê a entrada; não se alterou a sua consulta SQL nem se repetiu a carga da leitura.
## Integridade e concorrência
`ws_allocations` e `ws_returns` são registos append-only do ensaio. Não alteram `ws_claims` nem as suas unicidades anteriores. Uma entrega já ligada integralmente não pode também ser repartida ou devolvida. A origem e proposta não podem ser usadas duas vezes. A soma de repartições e devoluções não excede a entrega.
Todas as decisões voltam a validar contexto, direitos, origem/versão/verificação, mapeamento, elegibilidade, livro e quantidade restante. A confirmação de outra proposta torna a prévia anterior desactualizada. Desactivar novas repartições não apaga a protecção das origens já associadas. Estornos, ajustes, transferências, lotes, reservas, peças e entregas sem hash original íntegro continuam recusados neste recorte.
A concorrência foi exercitada com dois processos PHP e o bloqueador identificado por `pg_blocking_pids`. Nas repartições concorrentes de 3+3 contra uma entrega de 5, apenas 3 ficam associados; a segunda proposta recusa 409 após a libertação. Duas devoluções concorrentes de 3 contra 5 igualmente produzem uma só entrada de 3. As falhas injectadas após inserir a associação/decisão fazem rollback integral; a retoma não duplica efeitos.
## Histórico e permissões
`GET /api/workshop-stock` mantém páginas de 25 origens e acrescenta `proposal_page` e `status=all|pending|confirmed` para páginas de 25 propostas. Ordenação por ID decrescente, isolamento por tenant/empresa/unidade e associação conjunta dos movimentos da página. Confirmadas inclui os três livros de decisões; não se limita às últimas 25 propostas. Parâmetros desconhecidos são recusados. A interface tem filtros e navegação independentes das páginas de origens.
Reutilizam-se `workshop_stock.view/prepare/confirm`, além de `workshop.view` e `stock.view`, no contexto de Oficina e unidade correcta. Não houve concessões reais nem direitos públicos novos. `partial_delivery_links` e `stock_returns` não são activados por omissão. A guarda sintética e os esquemas locais explicitamente elegíveis permanecem obrigatórios. As novas tabelas/índices foram criados **apenas nas fixtures novas da regressão**, sem migração/índice no destino.
## Evidência
Resultados seleccionados, hashes e pós-ensaio: [workshop-material-cycle-20261102.json](proofs/workshop-material-cycle-20261102.json). As provas válidas foram reutilizadas. As alterações posteriores de declaração de recepção e paginação motivaram apenas a execução dos casos afectados. Uma expectativa antiga de saldo na helper de concorrência foi corrigida; a execução intermédia que a revelou não foi tratada como suite aprovada.
Consolidação: **22 testes distintos / 820 asserções aprovadas**, escolhendo a prova mais recente por caso e sem contar repetições duas vezes. A prova identifica cada execução e cada caso seleccionado. Nenhuma suite nativa alheia foi repetida.
Cobertura: saldo e quantidade restante, múltiplas origens, repetição, recusa de auto-confirmação, limite cumulativo, alteração concorrente, recuperação após falha, ocorrência/propriedade/verificação incompatíveis, direito revogado, contexto antigo, empresa distinta, apresentação conjunta de decisões e paginação/ordenação/filtros. O caso de devolução comprova ainda o replay do escritor comum e a observação do resultado na consulta de Stock.
Build e render estático dos impactos aprovados. A verificação da caixa obrigatória e dos controlos de histórico é de fonte; não se declara ensaio de interacção ou revisão visual. Nenhum navegador foi usado. O pós-ensaio verifica zero concessões temporárias, constraint original e zero fontes operacionais configuradas.
## Limitações separadas
- Não se implementou fraccionar a mesma origem por várias entregas, nem libertar automaticamente uma associação confirmada quando o apontamento é corrigido.
- Material já consumido não é recuperado por este percurso. Compensação/correcção física desse material exige um circuito próprio e evidência distinta; não se confunde com devolução de excedente não consumido.
- A aceitação física neste ensaio é de quantidade simples, sem classificação de qualidade/quarentena, lotes ou reservas. Não valida configuração/papéis de armazém de um cliente real.
- A instalação operacional das tabelas/fontes, o comando nativo de devolução de Compras, a composição integral numa demonstração única, outros drivers e a revisão visual continuam pendentes. Não há medição nova de carga da escrita nem capacidade de implantação validada.
Seis registos protegidos, cache bloqueada, demonstrações, credenciais e alterações alheias preservados. Nenhuma publicação, candidata activada, operação real, aceitação ou checkpoint presumido.
+63
View File
@@ -0,0 +1,63 @@
# Oficina → Stock: saída individual conferida
Continuação posterior: [ligação integral a uma entrega já abatida](WORKSHOP_DELIVERY_LINK.md), sem novo movimento. As limitações abaixo descrevem esta entrega inicial; a continuação não inclui repartições, devoluções ou compensações.
02/11/2026 — `WORKSHOP-STOCK-ISSUE-SIM-v1`. Implementação local sintética: um consumo de material da empresa, tecnicamente verificado, pode dar origem a uma proposta com impacto físico e a uma confirmação independente. A origem, quantidade e versão são reutilizadas; não se redigita o consumo nem se executa uma saída automática ao registar o apontamento.
## Código e responsabilidade única
`packages/inventory-issue` contém o escritor de saída comum. O circuito nativo `StockWorkflow` de Compras delega apenas a sua saída normal neste escritor, através de `StockIssueMovement`. Permanecem no circuito original as políticas, reservas, lotes/FEFO, peças/equipamentos, sinais e auditoria. Transferências, contagens e estornos mantêm os seus caminhos anteriores.
Artefacto local imutável em Compras: `packages/inventory-issue/releases/0.1.0`, manifesto SHA-256 `3c24d9e9fb99bfbb274077495c3a42ddb7eccab06b5c6a956cd739b2bc9b56f0`. É verificado contra a fonte; não depende do repositório SGF durante a execução de Compras. O escritor exige autorização do host e transacção já aberta, bloqueia armazém/artigo, revalida a fotografia da operação e a revisão do livro, recusa quantidade insuficiente e grava um único movimento negativo. Não faz commit próprio.
No SGF, `WorkshopStock` e `WorkshopStockController` disponibilizam consulta paginada de origens, preparação e confirmação. A interface está no submenu de Stock de Oficina. A navegação de seis módulos permanece. Não se fez instalação nas demonstrações existentes.
## Conferência e integridade
- Acesso exige contexto actual de Oficina, unidade, `workshop.view`, `stock.view` e direitos próprios da ligação. Todos são novamente exigidos na confirmação.
- Só ordens explicitamente elegíveis e recursos/unidades/armazéns explicitamente mapeados entram no ensaio. A fonte deve ser consumo autorizado de material da empresa, versão actual e verificação técnica por outra identidade. Não há conversão de unidade ou arredondamento de quantidade.
- Preparação exige fundamento, evidência e UUID de repetição. A mesma chave/conteúdo recupera a proposta; conteúdo diferente recusa com 409. O impacto preserva antes/depois, origem/versão, artigo e armazém.
- Confirmação exige outra identidade e fundamento. A fotografia é comparada novamente com a origem, verificação, mapa e livro actuais. Alteração exige nova conferência; a mesma origem estável só pode produzir um efeito, incluindo após correcções técnicas.
- Operação, movimento, associação à origem e auditoria fazem parte da mesma transacção. O histórico conserva preparador, confirmador, datas, fundamentos, evidência, origem/versão e estado anterior/posterior. Propostas e associações do ensaio são append-only.
- Uma saída anterior sem correspondência reconciliada bloqueia outro abatimento desse artigo/armazém. Uma entrega física já debitada não pode ser novamente debitada como consumo. Isto é uma recusa conservadora; a ligação a entregas existentes ainda não foi implementada.
A listagem lê 25 origens por página e associa os movimentos em conjunto. Mostra as últimas 25 propostas do contexto; não é ainda uma consulta paginada de todo o histórico de propostas. A confirmação consulta sempre o estado actual. Não há alegação de desempenho desta escrita em volume.
## Direitos e bases
Direitos novos propostos, de unidade: **`workshop_stock.view`**, **`workshop_stock.prepare`**, **`workshop_stock.confirm`**. Consulta de Oficina ou Stock não os concede implicitamente. Não foram adicionados ao catálogo/concessões reais nem concedidos publicamente. Os testes alargam temporariamente a constraint apenas na base isolada, criam identidades QA novas e removem essas concessões/restauram a constraint no final.
O código mantém a guarda sintética de Oficina, sem fonte configurada por omissão. A escrita usa apenas um esquema QA explícito na mesma base `sgf_tempo_test`, no cluster de regressão/porta 55439. Não existe adaptador de escrita externa ou configuração empresarial real desta ligação. As tabelas de conferência são criadas pela fixture sintética; não foi entregue um instalador/migração operacional.
## Provas
Provas consolidadas, hashes e resultados: [workshop-stock-20261102.json](proofs/workshop-stock-20261102.json). A evidência distingue os casos já válidos da repetição apenas do caso corrigido; uma execução intermédia teve uma falha de formato de data na fixture e não é tratada como suite integral aprovada.
| Verificação afectada | Testes aprovados | Asserções |
| --- | ---: | ---: |
| SGF: quatro casos válidos reutilizados | 4 | 154 |
| SGF: correcção de versão | 1 | 39 |
| SGF: outra empresa, contexto de módulo e chave alterada | 1 | 29 |
| Compras: operações de Stock afectadas | 25 | 125 |
| Compras: lotes seleccionados | 2 | 10 |
| Navegação existente | 8 | 90 |
| Total de casos seleccionados, sem contar falhas intermédias | **41** | **447** |
Na empresa distinta, mesmo com direitos QA explícitos e o mesmo livro de ensaio mapeado, a consulta não revela origens/propostas e os IDs da primeira empresa são recusados com 403. A chamada no módulo Stock ao endpoint de Oficina recusa o contexto com 409. O pós-ensaio confirmou zero concessões temporárias restantes, zero bindings operacionais e a constraint original com SHA-256 `40046092cba51f1b46d26d5f0da8af47e8336e90a8d50b8de3a8c390758f1783`.
O cenário HTTP real de Oficina abre/autoriza uma ordem, regista 2 UN, verifica tecnicamente, prepara e confirma: **10 → 8 UN**, um movimento e uma associação. Stock consulta o mesmo livro e observa 8. A repetição recupera o movimento original. Material de cliente, entrega, ausência de verificação, fracção não representável, insuficiência, mudança de livro/mapa/direitos/contexto e autoconfirmação são recusados.
A falha injectada depois do INSERT da associação desfaz também a operação e a saída; a retoma produz um único efeito. Na concorrência real de dois processos PHP, a primeira transacção mantém a linha da empresa bloqueada; o segundo processo é observado em `pg_stat_activity`, bloqueado pelo PID da primeira. Depois do commit, termina com 200/replay e o mesmo movimento. Não se inferiu o resultado apenas de um timeout.
Correcção antes da confirmação invalida a proposta antiga; a versão 2 verificada pode ser novamente conferida (10 → 7). A versão 3 da mesma origem, posterior ao abatimento, não produz nova saída. A correcção da quantidade técnica não representa automaticamente uma compensação física.
O render estático confirma separação de direitos, estado de carregamento sem saldo fictício e substituição do aviso de capacidade pendente apenas para quem tem acesso. Build Vite aprovado. Isto não é revisão visual nem ensaio de interacção no navegador. Não se repetiu a via bloqueada.
## Limitações e continuação
1. Apenas artigos de quantidade, sem lotes, reservas ou peças/equipamentos de stock. O binding recusa essas capacidades; as regras nativas não são contornadas.
2. Devoluções, compensações, consumo parcial de entregas existentes e reconciliação de saídas antigas continuam por implementar. São o próximo incremento necessário antes de incorporar origens antigas.
3. O livro inicial de 10 UN desta fixture é sintético. A [prova anterior de recepção nativa → consulta SGF](STOCK_RECEIPT_LINK_DELIVERY.md) permanece válida e separada. Não se demonstrou aqui um percurso único instalado desde procurement/recepção até consumo de Oficina no mesmo cenário.
4. PostgreSQL validado; outros drivers, implantação, carga da escrita e revisão visual permanecem separados. Os ensaios anteriores de carga da leitura não demonstram capacidade de implantação desta ligação.
Preservados os seis registos sem associação, cache bloqueada, demonstrações e trabalho alheio. Nenhuma candidata Compras activada, publicação, concessão real, operação real, aceitação ou checkpoint presumido.
+47
View File
@@ -0,0 +1,47 @@
# Oficina → Stock: retirada e recusa de propostas
02/11/2026 — `WORKSHOP-STOCK-PROPOSAL-CLOSURE-SIM-v1`. Implementação local sintética que completa o ciclo de propostas de saída, associação a entrega, repartição e devolução. Continua [o ciclo de material](WORKSHOP_MATERIAL_CYCLE.md), preservando os efeitos físicos e [a devolução nativa anterior](NATIVE_WAREHOUSE_RETURN_DELIVERY.md).
## Problema resolvido
Uma proposta desactualizada podia permanecer indefinidamente pendente. Agora o preparador pode retirá-la e outra identidade com competência de confirmação pode recusá-la, com fundamento individual. A página mostra antecipadamente **efeito físico zero**, nenhuma associação/libertação de origem e necessidade de nova conferência para tratar novamente a origem. A prévia original permanece arquivada; o encerramento não executa a quantidade que ela mostrava.
Reutilizam-se os direitos existentes: `workshop_stock.prepare` para retirar a própria proposta; `workshop_stock.confirm` para recusar proposta de outro preparador. Os direitos de consulta Oficina/Stock e o contexto da unidade continuam necessários. Não foi criado ou concedido um novo direito real.
## Comandos, decisões e concorrência
`POST /api/workshop-stock/{id}/withdraw` e `.../{id}/reject` recebem `state_version`, `source_hash` e `reason`. A proposta original é imutável: a revisão pendente é 1 e a decisão terminal tem revisão 2. Após bloquear a empresa e a proposta, o serviço revalida contexto, permissões e identidade, confere a versão/hash apresentados e a inexistência de confirmação anterior. As decisões append-only guardam âmbito, proposta, autor, data, fundamento, hash e estado anterior/posterior; a auditoria referencia proposta, decisão e revisão na mesma transacção.
Encerrar uma prévia obsoleta não exige que o seu efeito físico ainda seja executável. Isso permite retirar uma proposta cujo livro mudou, sem mexer nesse livro. Proposta já confirmada exige circuito de correcção física próprio e não pode ser retirada/recusada por este comando. Uma proposta encerrada não pode ser confirmada ou reaberta.
Uma repetição com a mesma proposta, decisão, autor e fundamento devolve a decisão original. Conteúdo ou actor incompatíveis recusam 409; versão/hash antigos recusam 409. Repetir a preparação original devolve a proposta com o estado terminal actual, sem a apresentar como nova pendência. Uma nova conferência gera outra proposta, sem apagar a anterior ou duplicar o efeito.
O bloqueio por empresa já existente serializa confirmação e encerramento. Com processos independentes e bloqueador confirmado por `pg_blocking_pids`:
- Retirada primeiro: confirmação espera e depois recusa 409; nenhum movimento.
- Confirmação primeiro: retirada espera e depois recusa 409; conserva-se um único movimento.
- Duas retiradas idênticas: a segunda espera e recupera a mesma decisão; uma só linha terminal.
Uma falha ao gravar a auditoria desfaz também a decisão. A repetição posterior termina com uma decisão e sem movimento. Um trigger da fixture recusa alterações à decisão já gravada.
## Histórico e interface
O histórico distingue pendentes, confirmadas, retiradas e recusadas, com paginação de 25 no servidor. Apresenta preparador/data, evidência e fundamento originais, autor/data/fundamento do encerramento e a indicação de prévia arquivada, não executada. Os controlos próprios/de revisão respeitam as identidades e direitos; o servidor continua a ser a autoridade.
A leitura HTTP usa transacção `REPEATABLE READ READ ONLY`, conservando uma fotografia coerente dos totais, página, confirmações e encerramentos. Na fixture de 51 propostas, três encerradas deixam 48 pendentes. Páginas são disjuntas. A página faz **uma consulta de descoberta da tabela e uma consulta conjunta das decisões**, limitada aos IDs da página; não há consulta por proposta ou leitura de todo o universo. Isso comprova a forma da consulta, não capacidade de carga.
Troca de contexto limpa a prévia/chave local. Respostas de comandos do contexto anterior não substituem o estado visível do contexto novo. Não há repetição automática de decisões.
## Provas e preservação
[Relatório e hashes](proofs/workshop-stock-closure-20261102.json): **33 testes distintos / 1.181 asserções**, sendo 11 casos novos/361 e os 22 casos afectados existentes/820. Não foram repetidas suites nativas, da fila de associações ou outras suites alheias. Os casos novos cobrem também revogação de direito, contexto antigo, acesso noutra empresa/unidade, ausência de instalação, versões/hashes, repetição com conteúdo alterado, preservação da proposta, encerramento de repartições/devoluções sem associações e recuperação após falha.
A primeira expectativa do teste de consultas ignorava a descoberta de schema. A falha permanece registada e foi substituída somente pela repetição dirigida desse caso, distinguindo a descoberta da leitura de dados. Os nove restantes casos válidos dessa execução foram reutilizados. O consolidado selecciona casos aprovados por nome, sem somar repetições ou contar a falha como prova válida.
Build Vite completo passou (46 módulos), bem como sintaxe PHP e renderização estática dirigida do impacto e das guardas da interface. O verificador adicional antigo da página inicial não terminou; apenas os processos próprios, previamente identificados, foram interrompidos. Não houve alteração da navegação nem nova aceitação visual. O build directo e a prova da interface deste incremento passaram. Não se repetiu a via bloqueada de navegador.
Schema/tabela/índice/triggers novos existem **apenas nas novas fixtures sintéticas**, na base de regressão `sgf_tempo_test` do cluster isolado 55439. Não há migração aplicada à instalação. Uma fonte sintética anterior sem `ws_closures` conserva consulta/confirmação; não oferece encerramento na interface e o comando responde 503. A confirmação continua comprovada nesse cenário. Não se cria tabela por acesso ou se interpreta indisponibilidade como estado encerrado.
O postcheck confirmou zero direitos temporários, a constraint original restaurada e zero bindings operacionais de Oficina/Stock. As provas anteriores da fila, leitor de stock e escritor comum conservam os hashes. Os seis registos protegidos, cache bloqueada, demonstrações, dados/acessos reais e trabalho em curso permanecem preservados. Sem publicação, activação de Compras, checkpoint ou aceitação presumidos.
Continuam separadas: revisão visual/interacção no navegador, instalação operacional, carga de escrita e capacidade de implantação. Encerramento de proposta não corrige material consumido nem um movimento confirmado; não acrescenta lotes, reservas, previsão líquida ou efeitos financeiros/contabilísticos.
+64
View File
@@ -0,0 +1,64 @@
{
"schema_version": 1,
"id": "SGF-MODULE-FLOW-PREPARATION-v1",
"status": "preparation_only",
"date": "2026-11-02",
"modules": ["commercial", "purchasing", "stock", "workshop", "finance", "accounting"],
"first_increment": "SGF-STOCK-READ-SIM-v1",
"evidence_contract": {
"required": ["tenant_id", "company_id", "unit_scope", "actor_id", "source_system", "source_kind", "source_id", "source_version", "source_hash", "effect_kind", "decision_id", "decided_at", "reason", "idempotency_key", "correlation_id", "permission_scope", "before", "after"],
"optional_by_effect": ["warehouse_id", "stock_item_id", "quantity_milli", "quantity_unit", "currency", "amount_exact", "rounding_policy", "verified_by", "evidence_references", "due_date", "pending_reason"],
"source_evidence_required": true,
"runtime_implemented": false,
"unknown_is_zero": false,
"automatic_dependency_association": false,
"new_global_event_bus": false
},
"stages": [
{"id": "requisition_order", "owner": "purchasing", "effect": "approved_procurement_origin", "state": "partial_synthetic", "source_ids": ["requisitions_delivery"], "requires": [], "exit_evidence": ["approved_origin_version", "budget_receipt_when_applicable"], "gap": "Only basic requisitions demonstrated in 8039; full procurement composition not transferred."},
{"id": "accepted_receipt", "owner": "purchasing", "effect": "accepted_physical_receipt", "state": "source_not_integrated", "source_ids": ["receipt_workflow"], "requires": ["requisition_order"], "exit_evidence": ["receipt_id_version", "accepted_quantities", "quality_decision", "warehouse_mapping"], "gap": "No common SGF receipt/stock adapter demonstrated."},
{"id": "physical_stock", "owner": "stock", "effect": "physical_movement_once", "state": "source_not_integrated", "source_ids": ["stock_workflow", "stock_controller", "inventory_lots", "inventory_counts", "inventory_dispositions", "inventory_reversals", "warehouse_reservations", "stock_menu"], "requires": ["accepted_receipt"], "exit_evidence": ["movement_origin", "quantity_unit", "ledger_revision", "receipt_or_compensation"], "gap": "Common scoped reader, authoritative writer and SGF warehouse mapping pending."},
{"id": "supplier_invoice", "owner": "purchasing", "effect": "verified_supplier_document", "state": "partial_synthetic", "source_ids": ["invoice_workflow", "supplier_adapter"], "requires": ["requisition_order"], "exit_evidence": ["invoice_snapshot", "independent_review", "accepted_receipt_references_when_required"], "gap": "Does not assume every purchase is stock; existing eligibility/partial receipt rules must be preserved."},
{"id": "supplier_payable", "owner": "finance", "effect": "supplier_obligation_once", "state": "partial_synthetic", "source_ids": ["payables", "supplier_adapter"], "requires": ["supplier_invoice"], "exit_evidence": ["obligation_receipt", "principal_currency", "history_responsibility", "due_date_or_pending_reason"], "gap": "Synthetic core exists; common operational composition and historical source mapping remain delimited."},
{"id": "supplier_settlement", "owner": "finance", "effect": "confirmed_allocation_once", "state": "partial_synthetic", "source_ids": ["settlements", "settlement_delivery"], "requires": ["supplier_payable"], "exit_evidence": ["confirmed_payment_evidence", "distinct_confirmation", "allocation_receipt", "remaining_balance"], "gap": "Synthetic payments/allocations exist; no bank execution or complete bank reconciliation delivered."},
{"id": "workshop_execution", "owner": "workshop", "effect": "verified_work_record", "state": "partial_synthetic", "source_ids": ["workshop_workflow"], "requires": [], "exit_evidence": ["authorised_order", "verified_time_material_versions", "ownership_of_material"], "gap": "Verified observations exist; no automatic physical stock movement."},
{"id": "workshop_stock_consumption", "owner": "stock", "effect": "company_material_consumption_once", "state": "planned", "source_ids": ["stock_workflow", "workshop_workflow"], "requires": ["physical_stock", "workshop_execution"], "exit_evidence": ["explicit_item_warehouse_mapping", "movement_receipt", "consumption_origin_version"], "gap": "Linking observed material to a physical movement is not implemented; do not replay old observations."},
{"id": "verified_cost", "owner": "finance", "effect": "validated_cost_version", "state": "partial_synthetic", "source_ids": ["direct_costs", "industrial_costs"], "requires": ["workshop_execution"], "exit_evidence": ["verified_source_versions", "approved_rate_versions", "complete_or_explicitly_incomplete"], "gap": "Current costs are synthetic; physical movement linkage is future and absence of rate stays visible."},
{"id": "sales_draft", "owner": "commercial", "effect": "commercial_draft_from_unique_origins", "state": "partial_synthetic", "source_ids": ["workshop_billing"], "requires": ["workshop_execution"], "exit_evidence": ["billable_source_versions", "commercial_price_version", "distinct_commercial_review"], "gap": "Draft integration exists; cost is not sale price and draft does not decrement stock."},
{"id": "sales_invoice", "owner": "commercial", "effect": "issued_sales_document", "state": "partial_synthetic", "source_ids": ["service_invoicing"], "requires": ["sales_draft"], "exit_evidence": ["document_snapshot", "series_rule_version", "applicable_fiscal_decisions"], "gap": "Test issuance exists; real fiscal issuance remains guarded. Direct service origins remain valid."},
{"id": "customer_receivable", "owner": "finance", "effect": "customer_receipt_allocation_once", "state": "partial_synthetic", "source_ids": ["service_receivables"], "requires": ["sales_invoice"], "exit_evidence": ["receivable_origin", "payment_evidence", "distinct_confirmation", "allocation_history"], "gap": "Synthetic receipts exist; fiscal receipt/bank reconciliation not presumed."},
{"id": "general_ledger", "owner": "accounting", "effect": "balanced_journal_once", "state": "planned", "source_ids": ["catalogue_accounting", "accounting_menu"], "requires": [], "exit_evidence": ["approved_source_effect", "dated_account_mapping", "balanced_debit_credit", "open_accounting_period", "posting_receipt"], "gap": "Classification/menu exist; journal, ledger, accounting periods, close and reporting engine absent."}
],
"event_consumers": [
{"source": "supplier_payable", "target": "general_ledger", "status": "planned", "rule": "Accounting recognition eligibility must be delimited; never also book the same invoice through another competing writer."},
{"source": "supplier_settlement", "target": "general_ledger", "status": "planned", "rule": "Settlement is a separate effect, not another recognition of principal."},
{"source": "sales_invoice", "target": "general_ledger", "status": "planned", "rule": "Sales recognition and applicable tax rules require explicit scope; draft is insufficient."},
{"source": "customer_receivable", "target": "general_ledger", "status": "planned", "rule": "Receipt/allocation is distinct from revenue recognition."},
{"source": "physical_stock", "target": "general_ledger", "status": "planned", "rule": "Quantity alone is not valuation or an approved accounting entry."}
],
"sources": [
{"id": "requisitions_delivery", "repository": "sgf", "path": "docs/SGF_REQUISITIONS_8039_DELIVERY.md"},
{"id": "receipt_workflow", "repository": "compras", "path": "app/Services/ReceiptWorkflow.php"},
{"id": "stock_workflow", "repository": "compras", "path": "app/Services/StockWorkflow.php"},
{"id": "stock_controller", "repository": "compras", "path": "app/Http/Controllers/StockController.php"},
{"id": "inventory_lots", "repository": "compras", "path": "app/Services/InventoryLots.php"},
{"id": "inventory_counts", "repository": "compras", "path": "app/Services/InventoryCounts.php"},
{"id": "inventory_dispositions", "repository": "compras", "path": "app/Services/InventoryDispositions.php"},
{"id": "inventory_reversals", "repository": "compras", "path": "app/Services/InventoryReversals.php"},
{"id": "warehouse_reservations", "repository": "compras", "path": "app/Services/WarehouseReservations.php"},
{"id": "stock_menu", "repository": "sgf", "path": "resources/js/stock-menu.js"},
{"id": "invoice_workflow", "repository": "compras", "path": "app/Services/InvoiceWorkflow.php"},
{"id": "supplier_adapter", "repository": "sgf", "path": "app/Modules/Purchasing/SupplierPayables.php"},
{"id": "payables", "repository": "sgf", "path": "packages/payables/src/Payables.php"},
{"id": "settlements", "repository": "sgf", "path": "packages/payables/src/SupplierSettlements.php"},
{"id": "settlement_delivery", "repository": "sgf", "path": "docs/SUPPLIER_SETTLEMENT_DELIVERY.md"},
{"id": "workshop_workflow", "repository": "sgf", "path": "app/Modules/Workshop/WorkshopWorkflow.php"},
{"id": "direct_costs", "repository": "sgf", "path": "app/Modules/Workshop/DirectCosts.php"},
{"id": "industrial_costs", "repository": "sgf", "path": "app/Modules/Industry/IndustrialCosts.php"},
{"id": "workshop_billing", "repository": "sgf", "path": "app/Modules/Workshop/WorkshopBilling.php"},
{"id": "service_invoicing", "repository": "sgf", "path": "app/Modules/Services/ServiceInvoicing.php"},
{"id": "service_receivables", "repository": "sgf", "path": "app/Modules/Services/ServiceReceivables.php"},
{"id": "catalogue_accounting", "repository": "sgf", "path": "app/Modules/Services/CatalogueAccounting.php"},
{"id": "accounting_menu", "repository": "sgf", "path": "docs/ACCOUNTING_MENU_DELIVERY.md"}
]
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,300 @@
{
"date": "2026-11-02",
"source_sha256": "b901bccc73a59e80d98d32a56532e9300a55ba9a216e5ac5a0ce84d78f976397",
"test": {
"tests": 1,
"assertions": 346,
"errors": 0,
"failures": 0,
"junit_sha256": "217e4ff8096d985a523748a9b98bc3b573614c8dbe2318e1a0a2b7a26798cc1d"
},
"method": {
"independent_php_workers": true,
"distinct_synthetic_identities": 4,
"requests_per_worker": 5,
"waves_per_case": 3,
"percentiles": "Nearest rank; descriptive samples of 15/30/60 requests only",
"warm_in_process_http": true,
"login_network_tls_browser_measured": false,
"read_only_reader_transactions": true,
"records_per_area": 3000,
"lines_per_wide_draft": 100,
"description_bytes": 1000
},
"results": [
{
"index_mode": "none",
"workload": "clients",
"workers": 1,
"complete_requests": 15,
"limited_requests": 0,
"p50_ms": 35.86,
"p95_sample_ms": 51.068,
"closed_loop_observed_rps": 24.61,
"observed_max_inflight": [
1,
1,
1
],
"queries": [
11
],
"max_incremental_php_bytes": 91240,
"mean_startup_to_ready_ms": 978.556
},
{
"index_mode": "none",
"workload": "clients",
"workers": 2,
"complete_requests": 30,
"limited_requests": 0,
"p50_ms": 35.73,
"p95_sample_ms": 39.455,
"closed_loop_observed_rps": 50.32,
"observed_max_inflight": [
2,
2,
2
],
"queries": [
11
],
"max_incremental_php_bytes": 91240,
"mean_startup_to_ready_ms": 1300.194
},
{
"index_mode": "none",
"workload": "clients",
"workers": 4,
"complete_requests": 60,
"limited_requests": 0,
"p50_ms": 37.99,
"p95_sample_ms": 60.81,
"closed_loop_observed_rps": 80.58,
"observed_max_inflight": [
4,
4,
4
],
"queries": [
11
],
"max_incremental_php_bytes": 91240,
"mean_startup_to_ready_ms": 1527.093
},
{
"index_mode": "none",
"workload": "billing_drafts",
"workers": 1,
"complete_requests": 15,
"limited_requests": 0,
"p50_ms": 298.013,
"p95_sample_ms": 476.933,
"closed_loop_observed_rps": 3.11,
"observed_max_inflight": [
1,
1,
1
],
"queries": [
31
],
"max_incremental_php_bytes": 5088608,
"mean_startup_to_ready_ms": 1430.336
},
{
"index_mode": "none",
"workload": "billing_drafts",
"workers": 2,
"complete_requests": 30,
"limited_requests": 0,
"p50_ms": 264.367,
"p95_sample_ms": 358.295,
"closed_loop_observed_rps": 6.92,
"observed_max_inflight": [
2,
2,
2
],
"queries": [
31
],
"max_incremental_php_bytes": 5088608,
"mean_startup_to_ready_ms": 1504.95
},
{
"index_mode": "none",
"workload": "billing_drafts",
"workers": 4,
"complete_requests": 60,
"limited_requests": 0,
"p50_ms": 429.457,
"p95_sample_ms": 495.43,
"closed_loop_observed_rps": 9.57,
"observed_max_inflight": [
4,
4,
4
],
"queries": [
31
],
"max_incremental_php_bytes": 5088608,
"mean_startup_to_ready_ms": 1353.583
},
{
"index_mode": "revision",
"workload": "clients",
"workers": 1,
"complete_requests": 15,
"limited_requests": 0,
"p50_ms": 11.544,
"p95_sample_ms": 13.478,
"closed_loop_observed_rps": 65.64,
"observed_max_inflight": [
1,
1,
1
],
"queries": [
11
],
"max_incremental_php_bytes": 91240,
"mean_startup_to_ready_ms": 846.268
},
{
"index_mode": "revision",
"workload": "clients",
"workers": 2,
"complete_requests": 30,
"limited_requests": 0,
"p50_ms": 11.079,
"p95_sample_ms": 12.162,
"closed_loop_observed_rps": 132.32,
"observed_max_inflight": [
2,
2,
2
],
"queries": [
11
],
"max_incremental_php_bytes": 91240,
"mean_startup_to_ready_ms": 852.6
},
{
"index_mode": "revision",
"workload": "clients",
"workers": 4,
"complete_requests": 60,
"limited_requests": 0,
"p50_ms": 14.79,
"p95_sample_ms": 21.402,
"closed_loop_observed_rps": 207.56,
"observed_max_inflight": [
4,
4,
4
],
"queries": [
11
],
"max_incremental_php_bytes": 91240,
"mean_startup_to_ready_ms": 1313.81
},
{
"index_mode": "revision",
"workload": "billing_drafts",
"workers": 1,
"complete_requests": 15,
"limited_requests": 0,
"p50_ms": 99.513,
"p95_sample_ms": 157.652,
"closed_loop_observed_rps": 8.47,
"observed_max_inflight": [
1,
1,
1
],
"queries": [
31
],
"max_incremental_php_bytes": 5088608,
"mean_startup_to_ready_ms": 920.204
},
{
"index_mode": "revision",
"workload": "billing_drafts",
"workers": 2,
"complete_requests": 30,
"limited_requests": 0,
"p50_ms": 102.922,
"p95_sample_ms": 188.288,
"closed_loop_observed_rps": 14.36,
"observed_max_inflight": [
2,
2,
2
],
"queries": [
31
],
"max_incremental_php_bytes": 5088608,
"mean_startup_to_ready_ms": 1097.493
},
{
"index_mode": "revision",
"workload": "billing_drafts",
"workers": 4,
"complete_requests": 60,
"limited_requests": 0,
"p50_ms": 102.861,
"p95_sample_ms": 121.342,
"closed_loop_observed_rps": 33.81,
"observed_max_inflight": [
4,
4,
4
],
"queries": [
31
],
"max_incremental_php_bytes": 5088608,
"mean_startup_to_ready_ms": 1123.177
}
],
"matrix_complete_requests": 420,
"matrix_limited_requests": 0,
"mixed_read_complete_requests": 20,
"mixed_read_max_inflight": 4,
"workload_response_hashes": {
"clients": "f5e976b68ab0c70cb2fbd6e70e7533175755e6767c3bcbb588ce6e5c7dbd99b6",
"billing_drafts": "302a56e89bec837712c0e2e598a12aa02482c4ad932f64baee92595ce1311bd4"
},
"competing_confirmation": {
"actual_lock_wait_observed": true,
"status": "database_error",
"sqlstate": "55P03",
"elapsed_ms": 1044.222
},
"preservation": {
"previous_qa_rows_and_indexes_unchanged": true,
"new_qa_fixture_retained": true,
"private_manifest_kept": true,
"synthetic_confirmation_rolled_back": true,
"test_index_removed": true,
"protected_six_records_untouched": true,
"blocked_cache_untouched": true,
"destination_connected": false,
"production_rights_changed": false,
"publication": false,
"purchasing_activation": false,
"checkpoint_created": false
},
"artifact": {
"path": "module-association-concurrency-20261102.json",
"sha256": "bd75881c7c60cf5c2acf4fb256d83e090b07f112becbf30c8620cbb81432546a"
},
"deployment_capacity_validated": false,
"visual_review_pending": true
}
@@ -0,0 +1,900 @@
{
"date": "2026-11-02",
"joint_page_read_implemented": true,
"source_sha256": "b901bccc73a59e80d98d32a56532e9300a55ba9a216e5ac5a0ce84d78f976397",
"controller_sha256": "6c16481f7e3f4355ba60ca22bc67385ec3b3113b4784e5d9f57025618e1735a9",
"method": {
"new_database_connections": 0,
"new_measurements": 0,
"valid_proofs_reused": true,
"reason": "All 24 required area/volume/page combinations have measured A/B/C outcomes, including explicitly bounded baseline attempts; no dimension is untested.",
"historical_batch_before_projection_sha256": "6df1a85af8ea3112ff8e61741408158cd0444944cc3e0b407ad5bd4ad8043361",
"current_projection_all_three_volume_matrix_measured": false,
"current_projection_scope": "Separate 10000-record-per-area, 100-line profiles; do not present historical B as current projected-code measurements.",
"memory_unit": "bytes",
"memory_metric": "incremental_php_used_bytes; peak_php_used_bytes also retained",
"latency_metric": "median_ms only for complete samples"
},
"coverage": [
{
"records_per_area": 1000,
"area": "clients",
"page_size": 25,
"before": {
"completed_samples": 3,
"median_ms": 1986.496,
"queries": 185,
"peak_php_used_bytes": 43887296,
"incremental_php_used_bytes": 88576,
"censored": false,
"last_observed_ms": 1975.37
},
"after_joint_read": {
"completed_samples": 3,
"median_ms": 36.773,
"queries": 11,
"peak_php_used_bytes": 43903208,
"incremental_php_used_bytes": 102696,
"censored": false,
"last_observed_ms": 29.283
},
"after_joint_read_with_indexes": {
"completed_samples": 3,
"median_ms": 10.664,
"queries": 11,
"peak_php_used_bytes": 44039280,
"incremental_php_used_bytes": 102536,
"censored": false,
"last_observed_ms": 11.516
}
},
{
"records_per_area": 1000,
"area": "clients",
"page_size": 100,
"before": {
"completed_samples": 3,
"median_ms": 7407.368,
"queries": 710,
"peak_php_used_bytes": 43974712,
"incremental_php_used_bytes": 162416,
"censored": false,
"last_observed_ms": 7358.838
},
"after_joint_read": {
"completed_samples": 3,
"median_ms": 29.77,
"queries": 11,
"peak_php_used_bytes": 44074560,
"incremental_php_used_bytes": 260472,
"censored": false,
"last_observed_ms": 29.77
},
"after_joint_read_with_indexes": {
"completed_samples": 3,
"median_ms": 12.854,
"queries": 11,
"peak_php_used_bytes": 44205112,
"incremental_php_used_bytes": 260312,
"censored": false,
"last_observed_ms": 12.607
}
},
{
"records_per_area": 1000,
"area": "services",
"page_size": 25,
"before": {
"completed_samples": 3,
"median_ms": 1924.424,
"queries": 185,
"peak_php_used_bytes": 43914616,
"incremental_php_used_bytes": 88632,
"censored": false,
"last_observed_ms": 1940.761
},
"after_joint_read": {
"completed_samples": 3,
"median_ms": 30.091,
"queries": 11,
"peak_php_used_bytes": 43929712,
"incremental_php_used_bytes": 101944,
"censored": false,
"last_observed_ms": 27.823
},
"after_joint_read_with_indexes": {
"completed_samples": 3,
"median_ms": 10.811,
"queries": 11,
"peak_php_used_bytes": 44054264,
"incremental_php_used_bytes": 101776,
"censored": false,
"last_observed_ms": 9.826
}
},
{
"records_per_area": 1000,
"area": "services",
"page_size": 100,
"before": {
"completed_samples": 3,
"median_ms": 7778.431,
"queries": 710,
"peak_php_used_bytes": 44001528,
"incremental_php_used_bytes": 162504,
"censored": false,
"last_observed_ms": 7778.431
},
"after_joint_read": {
"completed_samples": 3,
"median_ms": 31.962,
"queries": 11,
"peak_php_used_bytes": 44100504,
"incremental_php_used_bytes": 259680,
"censored": false,
"last_observed_ms": 31.962
},
"after_joint_read_with_indexes": {
"completed_samples": 3,
"median_ms": 11.898,
"queries": 11,
"peak_php_used_bytes": 44219696,
"incremental_php_used_bytes": 259528,
"censored": false,
"last_observed_ms": 10.903
}
},
{
"records_per_area": 1000,
"area": "service_drafts",
"page_size": 25,
"before": {
"completed_samples": 3,
"median_ms": 3905.946,
"queries": 435,
"peak_php_used_bytes": 43973256,
"incremental_php_used_bytes": 119760,
"censored": false,
"last_observed_ms": 3935.114
},
"after_joint_read": {
"completed_samples": 3,
"median_ms": 77.228,
"queries": 19,
"peak_php_used_bytes": 44081976,
"incremental_php_used_bytes": 226664,
"censored": false,
"last_observed_ms": 72.522
},
"after_joint_read_with_indexes": {
"completed_samples": 3,
"median_ms": 16.649,
"queries": 19,
"peak_php_used_bytes": 44194464,
"incremental_php_used_bytes": 226528,
"censored": false,
"last_observed_ms": 15.141
}
},
{
"records_per_area": 1000,
"area": "service_drafts",
"page_size": 100,
"before": {
"completed_samples": 0,
"median_ms": null,
"queries": null,
"peak_php_used_bytes": null,
"incremental_php_used_bytes": null,
"censored": true,
"last_observed_ms": 15014.911
},
"after_joint_read": {
"completed_samples": 3,
"median_ms": 77.016,
"queries": 19,
"peak_php_used_bytes": 44626272,
"incremental_php_used_bytes": 762504,
"censored": false,
"last_observed_ms": 77.016
},
"after_joint_read_with_indexes": {
"completed_samples": 3,
"median_ms": 22.162,
"queries": 19,
"peak_php_used_bytes": 44738048,
"incremental_php_used_bytes": 762368,
"censored": false,
"last_observed_ms": 22.115
}
},
{
"records_per_area": 1000,
"area": "billing_drafts",
"page_size": 25,
"before": {
"completed_samples": 3,
"median_ms": 5014.745,
"queries": 560,
"peak_php_used_bytes": 44010024,
"incremental_php_used_bytes": 134904,
"censored": false,
"last_observed_ms": 4823.376
},
"after_joint_read": {
"completed_samples": 3,
"median_ms": 96.212,
"queries": 23,
"peak_php_used_bytes": 44178416,
"incremental_php_used_bytes": 301480,
"censored": false,
"last_observed_ms": 94.739
},
"after_joint_read_with_indexes": {
"completed_samples": 3,
"median_ms": 19.615,
"queries": 23,
"peak_php_used_bytes": 44284608,
"incremental_php_used_bytes": 301344,
"censored": false,
"last_observed_ms": 22.34
}
},
{
"records_per_area": 1000,
"area": "billing_drafts",
"page_size": 100,
"before": {
"completed_samples": 0,
"median_ms": null,
"queries": null,
"peak_php_used_bytes": null,
"incremental_php_used_bytes": null,
"censored": true,
"last_observed_ms": 15001.514
},
"after_joint_read": {
"completed_samples": 3,
"median_ms": 100.602,
"queries": 23,
"peak_php_used_bytes": 44947480,
"incremental_php_used_bytes": 1062088,
"censored": false,
"last_observed_ms": 107.698
},
"after_joint_read_with_indexes": {
"completed_samples": 3,
"median_ms": 28.94,
"queries": 23,
"peak_php_used_bytes": 45053120,
"incremental_php_used_bytes": 1061952,
"censored": false,
"last_observed_ms": 30.172
}
},
{
"records_per_area": 5000,
"area": "clients",
"page_size": 25,
"before": {
"completed_samples": 3,
"median_ms": 6295.358,
"queries": 185,
"peak_php_used_bytes": 44891080,
"incremental_php_used_bytes": 88832,
"censored": false,
"last_observed_ms": 6312.188
},
"after_joint_read": {
"completed_samples": 3,
"median_ms": 97.221,
"queries": 11,
"peak_php_used_bytes": 44906744,
"incremental_php_used_bytes": 102704,
"censored": false,
"last_observed_ms": 112.29
},
"after_joint_read_with_indexes": {
"completed_samples": 3,
"median_ms": 18.454,
"queries": 11,
"peak_php_used_bytes": 45025520,
"incremental_php_used_bytes": 102544,
"censored": false,
"last_observed_ms": 18.454
}
},
{
"records_per_area": 5000,
"area": "clients",
"page_size": 100,
"before": {
"completed_samples": 0,
"median_ms": null,
"queries": null,
"peak_php_used_bytes": null,
"incremental_php_used_bytes": null,
"censored": true,
"last_observed_ms": 15035.078
},
"after_joint_read": {
"completed_samples": 3,
"median_ms": 87.006,
"queries": 11,
"peak_php_used_bytes": 45073320,
"incremental_php_used_bytes": 260736,
"censored": false,
"last_observed_ms": 87.006
},
"after_joint_read_with_indexes": {
"completed_samples": 3,
"median_ms": 19.76,
"queries": 11,
"peak_php_used_bytes": 45191232,
"incremental_php_used_bytes": 260576,
"censored": false,
"last_observed_ms": 20.742
}
},
{
"records_per_area": 5000,
"area": "services",
"page_size": 25,
"before": {
"completed_samples": 3,
"median_ms": 5238.39,
"queries": 185,
"peak_php_used_bytes": 44912728,
"incremental_php_used_bytes": 88888,
"censored": false,
"last_observed_ms": 5101.054
},
"after_joint_read": {
"completed_samples": 3,
"median_ms": 92.186,
"queries": 11,
"peak_php_used_bytes": 44928392,
"incremental_php_used_bytes": 102768,
"censored": false,
"last_observed_ms": 92.186
},
"after_joint_read_with_indexes": {
"completed_samples": 3,
"median_ms": 17.112,
"queries": 11,
"peak_php_used_bytes": 45040784,
"incremental_php_used_bytes": 102600,
"censored": false,
"last_observed_ms": 17.112
}
},
{
"records_per_area": 5000,
"area": "services",
"page_size": 100,
"before": {
"completed_samples": 0,
"median_ms": null,
"queries": null,
"peak_php_used_bytes": null,
"incremental_php_used_bytes": null,
"censored": true,
"last_observed_ms": 15008.401
},
"after_joint_read": {
"completed_samples": 3,
"median_ms": 77.976,
"queries": 11,
"peak_php_used_bytes": 45094784,
"incremental_php_used_bytes": 260816,
"censored": false,
"last_observed_ms": 79.222
},
"after_joint_read_with_indexes": {
"completed_samples": 3,
"median_ms": 18.127,
"queries": 11,
"peak_php_used_bytes": 45206688,
"incremental_php_used_bytes": 260664,
"censored": false,
"last_observed_ms": 17.877
}
},
{
"records_per_area": 5000,
"area": "service_drafts",
"page_size": 25,
"before": {
"completed_samples": 3,
"median_ms": 10553.094,
"queries": 435,
"peak_php_used_bytes": 44965376,
"incremental_php_used_bytes": 120016,
"censored": false,
"last_observed_ms": 11120.366
},
"after_joint_read": {
"completed_samples": 3,
"median_ms": 216.018,
"queries": 19,
"peak_php_used_bytes": 45074096,
"incremental_php_used_bytes": 226920,
"censored": false,
"last_observed_ms": 216.018
},
"after_joint_read_with_indexes": {
"completed_samples": 3,
"median_ms": 36.972,
"queries": 19,
"peak_php_used_bytes": 45180416,
"incremental_php_used_bytes": 226784,
"censored": false,
"last_observed_ms": 36.972
}
},
{
"records_per_area": 5000,
"area": "service_drafts",
"page_size": 100,
"before": {
"completed_samples": 0,
"median_ms": null,
"queries": null,
"peak_php_used_bytes": null,
"incremental_php_used_bytes": null,
"censored": true,
"last_observed_ms": 15047.893
},
"after_joint_read": {
"completed_samples": 3,
"median_ms": 232.943,
"queries": 19,
"peak_php_used_bytes": 45618392,
"incremental_php_used_bytes": 762760,
"censored": false,
"last_observed_ms": 232.943
},
"after_joint_read_with_indexes": {
"completed_samples": 3,
"median_ms": 44.376,
"queries": 19,
"peak_php_used_bytes": 45724160,
"incremental_php_used_bytes": 762624,
"censored": false,
"last_observed_ms": 51.99
}
},
{
"records_per_area": 5000,
"area": "billing_drafts",
"page_size": 25,
"before": {
"completed_samples": 3,
"median_ms": 13947.252,
"queries": 560,
"peak_php_used_bytes": 45002488,
"incremental_php_used_bytes": 135504,
"censored": false,
"last_observed_ms": 14018.632
},
"after_joint_read": {
"completed_samples": 3,
"median_ms": 377.178,
"queries": 23,
"peak_php_used_bytes": 45170280,
"incremental_php_used_bytes": 301480,
"censored": false,
"last_observed_ms": 452.889
},
"after_joint_read_with_indexes": {
"completed_samples": 3,
"median_ms": 33.662,
"queries": 23,
"peak_php_used_bytes": 45270464,
"incremental_php_used_bytes": 301344,
"censored": false,
"last_observed_ms": 31.493
}
},
{
"records_per_area": 5000,
"area": "billing_drafts",
"page_size": 100,
"before": {
"completed_samples": 0,
"median_ms": null,
"queries": null,
"peak_php_used_bytes": null,
"incremental_php_used_bytes": null,
"censored": true,
"last_observed_ms": 15014.771
},
"after_joint_read": {
"completed_samples": 3,
"median_ms": 322.135,
"queries": 23,
"peak_php_used_bytes": 45939344,
"incremental_php_used_bytes": 1062088,
"censored": false,
"last_observed_ms": 346.88
},
"after_joint_read_with_indexes": {
"completed_samples": 3,
"median_ms": 65.664,
"queries": 23,
"peak_php_used_bytes": 46038976,
"incremental_php_used_bytes": 1061952,
"censored": false,
"last_observed_ms": 67.107
}
},
{
"records_per_area": 10000,
"area": "clients",
"page_size": 25,
"before": {
"completed_samples": 3,
"median_ms": 9683.039,
"queries": 185,
"peak_php_used_bytes": 45757968,
"incremental_php_used_bytes": 88832,
"censored": false,
"last_observed_ms": 9162.265
},
"after_joint_read": {
"completed_samples": 3,
"median_ms": 156.317,
"queries": 11,
"peak_php_used_bytes": 45773632,
"incremental_php_used_bytes": 102704,
"censored": false,
"last_observed_ms": 122.2
},
"after_joint_read_with_indexes": {
"completed_samples": 3,
"median_ms": 13.88,
"queries": 11,
"peak_php_used_bytes": 45886464,
"incremental_php_used_bytes": 102544,
"censored": false,
"last_observed_ms": 13.88
}
},
{
"records_per_area": 10000,
"area": "clients",
"page_size": 100,
"before": {
"completed_samples": 0,
"median_ms": null,
"queries": null,
"peak_php_used_bytes": null,
"incremental_php_used_bytes": null,
"censored": true,
"last_observed_ms": 15162.011
},
"after_joint_read": {
"completed_samples": 3,
"median_ms": 203.094,
"queries": 11,
"peak_php_used_bytes": 45948400,
"incremental_php_used_bytes": 260736,
"censored": false,
"last_observed_ms": 203.094
},
"after_joint_read_with_indexes": {
"completed_samples": 3,
"median_ms": 14.52,
"queries": 11,
"peak_php_used_bytes": 46052176,
"incremental_php_used_bytes": 260576,
"censored": false,
"last_observed_ms": 13.473
}
},
{
"records_per_area": 10000,
"area": "services",
"page_size": 25,
"before": {
"completed_samples": 3,
"median_ms": 9385.151,
"queries": 185,
"peak_php_used_bytes": 45787552,
"incremental_php_used_bytes": 88632,
"censored": false,
"last_observed_ms": 9819.329
},
"after_joint_read": {
"completed_samples": 3,
"median_ms": 117.184,
"queries": 11,
"peak_php_used_bytes": 45802648,
"incremental_php_used_bytes": 101944,
"censored": false,
"last_observed_ms": 133.623
},
"after_joint_read_with_indexes": {
"completed_samples": 3,
"median_ms": 11.662,
"queries": 11,
"peak_php_used_bytes": 45900904,
"incremental_php_used_bytes": 101776,
"censored": false,
"last_observed_ms": 11.772
}
},
{
"records_per_area": 10000,
"area": "services",
"page_size": 100,
"before": {
"completed_samples": 0,
"median_ms": null,
"queries": null,
"peak_php_used_bytes": null,
"incremental_php_used_bytes": null,
"censored": true,
"last_observed_ms": 15016.685
},
"after_joint_read": {
"completed_samples": 3,
"median_ms": 109.768,
"queries": 11,
"peak_php_used_bytes": 45968728,
"incremental_php_used_bytes": 259680,
"censored": false,
"last_observed_ms": 109.768
},
"after_joint_read_with_indexes": {
"completed_samples": 3,
"median_ms": 14.871,
"queries": 11,
"peak_php_used_bytes": 46066496,
"incremental_php_used_bytes": 259528,
"censored": false,
"last_observed_ms": 14.871
}
},
{
"records_per_area": 10000,
"area": "service_drafts",
"page_size": 25,
"before": {
"completed_samples": 0,
"median_ms": null,
"queries": null,
"peak_php_used_bytes": null,
"incremental_php_used_bytes": null,
"censored": true,
"last_observed_ms": 15036.425
},
"after_joint_read": {
"completed_samples": 3,
"median_ms": 333.786,
"queries": 19,
"peak_php_used_bytes": 45943832,
"incremental_php_used_bytes": 226288,
"censored": false,
"last_observed_ms": 333.786
},
"after_joint_read_with_indexes": {
"completed_samples": 3,
"median_ms": 20.321,
"queries": 19,
"peak_php_used_bytes": 46040728,
"incremental_php_used_bytes": 226152,
"censored": false,
"last_observed_ms": 20.321
}
},
{
"records_per_area": 10000,
"area": "service_drafts",
"page_size": 100,
"before": {
"completed_samples": 0,
"median_ms": null,
"queries": null,
"peak_php_used_bytes": null,
"incremental_php_used_bytes": null,
"censored": true,
"last_observed_ms": 15103.593
},
"after_joint_read": {
"completed_samples": 3,
"median_ms": 399.873,
"queries": 19,
"peak_php_used_bytes": 46488128,
"incremental_php_used_bytes": 762128,
"censored": false,
"last_observed_ms": 399.873
},
"after_joint_read_with_indexes": {
"completed_samples": 3,
"median_ms": 26.888,
"queries": 19,
"peak_php_used_bytes": 46584312,
"incremental_php_used_bytes": 761992,
"censored": false,
"last_observed_ms": 26.621
}
},
{
"records_per_area": 10000,
"area": "billing_drafts",
"page_size": 25,
"before": {
"completed_samples": 0,
"median_ms": null,
"queries": null,
"peak_php_used_bytes": null,
"incremental_php_used_bytes": null,
"censored": true,
"last_observed_ms": 15034.132
},
"after_joint_read": {
"completed_samples": 3,
"median_ms": 592.801,
"queries": 23,
"peak_php_used_bytes": 46035560,
"incremental_php_used_bytes": 301104,
"censored": false,
"last_observed_ms": 684.446
},
"after_joint_read_with_indexes": {
"completed_samples": 3,
"median_ms": 28.728,
"queries": 23,
"peak_php_used_bytes": 46131032,
"incremental_php_used_bytes": 300968,
"censored": false,
"last_observed_ms": 23.471
}
},
{
"records_per_area": 10000,
"area": "billing_drafts",
"page_size": 100,
"before": {
"completed_samples": 0,
"median_ms": null,
"queries": null,
"peak_php_used_bytes": null,
"incremental_php_used_bytes": null,
"censored": true,
"last_observed_ms": 15151.598
},
"after_joint_read": {
"completed_samples": 3,
"median_ms": 451.128,
"queries": 23,
"peak_php_used_bytes": 46804624,
"incremental_php_used_bytes": 1061712,
"censored": false,
"last_observed_ms": 449.233
},
"after_joint_read_with_indexes": {
"completed_samples": 3,
"median_ms": 35.65,
"queries": 23,
"peak_php_used_bytes": 46899384,
"incremental_php_used_bytes": 1061576,
"censored": false,
"last_observed_ms": 35.65
}
}
],
"missing_combinations": [],
"additional_filter_cases": 9,
"complete_measured_requests": 258,
"bounded_baseline_attempts": 13,
"current_projection": {
"all_complete_responses_identical": true,
"records_per_area": 10000,
"limited_attempts": 0,
"lines_per_draft": 100,
"description_bytes": [
128,
1000
],
"scenarios": 44,
"complete_scenarios": 44,
"memory_budget_diagnostic_bytes": 201326592,
"capacity_validated": false,
"complete_measured_requests": 132,
"page_sizes": [
25,
100
],
"variants": [
"pre_projection",
"none",
"revision_only",
"pair"
],
"php_memory_limit": "512M"
},
"concurrency": {
"test": {
"tests": 1,
"assertions": 346,
"errors": 0,
"failures": 0,
"junit_sha256": "217e4ff8096d985a523748a9b98bc3b573614c8dbe2318e1a0a2b7a26798cc1d"
},
"matrix_reads": 420,
"mixed_reads": 20
},
"release": {
"tests": 1,
"assertions": 79,
"failures": 0,
"errors": 0,
"junit_sha256": "b2fcb62f49a1f13e0b14882a8d68c45cf2c634d9f7f7094083e917d7175f9d3a"
},
"http": {
"http_lock": {
"tests": 1,
"assertions": 54,
"errors": 0,
"failures": 0,
"sha256": "87dfb60f41c12a2c7b34c2236d8d2af631b6737360637347017351e946e5b69c"
},
"affected_queue": {
"tests": 13,
"assertions": 232,
"errors": 0,
"failures": 0,
"sha256": "e226bed0ab078a35175ac031e46441c229e833069ab5d0229cbd117041d8e284"
}
},
"validated_existing_proofs": [
{
"path": "docs/proofs/module-association-http-lock-20261102.json",
"sha256": "fa3d95ba919d23b6269e6a27f5f085718247e9ba0d06291c3276db62c04d9286"
},
{
"path": "docs/proofs/module-association-release-20261102.json",
"sha256": "a4017200b2ce7d60efcc3590780019309850f3c864f90ba0b3c786382fae4f28"
},
{
"path": "docs/proofs/module-association-optimization-comparison-20261102.json",
"sha256": "2f24696cd4282856151c044de4830f77d12ae618430461b2202360a30215580a"
},
{
"path": "docs/proofs/module-association-optimization-summary-20261102.json",
"sha256": "6371512a070c3ae71872eeb76fae6f04d7a1aeeffc97510a3ea8e5e263396591"
},
{
"path": "docs/proofs/module-association-projection-fanout-20261102.json",
"sha256": "e0353b7925a997a8a067a996d20bf462cd89c75b4eb3e302629015297a356f2d"
},
{
"path": "docs/proofs/module-association-projection-summary-20261102.json",
"sha256": "171309fd4ca204e6e485e1790b1892d63e5f0ad13b494bd6d09434c5c9e8a193"
},
{
"path": "docs/proofs/module-association-concurrency-20261102.json",
"sha256": "bd75881c7c60cf5c2acf4fb256d83e090b07f112becbf30c8620cbb81432546a"
},
{
"path": "docs/proofs/module-association-concurrency-summary-20261102.json",
"sha256": "bb12a5fd566d8c606a7a0e082256ad82a4b399929755c60f8be69bf1bcd6b239"
}
],
"preservation": {
"existing_proofs_unchanged": true,
"protected_six_records_untouched": true,
"blocked_cache_untouched": true,
"destination_connected": false,
"application_code_changed": false,
"indexes_created": false,
"rights_changed": false,
"purchasing_activated": false,
"publication": false,
"checkpoint": false
},
"visual_review_pending": true,
"deployment_capacity_validated": false
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,69 @@
{
"identity": {
"database": "sgf_tempo_test",
"role": "sgf_test_runner",
"port": 55439,
"cluster": "sgf_modular_regression_2576427d1939"
},
"run_tag": "f6668b16cd7e",
"source_sha256": "b901bccc73a59e80d98d32a56532e9300a55ba9a216e5ac5a0ce84d78f976397",
"controller_sha256": "6c16481f7e3f4355ba60ca22bc67385ec3b3113b4784e5d9f57025618e1735a9",
"cases": [
{
"case": "confirm_rollback",
"wait_event": "transactionid",
"blocking_parent_verified": true,
"timeout": {
"status": "http_busy",
"http_status": 423,
"code": "association_busy",
"body_keys": [
"code",
"message"
],
"elapsed_ms": 1086.658
},
"recovery": "200_then_idempotent_replay",
"decision_events_after_retry": 1,
"duplicate_decision": false
},
{
"case": "confirm_commit",
"wait_event": "transactionid",
"blocking_parent_verified": true,
"timeout": {
"status": "http_busy",
"http_status": 423,
"code": "association_busy",
"body_keys": [
"code",
"message"
],
"elapsed_ms": 1093.136
},
"recovery": "409_then_new_preview",
"decision_events_after_retry": 1,
"duplicate_decision": false
},
{
"case": "preview_rollback",
"wait_event": "transactionid",
"blocking_parent_verified": true,
"timeout": {
"status": "http_busy",
"http_status": 423,
"code": "association_busy",
"body_keys": [
"code",
"message"
],
"elapsed_ms": 1083.944
},
"recovery": "200_then_idempotent_replay",
"decision_events_after_retry": 1,
"duplicate_decision": false
}
],
"completed": true,
"previous_qa_rows_and_index_catalog_preserved": true
}
@@ -0,0 +1,134 @@
{
"date": "2026-11-02",
"source_sha256": "b901bccc73a59e80d98d32a56532e9300a55ba9a216e5ac5a0ce84d78f976397",
"controller_sha256": "6c16481f7e3f4355ba60ca22bc67385ec3b3113b4784e5d9f57025618e1735a9",
"tests": {
"http_lock": {
"tests": 1,
"assertions": 54,
"errors": 0,
"failures": 0,
"sha256": "87dfb60f41c12a2c7b34c2236d8d2af631b6737360637347017351e946e5b69c"
},
"affected_queue": {
"tests": 13,
"assertions": 232,
"errors": 0,
"failures": 0,
"sha256": "e226bed0ab078a35175ac031e46441c229e833069ab5d0229cbd117041d8e284"
}
},
"cases": [
{
"case": "confirm_rollback",
"wait_event": "transactionid",
"blocking_parent_verified": true,
"timeout": {
"status": "http_busy",
"http_status": 423,
"code": "association_busy",
"body_keys": [
"code",
"message"
],
"elapsed_ms": 1086.658
},
"recovery": "200_then_idempotent_replay",
"decision_events_after_retry": 1,
"duplicate_decision": false
},
{
"case": "confirm_commit",
"wait_event": "transactionid",
"blocking_parent_verified": true,
"timeout": {
"status": "http_busy",
"http_status": 423,
"code": "association_busy",
"body_keys": [
"code",
"message"
],
"elapsed_ms": 1093.136
},
"recovery": "409_then_new_preview",
"decision_events_after_retry": 1,
"duplicate_decision": false
},
{
"case": "preview_rollback",
"wait_event": "transactionid",
"blocking_parent_verified": true,
"timeout": {
"status": "http_busy",
"http_status": 423,
"code": "association_busy",
"body_keys": [
"code",
"message"
],
"elapsed_ms": 1083.944
},
"recovery": "200_then_idempotent_replay",
"decision_events_after_retry": 1,
"duplicate_decision": false
}
],
"preservation": {
"previous_qa_rows_and_index_catalog_preserved": true,
"prior_proof_hashes_preserved": true,
"protected_six_records_untouched": true,
"blocked_cache_untouched": true,
"destination_connected": false,
"public_rights_changed": false,
"indexes_created": false,
"purchasing_activation": false,
"publication": false,
"checkpoint": false,
"new_qa_fixture_retained": true
},
"proof": {
"path": "docs/proofs/module-association-http-lock-20261102.json",
"sha256": "fa3d95ba919d23b6269e6a27f5f085718247e9ba0d06291c3276db62c04d9286"
},
"previous_proofs": [
{
"path": "docs/proofs/module-association-release-20261102.json",
"sha256": "a4017200b2ce7d60efcc3590780019309850f3c864f90ba0b3c786382fae4f28"
},
{
"path": "docs/proofs/module-association-optimization-comparison-20261102.json",
"sha256": "2f24696cd4282856151c044de4830f77d12ae618430461b2202360a30215580a"
},
{
"path": "docs/proofs/module-association-optimization-summary-20261102.json",
"sha256": "6371512a070c3ae71872eeb76fae6f04d7a1aeeffc97510a3ea8e5e263396591"
},
{
"path": "docs/proofs/module-association-projection-fanout-20261102.json",
"sha256": "e0353b7925a997a8a067a996d20bf462cd89c75b4eb3e302629015297a356f2d"
},
{
"path": "docs/proofs/module-association-projection-summary-20261102.json",
"sha256": "171309fd4ca204e6e485e1790b1892d63e5f0ad13b494bd6d09434c5c9e8a193"
},
{
"path": "docs/proofs/module-association-concurrency-20261102.json",
"sha256": "bd75881c7c60cf5c2acf4fb256d83e090b07f112becbf30c8620cbb81432546a"
},
{
"path": "docs/proofs/module-association-concurrency-summary-20261102.json",
"sha256": "bb12a5fd566d8c606a7a0e082256ad82a4b399929755c60f8be69bf1bcd6b239"
}
],
"method": {
"http_kernel_in_process": true,
"independent_lock_contender": true,
"test_lock_timeout_ms": 1000,
"runtime_timeout_changed": false,
"automatic_decision_retry_added": false,
"network_browser_login_tls_tested": false
},
"deployment_capacity_validated": false,
"visual_review_pending": true
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,77 @@
{
"identity": {
"database": "sgf_tempo_test",
"role": "sgf_test_runner",
"port": 55439,
"cluster": "sgf_modular_regression_2576427d1939",
"postgres": "17.11"
},
"indexes": [
{
"tablename": "a_billing_drafts",
"indexname": "a_billing_drafts_pkey",
"indexdef": "CREATE UNIQUE INDEX a_billing_drafts_pkey ON public.a_billing_drafts USING btree (id)"
},
{
"tablename": "a_billing_drafts",
"indexname": "a_billing_drafts_tenant_id_company_id_id_unique",
"indexdef": "CREATE UNIQUE INDEX a_billing_drafts_tenant_id_company_id_id_unique ON public.a_billing_drafts USING btree (tenant_id, company_id, id)"
},
{
"tablename": "a_billing_drafts",
"indexname": "a_billing_drafts_tenant_id_company_id_unit_id_id_unique",
"indexdef": "CREATE UNIQUE INDEX a_billing_drafts_tenant_id_company_id_unit_id_id_unique ON public.a_billing_drafts USING btree (tenant_id, company_id, unit_id, id)"
},
{
"tablename": "a_clients",
"indexname": "a_clients_pkey",
"indexdef": "CREATE UNIQUE INDEX a_clients_pkey ON public.a_clients USING btree (id)"
},
{
"tablename": "a_clients",
"indexname": "a_clients_tenant_id_company_id_id_unique",
"indexdef": "CREATE UNIQUE INDEX a_clients_tenant_id_company_id_id_unique ON public.a_clients USING btree (tenant_id, company_id, id)"
},
{
"tablename": "a_clients",
"indexname": "a_clients_tenant_id_company_id_unit_id_id_unique",
"indexdef": "CREATE UNIQUE INDEX a_clients_tenant_id_company_id_unit_id_id_unique ON public.a_clients USING btree (tenant_id, company_id, unit_id, id)"
},
{
"tablename": "a_service_drafts",
"indexname": "a_service_drafts_pkey",
"indexdef": "CREATE UNIQUE INDEX a_service_drafts_pkey ON public.a_service_drafts USING btree (id)"
},
{
"tablename": "a_service_drafts",
"indexname": "a_service_drafts_tenant_id_company_id_id_unique",
"indexdef": "CREATE UNIQUE INDEX a_service_drafts_tenant_id_company_id_id_unique ON public.a_service_drafts USING btree (tenant_id, company_id, id)"
},
{
"tablename": "a_service_drafts",
"indexname": "a_service_drafts_tenant_id_company_id_unit_id_id_unique",
"indexdef": "CREATE UNIQUE INDEX a_service_drafts_tenant_id_company_id_unit_id_id_unique ON public.a_service_drafts USING btree (tenant_id, company_id, unit_id, id)"
},
{
"tablename": "a_services",
"indexname": "a_services_pkey",
"indexdef": "CREATE UNIQUE INDEX a_services_pkey ON public.a_services USING btree (id)"
},
{
"tablename": "a_services",
"indexname": "a_services_tenant_id_company_id_id_unique",
"indexdef": "CREATE UNIQUE INDEX a_services_tenant_id_company_id_id_unique ON public.a_services USING btree (tenant_id, company_id, id)"
},
{
"tablename": "a_services",
"indexname": "a_services_tenant_id_company_id_unit_id_id_unique",
"indexdef": "CREATE UNIQUE INDEX a_services_tenant_id_company_id_unit_id_id_unique ON public.a_services USING btree (tenant_id, company_id, unit_id, id)"
},
{
"tablename": "identity_audit",
"indexname": "identity_audit_pkey",
"indexdef": "CREATE UNIQUE INDEX identity_audit_pkey ON public.identity_audit USING btree (id)"
}
],
"read_only": true
}
@@ -0,0 +1,43 @@
{
"identity": {
"database": "sgf_tempo_test",
"role": "sgf_test_runner",
"port": 55439,
"cluster": "sgf_modular_regression_2576427d1939"
},
"tables": {
"a_clients": {
"rows": 0,
"fingerprint": "d41d8cd98f00b204e9800998ecf8427e"
},
"a_services": {
"rows": 0,
"fingerprint": "d41d8cd98f00b204e9800998ecf8427e"
},
"a_service_drafts": {
"rows": 0,
"fingerprint": "d41d8cd98f00b204e9800998ecf8427e"
},
"a_billing_drafts": {
"rows": 0,
"fingerprint": "d41d8cd98f00b204e9800998ecf8427e"
},
"identity_audit": {
"rows": 0,
"fingerprint": "d41d8cd98f00b204e9800998ecf8427e"
},
"users": {
"rows": 0,
"fingerprint": "d41d8cd98f00b204e9800998ecf8427e"
},
"permission_grants": {
"rows": 0,
"fingerprint": "d41d8cd98f00b204e9800998ecf8427e"
},
"company_memberships": {
"rows": 0,
"fingerprint": "d41d8cd98f00b204e9800998ecf8427e"
}
},
"read_only": true
}
@@ -0,0 +1,43 @@
{
"identity": {
"database": "sgf_tempo_test",
"role": "sgf_test_runner",
"port": 55439,
"cluster": "sgf_modular_regression_2576427d1939"
},
"tables": {
"a_clients": {
"rows": 0,
"fingerprint": "d41d8cd98f00b204e9800998ecf8427e"
},
"a_services": {
"rows": 0,
"fingerprint": "d41d8cd98f00b204e9800998ecf8427e"
},
"a_service_drafts": {
"rows": 0,
"fingerprint": "d41d8cd98f00b204e9800998ecf8427e"
},
"a_billing_drafts": {
"rows": 0,
"fingerprint": "d41d8cd98f00b204e9800998ecf8427e"
},
"identity_audit": {
"rows": 0,
"fingerprint": "d41d8cd98f00b204e9800998ecf8427e"
},
"users": {
"rows": 0,
"fingerprint": "d41d8cd98f00b204e9800998ecf8427e"
},
"permission_grants": {
"rows": 0,
"fingerprint": "d41d8cd98f00b204e9800998ecf8427e"
},
"company_memberships": {
"rows": 0,
"fingerprint": "d41d8cd98f00b204e9800998ecf8427e"
}
},
"read_only": true
}
@@ -0,0 +1,56 @@
{
"date": "2026-11-02",
"accepted_functional_checkpoint": "340f3bb5fa0e72d659abe43f3498b49e25ca3809",
"functional_source_changed": false,
"new_test": {
"assertions": 2439,
"errors": 0,
"tests": 1,
"junit_sha256": "658e67aae1fca715a45541cf3b7da6b6ff9c3a3a8181f9226d74af2f65e3c726",
"failures": 0
},
"workload": {
"concurrent_capacity_tested": false,
"database_context": "sgf_tempo_test / sgf_test_runner / 55439 / sgf_modular_regression_2576427d1939",
"postgres": "17.11",
"diagnostic_budget_cases": 1,
"budget_is_not_sla": true,
"measured_complete_requests": 78,
"diagnostic_request_budget_ms": 15000,
"complete_cases": 26,
"cases": 27
},
"rollback": {
"snapshots": [
"module-association-load-postcheck1-20261102.json",
"module-association-load-postcheck2-20261102.json"
],
"observation": "Both snapshots were captured AFTER the run; they establish empty test tables and stability, not a pre-run fingerprint comparison.",
"sequences_not_compared": true,
"analyze_was_used": true,
"post_run_empty_tables": 8
},
"source_artifact": {
"sha256": "fde68e68e49ba81cc48e9d01455751c97e66489907f30b7b00c84ff34ca59a11",
"report": "docs/proofs/module-association-load-20261102.json"
},
"method_limits": [
"Sequential authenticated in-process HTTP kernel dispatch, no external network/login/browser latency",
"Three samples per completed case; no p95, throughput or concurrent-user capacity conclusion",
"Scales run serially in the same DB using rollback and ANALYZE; no fresh database or VACUUM between scales; physical table layout and cache can differ",
"Peak PHP memory includes harness/fixture allocations; not PostgreSQL memory",
"Generated history uses commercial association/removal cycles; not every possible module/history distribution"
],
"initial_harness_correction": "First fixture attempt failed with PostgreSQL 42P18; explicit text casts were added to synthetic JSON parameters. The failed transaction rolled back; accepted product code was unchanged.",
"preserved": {
"no_purchasing_activation": true,
"blocked_cache_untouched": true,
"public_rights_unchanged": true,
"no_publication": true,
"visual_review_pending": true,
"real_associations_not_decided": true,
"protected_six_records_not_accessed": true,
"deployment_capacity_pending": true,
"no_new_checkpoint": true
}
}
@@ -0,0 +1,30 @@
{
"date": "2026-11-02",
"variants": [
{
"experimental_indexes": false,
"refusals_equal": {
"reader": 403,
"limited": 403,
"unselected_unit": 403,
"invalid_page_size": 422,
"old_generation": 409
},
"revoked_dependency_response_identical": true,
"response_sha256": "9390bf89fbd259d5dab9d282882d10e1ea4af089b2fb23d47d36fffa458110e0"
},
{
"experimental_indexes": true,
"refusals_equal": {
"reader": 403,
"limited": 403,
"unselected_unit": 403,
"invalid_page_size": 422,
"old_generation": 409
},
"revoked_dependency_response_identical": true,
"response_sha256": "9390bf89fbd259d5dab9d282882d10e1ea4af089b2fb23d47d36fffa458110e0"
}
],
"indexes_rolled_back": true
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,672 @@
{
"date": "2026-11-02",
"identity": {
"database": "sgf_tempo_test",
"role": "sgf_test_runner",
"port": 55439,
"cluster": "sgf_modular_regression_2576427d1939"
},
"records_per_area": 10000,
"variants": {
"batch": [
{
"signature": "50ff98a3116b073b1b26095ecaf597708917b73ca926112c977ec7507813bf3a",
"shape": "WITH scoped AS MATERIALIZED (select id,action,details::jsonb->>'record_id' AS record_id,details::jsonb->>'module_id' AS module_id from \"identity_audit\" where (\"tenant_id\" = ? and \"company_id\" = ?) and \"action\" in (?, ?, ?) and details::jsonb->>'area' = ? and details::jsonb->>'record_id' in (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)),\n latest AS (SELECT DISTINCT ON (record_id,module_id) record_id,module_id,action FROM scoped\n WHERE action <> 'module.record.reviewed' ORDER BY record_id,module_id,id DESC),\n revisions AS (SELECT record_id,max(id) AS revision FROM scoped GROUP BY record_id)\n SELECT r.record_id,r.revision,coalesce(jsonb_agg(l.module_id ORDER BY l.module_id)\n FILTER (WHERE l.action='module.record.associated'),'[]'::jsonb) AS modules\n FROM revisions r LEFT JOIN latest l ON l.record_id=r.record_id GROUP BY r.record_id,r.revision",
"execution_ms": 98.525,
"nodes": [
{
"Node Type": "Aggregate",
"Actual Rows": 67,
"Actual Loops": 1,
"Shared Hit Blocks": 7320,
"Shared Read Blocks": 0,
"Temp Read Blocks": 0,
"Temp Written Blocks": 0
},
{
"Node Type": "Gather",
"Actual Rows": 569,
"Actual Loops": 1,
"Shared Hit Blocks": 7320,
"Shared Read Blocks": 0,
"Temp Read Blocks": 0,
"Temp Written Blocks": 0
},
{
"Node Type": "Seq Scan",
"Relation Name": "identity_audit",
"Actual Rows": 190,
"Actual Loops": 3,
"Rows Removed by Filter": 75367,
"Shared Hit Blocks": 7320,
"Shared Read Blocks": 0,
"Temp Read Blocks": 0,
"Temp Written Blocks": 0
},
{
"Node Type": "Sort",
"Actual Rows": 67,
"Actual Loops": 1,
"Shared Hit Blocks": 7320,
"Shared Read Blocks": 0,
"Temp Read Blocks": 0,
"Temp Written Blocks": 0
},
{
"Node Type": "Hash Join",
"Actual Rows": 67,
"Actual Loops": 1,
"Shared Hit Blocks": 7320,
"Shared Read Blocks": 0,
"Temp Read Blocks": 0,
"Temp Written Blocks": 0
},
{
"Node Type": "Unique",
"Actual Rows": 67,
"Actual Loops": 1,
"Shared Hit Blocks": 0,
"Shared Read Blocks": 0,
"Temp Read Blocks": 0,
"Temp Written Blocks": 0
},
{
"Node Type": "Sort",
"Actual Rows": 569,
"Actual Loops": 1,
"Shared Hit Blocks": 0,
"Shared Read Blocks": 0,
"Temp Read Blocks": 0,
"Temp Written Blocks": 0
},
{
"Node Type": "CTE Scan",
"Actual Rows": 569,
"Actual Loops": 1,
"Rows Removed by Filter": 0,
"Shared Hit Blocks": 0,
"Shared Read Blocks": 0,
"Temp Read Blocks": 0,
"Temp Written Blocks": 0
},
{
"Node Type": "Hash",
"Actual Rows": 67,
"Actual Loops": 1,
"Shared Hit Blocks": 7320,
"Shared Read Blocks": 0,
"Temp Read Blocks": 0,
"Temp Written Blocks": 0
},
{
"Node Type": "Aggregate",
"Actual Rows": 67,
"Actual Loops": 1,
"Shared Hit Blocks": 7320,
"Shared Read Blocks": 0,
"Temp Read Blocks": 0,
"Temp Written Blocks": 0
},
{
"Node Type": "CTE Scan",
"Actual Rows": 569,
"Actual Loops": 1,
"Shared Hit Blocks": 7320,
"Shared Read Blocks": 0,
"Temp Read Blocks": 0,
"Temp Written Blocks": 0
}
]
},
{
"signature": "10d02426d5830d39b0c3d99210b0d23d0023c3ee581a7885c043b23039fd95e3",
"shape": "select count(*) as \"aggregate\" from \"a_clients\" where (\"tenant_id\" = ? and \"company_id\" = ? and \"unit_id\" is null) and NOT EXISTS (SELECT 1 FROM identity_audit me WHERE me.tenant_id=a_clients.tenant_id AND me.company_id=a_clients.company_id\n AND me.action IN ('module.record.associated','module.record.disassociated') AND me.details::jsonb->>'area'=? AND me.details::jsonb->>'record_id'=a_clients.id::text)",
"execution_ms": 194.636,
"nodes": [
{
"Node Type": "Aggregate",
"Actual Rows": 1,
"Actual Loops": 1,
"Shared Hit Blocks": 7461,
"Shared Read Blocks": 0,
"Temp Read Blocks": 672,
"Temp Written Blocks": 672
},
{
"Node Type": "Hash Join",
"Actual Rows": 3334,
"Actual Loops": 1,
"Shared Hit Blocks": 7461,
"Shared Read Blocks": 0,
"Temp Read Blocks": 672,
"Temp Written Blocks": 672
},
{
"Node Type": "Seq Scan",
"Relation Name": "a_clients",
"Actual Rows": 10000,
"Actual Loops": 1,
"Rows Removed by Filter": 104,
"Shared Hit Blocks": 135,
"Shared Read Blocks": 0,
"Temp Read Blocks": 0,
"Temp Written Blocks": 0
},
{
"Node Type": "Hash",
"Actual Rows": 56661,
"Actual Loops": 1,
"Shared Hit Blocks": 7326,
"Shared Read Blocks": 0,
"Temp Read Blocks": 0,
"Temp Written Blocks": 610
},
{
"Node Type": "Gather",
"Actual Rows": 56661,
"Actual Loops": 1,
"Shared Hit Blocks": 7326,
"Shared Read Blocks": 0,
"Temp Read Blocks": 0,
"Temp Written Blocks": 0
},
{
"Node Type": "Seq Scan",
"Relation Name": "identity_audit",
"Actual Rows": 18887,
"Actual Loops": 3,
"Rows Removed by Filter": 56669,
"Shared Hit Blocks": 7326,
"Shared Read Blocks": 0,
"Temp Read Blocks": 0,
"Temp Written Blocks": 0
}
]
},
{
"signature": "d829bbef004ef2eaed502b3df683fdde82e28f848a85c0e2202e743b86bc046d",
"shape": "select * from \"a_clients\" where (\"tenant_id\" = ? and \"company_id\" = ? and \"unit_id\" is null) and NOT EXISTS (SELECT 1 FROM identity_audit me WHERE me.tenant_id=a_clients.tenant_id AND me.company_id=a_clients.company_id\n AND me.action IN ('module.record.associated','module.record.disassociated') AND me.details::jsonb->>'area'=? AND me.details::jsonb->>'record_id'=a_clients.id::text) order by \"id\" asc limit 25 offset 0",
"execution_ms": 1323.111,
"nodes": [
{
"Node Type": "Limit",
"Actual Rows": 25,
"Actual Loops": 1,
"Shared Hit Blocks": 7332,
"Shared Read Blocks": 0,
"Temp Read Blocks": 29477,
"Temp Written Blocks": 1162
},
{
"Node Type": "Nested Loop",
"Actual Rows": 25,
"Actual Loops": 1,
"Shared Hit Blocks": 7332,
"Shared Read Blocks": 0,
"Temp Read Blocks": 29477,
"Temp Written Blocks": 1162
},
{
"Node Type": "Index Scan",
"Index Name": "a_clients_pkey",
"Relation Name": "a_clients",
"Actual Rows": 73,
"Actual Loops": 1,
"Rows Removed by Filter": 4,
"Shared Hit Blocks": 6,
"Shared Read Blocks": 0,
"Temp Read Blocks": 0,
"Temp Written Blocks": 0
},
{
"Node Type": "Materialize",
"Actual Rows": 20450,
"Actual Loops": 73,
"Shared Hit Blocks": 7326,
"Shared Read Blocks": 0,
"Temp Read Blocks": 29477,
"Temp Written Blocks": 1162
},
{
"Node Type": "Gather",
"Actual Rows": 56661,
"Actual Loops": 1,
"Shared Hit Blocks": 7326,
"Shared Read Blocks": 0,
"Temp Read Blocks": 0,
"Temp Written Blocks": 0
},
{
"Node Type": "Seq Scan",
"Relation Name": "identity_audit",
"Actual Rows": 18887,
"Actual Loops": 3,
"Rows Removed by Filter": 56669,
"Shared Hit Blocks": 7326,
"Shared Read Blocks": 0,
"Temp Read Blocks": 0,
"Temp Written Blocks": 0
}
]
},
{
"signature": "2cba1346e4495a631236b0eb5d232028dcb4c332321f9c0f6789c42055f3f90b",
"shape": "WITH scoped AS MATERIALIZED (select id,action,details::jsonb->>'record_id' AS record_id,details::jsonb->>'module_id' AS module_id from \"identity_audit\" where (\"tenant_id\" = ? and \"company_id\" = ?) and \"action\" in (?, ?, ?) and details::jsonb->>'area' = ? and details::jsonb->>'record_id' in (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)),\n latest AS (SELECT DISTINCT ON (record_id,module_id) record_id,module_id,action FROM scoped\n WHERE action <> 'module.record.reviewed' ORDER BY record_id,module_id,id DESC),\n revisions AS (SELECT record_id,max(id) AS revision FROM scoped GROUP BY record_id)\n SELECT r.record_id,r.revision,coalesce(jsonb_agg(l.module_id ORDER BY l.module_id)\n FILTER (WHERE l.action='module.record.associated'),'[]'::jsonb) AS modules\n FROM revisions r LEFT JOIN latest l ON l.record_id=r.record_id GROUP BY r.record_id,r.revision",
"execution_ms": 77.761,
"nodes": [
{
"Node Type": "Aggregate",
"Actual Rows": 0,
"Actual Loops": 1,
"Shared Hit Blocks": 7320,
"Shared Read Blocks": 0,
"Temp Read Blocks": 0,
"Temp Written Blocks": 0
},
{
"Node Type": "Gather",
"Actual Rows": 0,
"Actual Loops": 1,
"Shared Hit Blocks": 7320,
"Shared Read Blocks": 0,
"Temp Read Blocks": 0,
"Temp Written Blocks": 0
},
{
"Node Type": "Seq Scan",
"Relation Name": "identity_audit",
"Actual Rows": 0,
"Actual Loops": 3,
"Rows Removed by Filter": 75556,
"Shared Hit Blocks": 7320,
"Shared Read Blocks": 0,
"Temp Read Blocks": 0,
"Temp Written Blocks": 0
},
{
"Node Type": "Sort",
"Actual Rows": 0,
"Actual Loops": 1,
"Shared Hit Blocks": 7320,
"Shared Read Blocks": 0,
"Temp Read Blocks": 0,
"Temp Written Blocks": 0
},
{
"Node Type": "Hash Join",
"Actual Rows": 0,
"Actual Loops": 1,
"Shared Hit Blocks": 7320,
"Shared Read Blocks": 0,
"Temp Read Blocks": 0,
"Temp Written Blocks": 0
},
{
"Node Type": "Unique",
"Actual Rows": 0,
"Actual Loops": 0,
"Shared Hit Blocks": 0,
"Shared Read Blocks": 0,
"Temp Read Blocks": 0,
"Temp Written Blocks": 0
},
{
"Node Type": "Sort",
"Actual Rows": 0,
"Actual Loops": 0,
"Shared Hit Blocks": 0,
"Shared Read Blocks": 0,
"Temp Read Blocks": 0,
"Temp Written Blocks": 0
},
{
"Node Type": "CTE Scan",
"Actual Rows": 0,
"Actual Loops": 0,
"Rows Removed by Filter": 0,
"Shared Hit Blocks": 0,
"Shared Read Blocks": 0,
"Temp Read Blocks": 0,
"Temp Written Blocks": 0
},
{
"Node Type": "Hash",
"Actual Rows": 0,
"Actual Loops": 1,
"Shared Hit Blocks": 7320,
"Shared Read Blocks": 0,
"Temp Read Blocks": 0,
"Temp Written Blocks": 0
},
{
"Node Type": "Aggregate",
"Actual Rows": 0,
"Actual Loops": 1,
"Shared Hit Blocks": 7320,
"Shared Read Blocks": 0,
"Temp Read Blocks": 0,
"Temp Written Blocks": 0
},
{
"Node Type": "CTE Scan",
"Actual Rows": 0,
"Actual Loops": 1,
"Shared Hit Blocks": 7320,
"Shared Read Blocks": 0,
"Temp Read Blocks": 0,
"Temp Written Blocks": 0
}
]
}
],
"indexed_batch": [
{
"signature": "50ff98a3116b073b1b26095ecaf597708917b73ca926112c977ec7507813bf3a",
"shape": "WITH scoped AS MATERIALIZED (select id,action,details::jsonb->>'record_id' AS record_id,details::jsonb->>'module_id' AS module_id from \"identity_audit\" where (\"tenant_id\" = ? and \"company_id\" = ?) and \"action\" in (?, ?, ?) and details::jsonb->>'area' = ? and details::jsonb->>'record_id' in (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)),\n latest AS (SELECT DISTINCT ON (record_id,module_id) record_id,module_id,action FROM scoped\n WHERE action <> 'module.record.reviewed' ORDER BY record_id,module_id,id DESC),\n revisions AS (SELECT record_id,max(id) AS revision FROM scoped GROUP BY record_id)\n SELECT r.record_id,r.revision,coalesce(jsonb_agg(l.module_id ORDER BY l.module_id)\n FILTER (WHERE l.action='module.record.associated'),'[]'::jsonb) AS modules\n FROM revisions r LEFT JOIN latest l ON l.record_id=r.record_id GROUP BY r.record_id,r.revision",
"execution_ms": 1.563,
"nodes": [
{
"Node Type": "Aggregate",
"Actual Rows": 67,
"Actual Loops": 1,
"Shared Hit Blocks": 576,
"Shared Read Blocks": 0,
"Temp Read Blocks": 0,
"Temp Written Blocks": 0
},
{
"Node Type": "Index Scan",
"Index Name": "sgf_qa_assoc_revision",
"Relation Name": "identity_audit",
"Actual Rows": 569,
"Actual Loops": 1,
"Shared Hit Blocks": 576,
"Shared Read Blocks": 0,
"Temp Read Blocks": 0,
"Temp Written Blocks": 0
},
{
"Node Type": "Sort",
"Actual Rows": 67,
"Actual Loops": 1,
"Shared Hit Blocks": 576,
"Shared Read Blocks": 0,
"Temp Read Blocks": 0,
"Temp Written Blocks": 0
},
{
"Node Type": "Hash Join",
"Actual Rows": 67,
"Actual Loops": 1,
"Shared Hit Blocks": 576,
"Shared Read Blocks": 0,
"Temp Read Blocks": 0,
"Temp Written Blocks": 0
},
{
"Node Type": "Unique",
"Actual Rows": 67,
"Actual Loops": 1,
"Shared Hit Blocks": 0,
"Shared Read Blocks": 0,
"Temp Read Blocks": 0,
"Temp Written Blocks": 0
},
{
"Node Type": "Sort",
"Actual Rows": 569,
"Actual Loops": 1,
"Shared Hit Blocks": 0,
"Shared Read Blocks": 0,
"Temp Read Blocks": 0,
"Temp Written Blocks": 0
},
{
"Node Type": "CTE Scan",
"Actual Rows": 569,
"Actual Loops": 1,
"Rows Removed by Filter": 0,
"Shared Hit Blocks": 0,
"Shared Read Blocks": 0,
"Temp Read Blocks": 0,
"Temp Written Blocks": 0
},
{
"Node Type": "Hash",
"Actual Rows": 67,
"Actual Loops": 1,
"Shared Hit Blocks": 576,
"Shared Read Blocks": 0,
"Temp Read Blocks": 0,
"Temp Written Blocks": 0
},
{
"Node Type": "Aggregate",
"Actual Rows": 67,
"Actual Loops": 1,
"Shared Hit Blocks": 576,
"Shared Read Blocks": 0,
"Temp Read Blocks": 0,
"Temp Written Blocks": 0
},
{
"Node Type": "CTE Scan",
"Actual Rows": 569,
"Actual Loops": 1,
"Shared Hit Blocks": 576,
"Shared Read Blocks": 0,
"Temp Read Blocks": 0,
"Temp Written Blocks": 0
}
]
},
{
"signature": "10d02426d5830d39b0c3d99210b0d23d0023c3ee581a7885c043b23039fd95e3",
"shape": "select count(*) as \"aggregate\" from \"a_clients\" where (\"tenant_id\" = ? and \"company_id\" = ? and \"unit_id\" is null) and NOT EXISTS (SELECT 1 FROM identity_audit me WHERE me.tenant_id=a_clients.tenant_id AND me.company_id=a_clients.company_id\n AND me.action IN ('module.record.associated','module.record.disassociated') AND me.details::jsonb->>'area'=? AND me.details::jsonb->>'record_id'=a_clients.id::text)",
"execution_ms": 104.319,
"nodes": [
{
"Node Type": "Aggregate",
"Actual Rows": 1,
"Actual Loops": 1,
"Shared Hit Blocks": 57204,
"Shared Read Blocks": 0,
"Temp Read Blocks": 672,
"Temp Written Blocks": 672
},
{
"Node Type": "Hash Join",
"Actual Rows": 3334,
"Actual Loops": 1,
"Shared Hit Blocks": 57204,
"Shared Read Blocks": 0,
"Temp Read Blocks": 672,
"Temp Written Blocks": 672
},
{
"Node Type": "Seq Scan",
"Relation Name": "a_clients",
"Actual Rows": 10000,
"Actual Loops": 1,
"Rows Removed by Filter": 104,
"Shared Hit Blocks": 135,
"Shared Read Blocks": 0,
"Temp Read Blocks": 0,
"Temp Written Blocks": 0
},
{
"Node Type": "Hash",
"Actual Rows": 56661,
"Actual Loops": 1,
"Shared Hit Blocks": 57069,
"Shared Read Blocks": 0,
"Temp Read Blocks": 0,
"Temp Written Blocks": 610
},
{
"Node Type": "Index Scan",
"Index Name": "sgf_qa_assoc_revision",
"Relation Name": "identity_audit",
"Actual Rows": 56661,
"Actual Loops": 1,
"Rows Removed by Filter": 0,
"Shared Hit Blocks": 57069,
"Shared Read Blocks": 0,
"Temp Read Blocks": 0,
"Temp Written Blocks": 0
}
]
},
{
"signature": "d829bbef004ef2eaed502b3df683fdde82e28f848a85c0e2202e743b86bc046d",
"shape": "select * from \"a_clients\" where (\"tenant_id\" = ? and \"company_id\" = ? and \"unit_id\" is null) and NOT EXISTS (SELECT 1 FROM identity_audit me WHERE me.tenant_id=a_clients.tenant_id AND me.company_id=a_clients.company_id\n AND me.action IN ('module.record.associated','module.record.disassociated') AND me.details::jsonb->>'area'=? AND me.details::jsonb->>'record_id'=a_clients.id::text) order by \"id\" asc limit 25 offset 0",
"execution_ms": 0.368,
"nodes": [
{
"Node Type": "Limit",
"Actual Rows": 25,
"Actual Loops": 1,
"Shared Hit Blocks": 273,
"Shared Read Blocks": 0,
"Temp Read Blocks": 0,
"Temp Written Blocks": 0
},
{
"Node Type": "Nested Loop",
"Actual Rows": 25,
"Actual Loops": 1,
"Shared Hit Blocks": 273,
"Shared Read Blocks": 0,
"Temp Read Blocks": 0,
"Temp Written Blocks": 0
},
{
"Node Type": "Index Scan",
"Index Name": "a_clients_pkey",
"Relation Name": "a_clients",
"Actual Rows": 73,
"Actual Loops": 1,
"Rows Removed by Filter": 4,
"Shared Hit Blocks": 6,
"Shared Read Blocks": 0,
"Temp Read Blocks": 0,
"Temp Written Blocks": 0
},
{
"Node Type": "Index Scan",
"Index Name": "sgf_qa_assoc_revision",
"Relation Name": "identity_audit",
"Actual Rows": 1,
"Actual Loops": 73,
"Rows Removed by Filter": 0,
"Shared Hit Blocks": 267,
"Shared Read Blocks": 0,
"Temp Read Blocks": 0,
"Temp Written Blocks": 0
}
]
},
{
"signature": "2cba1346e4495a631236b0eb5d232028dcb4c332321f9c0f6789c42055f3f90b",
"shape": "WITH scoped AS MATERIALIZED (select id,action,details::jsonb->>'record_id' AS record_id,details::jsonb->>'module_id' AS module_id from \"identity_audit\" where (\"tenant_id\" = ? and \"company_id\" = ?) and \"action\" in (?, ?, ?) and details::jsonb->>'area' = ? and details::jsonb->>'record_id' in (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)),\n latest AS (SELECT DISTINCT ON (record_id,module_id) record_id,module_id,action FROM scoped\n WHERE action <> 'module.record.reviewed' ORDER BY record_id,module_id,id DESC),\n revisions AS (SELECT record_id,max(id) AS revision FROM scoped GROUP BY record_id)\n SELECT r.record_id,r.revision,coalesce(jsonb_agg(l.module_id ORDER BY l.module_id)\n FILTER (WHERE l.action='module.record.associated'),'[]'::jsonb) AS modules\n FROM revisions r LEFT JOIN latest l ON l.record_id=r.record_id GROUP BY r.record_id,r.revision",
"execution_ms": 0.167,
"nodes": [
{
"Node Type": "Aggregate",
"Actual Rows": 0,
"Actual Loops": 1,
"Shared Hit Blocks": 12,
"Shared Read Blocks": 0,
"Temp Read Blocks": 0,
"Temp Written Blocks": 0
},
{
"Node Type": "Index Scan",
"Index Name": "sgf_qa_assoc_revision",
"Relation Name": "identity_audit",
"Actual Rows": 0,
"Actual Loops": 1,
"Shared Hit Blocks": 12,
"Shared Read Blocks": 0,
"Temp Read Blocks": 0,
"Temp Written Blocks": 0
},
{
"Node Type": "Sort",
"Actual Rows": 0,
"Actual Loops": 1,
"Shared Hit Blocks": 12,
"Shared Read Blocks": 0,
"Temp Read Blocks": 0,
"Temp Written Blocks": 0
},
{
"Node Type": "Hash Join",
"Actual Rows": 0,
"Actual Loops": 1,
"Shared Hit Blocks": 12,
"Shared Read Blocks": 0,
"Temp Read Blocks": 0,
"Temp Written Blocks": 0
},
{
"Node Type": "Unique",
"Actual Rows": 0,
"Actual Loops": 0,
"Shared Hit Blocks": 0,
"Shared Read Blocks": 0,
"Temp Read Blocks": 0,
"Temp Written Blocks": 0
},
{
"Node Type": "Sort",
"Actual Rows": 0,
"Actual Loops": 0,
"Shared Hit Blocks": 0,
"Shared Read Blocks": 0,
"Temp Read Blocks": 0,
"Temp Written Blocks": 0
},
{
"Node Type": "CTE Scan",
"Actual Rows": 0,
"Actual Loops": 0,
"Rows Removed by Filter": 0,
"Shared Hit Blocks": 0,
"Shared Read Blocks": 0,
"Temp Read Blocks": 0,
"Temp Written Blocks": 0
},
{
"Node Type": "Hash",
"Actual Rows": 0,
"Actual Loops": 1,
"Shared Hit Blocks": 12,
"Shared Read Blocks": 0,
"Temp Read Blocks": 0,
"Temp Written Blocks": 0
},
{
"Node Type": "Aggregate",
"Actual Rows": 0,
"Actual Loops": 1,
"Shared Hit Blocks": 12,
"Shared Read Blocks": 0,
"Temp Read Blocks": 0,
"Temp Written Blocks": 0
},
{
"Node Type": "CTE Scan",
"Actual Rows": 0,
"Actual Loops": 1,
"Shared Hit Blocks": 12,
"Shared Read Blocks": 0,
"Temp Read Blocks": 0,
"Temp Written Blocks": 0
}
]
}
]
},
"indexes_rolled_back": true
}
@@ -0,0 +1,92 @@
{
"date": "2026-11-02",
"baseline_checkpoint": "340f3bb5fa0e72d659abe43f3498b49e25ca3809",
"baseline_service_sha256": "44a2c75d6a2ecaddc151b3c92175324e15ca4e2664a87a4d50c093913adb4114",
"optimized_service_sha256": "6df1a85af8ea3112ff8e61741408158cd0444944cc3e0b407ad5bd4ad8043361",
"preview_and_confirmation_source_unchanged": true,
"tests": {
"affected": {
"assertions": 312,
"errors": 0,
"tests": 20,
"junit_sha256": "50a8e14b026ad20977ddc7257f48c2e74b2a7b50c4d355a6587d2d112201202b",
"failures": 0
},
"comparison": {
"assertions": 25521,
"errors": 0,
"tests": 1,
"junit_sha256": "c03ef9cd43057272696b459af4be553f9bf6d11ee40ed1db4601621e6f00d0e6",
"failures": 0
},
"plans": {
"assertions": 11,
"errors": 0,
"tests": 1,
"junit_sha256": "0726779185752aa0729a3d9a7e23ea7a4fb63c65ae7bed4ba861a3825497b73c",
"failures": 0
},
"access_parity": {
"assertions": 238,
"errors": 0,
"tests": 1,
"junit_sha256": "bd8564781ded7fdb4154245d4bb70a55a441eaa9ffdf62acf9e2ae06b988bd4c",
"failures": 0
}
},
"experiment": {
"repetitions": 3,
"records_in_each_area": true,
"pre_sample_garbage_collection": true,
"limited_indexed_attempts": 0,
"statement_budget_ms": 3000,
"limited_baseline_attempts": 13,
"successful_measured_requests": 258,
"limited_batch_attempts": 0,
"page_sizes": [
25,
100
],
"variants": [
"baseline",
"batch",
"indexed_batch"
],
"budget_ms": 15000,
"no_failed_sql_statements": true,
"timing_is_warm_in_process_http": true,
"scales": [
1000,
5000,
10000
],
"all_complete_responses_byte_identical": true,
"capacity_approved": false,
"cases_per_variant": 33
},
"preservation": {
"new_checkpoint": false,
"real_or_demo_database_connected": false,
"blocked_cache_untouched": true,
"synthetic_indexes_rolled_back_in_all_scales": true,
"new_public_rights": false,
"publication": false,
"committed_test_records_and_index_catalog_preserved": true,
"purchasing_activation": false,
"protected_six_records_untouched": true
},
"artifacts": {
"comparison_sha256": "2f24696cd4282856151c044de4830f77d12ae618430461b2202360a30215580a",
"plans": "module-association-optimization-plans-20261102.json",
"access": "module-association-optimization-access-20261102.json",
"comparison": "docs/proofs/module-association-optimization-comparison-20261102.json"
},
"limitations": [
"Same fixture A/B/C per scale; A/B alternate order; C follows with warm buffers and tested indexes",
"Scales run serially in the same database with rollback/ANALYZE; physical layout and cache may vary; no cold-start or pure cardinality curve claim",
"Incremental PHP memory is instrumented request peak minus baseline; process memory includes fixtures and kernel",
"One line per draft; maximum document fan-out and long/multi-module historical distributions not load-tested",
"No concurrent-user capacity, p95, throughput, write-cost or index deployment/recovery validation",
"Visual review remains separate"
]
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,73 @@
{
"date": "2026-11-02",
"tests": {
"affected": {
"assertions": 322,
"errors": 0,
"tests": 21,
"junit_sha256": "389a48ec91396c1af7ac2b05a8c6c359891a99d8ad51c4c1b88ed4df3662b14e",
"failures": 0
},
"fanout": {
"assertions": 25499,
"errors": 0,
"tests": 1,
"junit_sha256": "c768c145739a2d580cf3d9d4b408138c0015aec18bba5f0dbacb942df9f0fa39",
"failures": 0
}
},
"source": {
"pre_projection_sha256": "6df1a85af8ea3112ff8e61741408158cd0444944cc3e0b407ad5bd4ad8043361",
"final_sha256": "b901bccc73a59e80d98d32a56532e9300a55ba9a216e5ac5a0ce84d78f976397",
"baseline_recovered_from_measured_pre_projection_code": true,
"preview_and_confirmation_unchanged_from_340f3bb": true
},
"experiment": {
"all_complete_responses_identical": true,
"records_per_area": 10000,
"limited_attempts": 0,
"lines_per_draft": 100,
"description_bytes": [
128,
1000
],
"scenarios": 44,
"complete_scenarios": 44,
"memory_budget_diagnostic_bytes": 201326592,
"capacity_validated": false,
"complete_measured_requests": 132,
"page_sizes": [
25,
100
],
"variants": [
"pre_projection",
"none",
"revision_only",
"pair"
],
"php_memory_limit": "512M"
},
"preservation": {
"protected_six_records_untouched": true,
"no_destination_connection": true,
"no_public_rights_granted": true,
"original_test_rows_and_index_catalog_preserved": true,
"blocked_cache_untouched": true,
"no_purchasing_activation": true,
"no_checkpoint": true,
"no_publication": true
},
"artifacts": {
"measurement": "docs/proofs/module-association-projection-fanout-20261102.json",
"sha256": "e0353b7925a997a8a067a996d20bf462cd89c75b4eb3e302629015297a356f2d"
},
"limits": [
"Sequential phases and three warm in-process samples; not concurrent-user capacity or cold-start latency",
"Descriptions are repetitive synthetic text of 128/1000 bytes; not every document payload or full 2000-character text limit",
"Fixed phase order and shared cluster can influence latency; memory and response equality are the primary projection comparison",
"EXPLAIN without ANALYZE records planned index selection, not proof of cost under every production history",
"Index creation/size is measured only in transactionally disposable synthetic data; write costs and production rollout/recovery not validated",
"Visual review remains pending"
]
}
@@ -0,0 +1,120 @@
{
"date": "2026-11-02",
"run_tag": "d9db8f8ac6c0",
"identity": {
"database": "sgf_tempo_test",
"role": "sgf_test_runner",
"port": 55439,
"cluster": "sgf_modular_regression_2576427d1939"
},
"source_sha256": "b901bccc73a59e80d98d32a56532e9300a55ba9a216e5ac5a0ce84d78f976397",
"fixture_policy": "Four new QA-only clients committed for worker visibility; fixture and synthetic results retained in regression DB with private manifest.",
"cases": [
{
"case": "rollback_then_complete",
"release": "rollback",
"wait": {
"actual_wait_observed": true,
"blocking_parent_verified": true,
"statement_table": "companies",
"statement_for_update": true,
"wait_event_type": "Lock",
"wait_event": "transactionid",
"ungranted_locks": [
{
"locktype": "transactionid",
"mode": "ShareLock"
}
]
},
"second_status": "completed",
"second_http_status": 200,
"second_replayed": false,
"elapsed_ms": 352.387,
"record_version_after": 1,
"decision_events_after_retry": 1,
"first_event_persisted": false,
"duplicate_decision": false
},
{
"case": "commit_then_stale_revision",
"release": "commit",
"wait": {
"actual_wait_observed": true,
"blocking_parent_verified": true,
"statement_table": "companies",
"statement_for_update": true,
"wait_event_type": "Lock",
"wait_event": "transactionid",
"ungranted_locks": [
{
"locktype": "transactionid",
"mode": "ShareLock"
}
]
},
"second_status": "refused",
"second_http_status": 409,
"second_replayed": null,
"elapsed_ms": 338.389,
"record_version_after": 1,
"decision_events_after_retry": 1,
"first_event_persisted": true,
"duplicate_decision": false
},
{
"case": "commit_then_same_token",
"release": "commit",
"wait": {
"actual_wait_observed": true,
"blocking_parent_verified": true,
"statement_table": "companies",
"statement_for_update": true,
"wait_event_type": "Lock",
"wait_event": "transactionid",
"ungranted_locks": [
{
"locktype": "transactionid",
"mode": "ShareLock"
}
]
},
"second_status": "completed",
"second_http_status": 200,
"second_replayed": true,
"elapsed_ms": 333.37,
"record_version_after": 1,
"decision_events_after_retry": 1,
"first_event_persisted": true,
"duplicate_decision": false
},
{
"case": "commit_record_change_then_stale_version",
"release": "commit",
"wait": {
"actual_wait_observed": true,
"blocking_parent_verified": true,
"statement_table": "companies",
"statement_for_update": true,
"wait_event_type": "Lock",
"wait_event": "transactionid",
"ungranted_locks": [
{
"locktype": "transactionid",
"mode": "ShareLock"
}
]
},
"second_status": "refused",
"second_http_status": 409,
"second_replayed": null,
"elapsed_ms": 335.546,
"record_version_after": 2,
"decision_events_after_retry": 0,
"first_event_persisted": null,
"duplicate_decision": false
}
],
"completed": true,
"previous_qa_rows_and_index_catalog_preserved": true
}
@@ -0,0 +1,162 @@
{
"date": "2026-11-02",
"source_sha256": "b901bccc73a59e80d98d32a56532e9300a55ba9a216e5ac5a0ce84d78f976397",
"test": {
"tests": 1,
"assertions": 79,
"failures": 0,
"errors": 0,
"junit_sha256": "b2fcb62f49a1f13e0b14882a8d68c45cf2c634d9f7f7094083e917d7175f9d3a"
},
"cases": [
{
"case": "rollback_then_complete",
"release": "rollback",
"wait": {
"actual_wait_observed": true,
"blocking_parent_verified": true,
"statement_table": "companies",
"statement_for_update": true,
"wait_event_type": "Lock",
"wait_event": "transactionid",
"ungranted_locks": [
{
"locktype": "transactionid",
"mode": "ShareLock"
}
]
},
"second_status": "completed",
"second_http_status": 200,
"second_replayed": false,
"elapsed_ms": 352.387,
"record_version_after": 1,
"decision_events_after_retry": 1,
"first_event_persisted": false,
"duplicate_decision": false
},
{
"case": "commit_then_stale_revision",
"release": "commit",
"wait": {
"actual_wait_observed": true,
"blocking_parent_verified": true,
"statement_table": "companies",
"statement_for_update": true,
"wait_event_type": "Lock",
"wait_event": "transactionid",
"ungranted_locks": [
{
"locktype": "transactionid",
"mode": "ShareLock"
}
]
},
"second_status": "refused",
"second_http_status": 409,
"second_replayed": null,
"elapsed_ms": 338.389,
"record_version_after": 1,
"decision_events_after_retry": 1,
"first_event_persisted": true,
"duplicate_decision": false
},
{
"case": "commit_then_same_token",
"release": "commit",
"wait": {
"actual_wait_observed": true,
"blocking_parent_verified": true,
"statement_table": "companies",
"statement_for_update": true,
"wait_event_type": "Lock",
"wait_event": "transactionid",
"ungranted_locks": [
{
"locktype": "transactionid",
"mode": "ShareLock"
}
]
},
"second_status": "completed",
"second_http_status": 200,
"second_replayed": true,
"elapsed_ms": 333.37,
"record_version_after": 1,
"decision_events_after_retry": 1,
"first_event_persisted": true,
"duplicate_decision": false
},
{
"case": "commit_record_change_then_stale_version",
"release": "commit",
"wait": {
"actual_wait_observed": true,
"blocking_parent_verified": true,
"statement_table": "companies",
"statement_for_update": true,
"wait_event_type": "Lock",
"wait_event": "transactionid",
"ungranted_locks": [
{
"locktype": "transactionid",
"mode": "ShareLock"
}
]
},
"second_status": "refused",
"second_http_status": 409,
"second_replayed": null,
"elapsed_ms": 335.546,
"record_version_after": 2,
"decision_events_after_retry": 0,
"first_event_persisted": null,
"duplicate_decision": false
}
],
"preservation": {
"previous_qa_rows_and_index_catalog_preserved": true,
"protected_six_records_untouched": true,
"blocked_cache_untouched": true,
"destination_connected": false,
"public_rights_changed": false,
"indexes_created": false,
"publication": false,
"purchasing_activation": false,
"new_qa_fixture_retained": true,
"private_manifest_retained": true,
"functional_code_changed_in_this_followup": false
},
"proof": {
"path": "docs/proofs/module-association-release-20261102.json",
"sha256": "a4017200b2ce7d60efcc3590780019309850f3c864f90ba0b3c786382fae4f28"
},
"reused_proofs": [
{
"path": "docs/proofs/module-association-optimization-comparison-20261102.json",
"sha256": "2f24696cd4282856151c044de4830f77d12ae618430461b2202360a30215580a"
},
{
"path": "docs/proofs/module-association-optimization-summary-20261102.json",
"sha256": "6371512a070c3ae71872eeb76fae6f04d7a1aeeffc97510a3ea8e5e263396591"
},
{
"path": "docs/proofs/module-association-projection-fanout-20261102.json",
"sha256": "e0353b7925a997a8a067a996d20bf462cd89c75b4eb3e302629015297a356f2d"
},
{
"path": "docs/proofs/module-association-projection-summary-20261102.json",
"sha256": "171309fd4ca204e6e485e1790b1892d63e5f0ad13b494bd6d09434c5c9e8a193"
},
{
"path": "docs/proofs/module-association-concurrency-20261102.json",
"sha256": "bd75881c7c60cf5c2acf4fb256d83e090b07f112becbf30c8620cbb81432546a"
},
{
"path": "docs/proofs/module-association-concurrency-summary-20261102.json",
"sha256": "bb12a5fd566d8c606a7a0e082256ad82a4b399929755c60f8be69bf1bcd6b239"
}
],
"deployment_capacity_validated": false,
"visual_review_pending": true
}
@@ -0,0 +1,58 @@
{
"captured_at": "2026-11-02T08:55:28+00:00",
"target": "demo",
"identity": {
"database": "sgf_modules_dev_2576427d1939",
"role": "sgf_modules_qa_2576427d1939",
"port": 55439,
"read_only": "on"
},
"method": "Repeatable-read read-only transaction; latest explicit event per module; no business names or document contents exported.",
"classification_limit": "Never associated is a current state, not evidence of age or an inferred destination. Removed links require separate review.",
"areas": {
"clients": {
"scopes": [
{
"tenant_id": 1,
"company_id": 1,
"unit_id": null,
"total": 1,
"associated": 0,
"never_associated": 1,
"all_links_removed": 0
}
],
"pending_total": 1,
"pending_sample": [
{
"id": 1,
"tenant_id": 1,
"company_id": 1,
"unit_id": null,
"version": 1,
"reason": "never_associated"
}
],
"sample_truncated": false
},
"services": {
"scopes": [],
"pending_total": 0,
"pending_sample": [],
"sample_truncated": false
},
"service_drafts": {
"scopes": [],
"pending_total": 0,
"pending_sample": [],
"sample_truncated": false
},
"billing_drafts": {
"scopes": [],
"pending_total": 0,
"pending_sample": [],
"sample_truncated": false
}
},
"writes_performed": false
}
@@ -0,0 +1,137 @@
{
"captured_at": "2026-11-02T08:55:29+00:00",
"target": "installed",
"identity": {
"database": "sgf_tempo_dev",
"role": "sgf_dev_app",
"port": 55432,
"read_only": "on"
},
"method": "Repeatable-read read-only transaction; latest explicit event per module; no business names or document contents exported.",
"classification_limit": "Never associated is a current state, not evidence of age or an inferred destination. Removed links require separate review.",
"areas": {
"clients": {
"scopes": [
{
"tenant_id": 1,
"company_id": 1,
"unit_id": null,
"total": 1,
"associated": 0,
"never_associated": 1,
"all_links_removed": 0
}
],
"pending_total": 1,
"pending_sample": [
{
"id": 1,
"tenant_id": 1,
"company_id": 1,
"unit_id": null,
"version": 1,
"reason": "never_associated"
}
],
"sample_truncated": false
},
"services": {
"scopes": [
{
"tenant_id": 1,
"company_id": 1,
"unit_id": null,
"total": 2,
"associated": 0,
"never_associated": 2,
"all_links_removed": 0
}
],
"pending_total": 2,
"pending_sample": [
{
"id": 1,
"tenant_id": 1,
"company_id": 1,
"unit_id": null,
"version": 1,
"reason": "never_associated"
},
{
"id": 2,
"tenant_id": 1,
"company_id": 1,
"unit_id": null,
"version": 1,
"reason": "never_associated"
}
],
"sample_truncated": false
},
"service_drafts": {
"scopes": [
{
"tenant_id": 1,
"company_id": 1,
"unit_id": 1,
"total": 1,
"associated": 0,
"never_associated": 1,
"all_links_removed": 0
}
],
"pending_total": 1,
"pending_sample": [
{
"id": 1,
"tenant_id": 1,
"company_id": 1,
"unit_id": 1,
"version": 1,
"reason": "never_associated",
"references": {
"client_id": 1,
"service_ids": [
2
]
}
}
],
"sample_truncated": false
},
"billing_drafts": {
"scopes": [
{
"tenant_id": 1,
"company_id": 1,
"unit_id": 1,
"total": 1,
"associated": 0,
"never_associated": 1,
"all_links_removed": 0
}
],
"pending_total": 1,
"pending_sample": [
{
"id": 1,
"tenant_id": 1,
"company_id": 1,
"unit_id": 1,
"version": 1,
"reason": "never_associated",
"references": {
"client_id": 1,
"service_ids": [
2
],
"source_id": 1,
"source_version": 1
}
}
],
"sample_truncated": false
}
},
"writes_performed": false
}
@@ -0,0 +1,300 @@
{
"id": "SGF-MODULE-FLOW-PREPARATION-v1",
"date": "2026-11-02",
"kind": "static_preparation_inventory",
"plan_sha256": "5843f9d7ee4dcabbf1ba078744257dbe32fe3476d6d4641a2614aa90b50bec61",
"sources": [
{
"id": "requisitions_delivery",
"repository": "sgf",
"path": "docs/SGF_REQUISITIONS_8039_DELIVERY.md",
"sha256": "9c0bc172b91314c54e67ac1f547ce64cf2ce97d2df285172ad5d99eee554b167",
"meaning": "source_present_only_not_operational_proof"
},
{
"id": "receipt_workflow",
"repository": "compras",
"path": "app/Services/ReceiptWorkflow.php",
"sha256": "95d71faa860547c3838a72f8aeaf75cc73bf298eb3e61acadcd3f3fc732f8e79",
"meaning": "source_present_only_not_operational_proof"
},
{
"id": "stock_workflow",
"repository": "compras",
"path": "app/Services/StockWorkflow.php",
"sha256": "773d9434095c8e98aeaeb0279f62e7a53a4e06f9aab61313194573d20ec3ec5a",
"meaning": "source_present_only_not_operational_proof"
},
{
"id": "stock_controller",
"repository": "compras",
"path": "app/Http/Controllers/StockController.php",
"sha256": "79aa0f96da7b8290b23489bdaa5c45a4d9f122483dbc0b4132793f76e4f97d0b",
"meaning": "source_present_only_not_operational_proof"
},
{
"id": "inventory_lots",
"repository": "compras",
"path": "app/Services/InventoryLots.php",
"sha256": "6b35ea424a0b424823d02486910e90304384254dc11c37b6f3545f92f5647b08",
"meaning": "source_present_only_not_operational_proof"
},
{
"id": "inventory_counts",
"repository": "compras",
"path": "app/Services/InventoryCounts.php",
"sha256": "0c1b0d5e795a15b4d762c47fcdbeb19f225aa933b4507938f310ff25026afa11",
"meaning": "source_present_only_not_operational_proof"
},
{
"id": "inventory_dispositions",
"repository": "compras",
"path": "app/Services/InventoryDispositions.php",
"sha256": "1cf64babc5659a3c056600a2e8abcc7b88d11e37097ab3ed6e339313c392749f",
"meaning": "source_present_only_not_operational_proof"
},
{
"id": "inventory_reversals",
"repository": "compras",
"path": "app/Services/InventoryReversals.php",
"sha256": "aa17b3f30f65a855173dffef0f4659b7716d54d9cd622feb5e3cc44208ceebee",
"meaning": "source_present_only_not_operational_proof"
},
{
"id": "warehouse_reservations",
"repository": "compras",
"path": "app/Services/WarehouseReservations.php",
"sha256": "3120eaf6d9c8cedf3c991edcb41133f5107ca62736cea7e082ae4773755ffb54",
"meaning": "source_present_only_not_operational_proof"
},
{
"id": "stock_menu",
"repository": "sgf",
"path": "resources/js/stock-menu.js",
"sha256": "776360166b0fdacad343853eb335044306f078acb8da1439715010b4713dc4ff",
"meaning": "source_present_only_not_operational_proof"
},
{
"id": "invoice_workflow",
"repository": "compras",
"path": "app/Services/InvoiceWorkflow.php",
"sha256": "d25604134529a5217438385ff4ff70779b9962dbf3ca65929fe4e516153e6e30",
"meaning": "source_present_only_not_operational_proof"
},
{
"id": "supplier_adapter",
"repository": "sgf",
"path": "app/Modules/Purchasing/SupplierPayables.php",
"sha256": "120513ffc2588f9897c574dcfdaba68966315f207b3cf887b1d6e080ecc11a6a",
"meaning": "source_present_only_not_operational_proof"
},
{
"id": "payables",
"repository": "sgf",
"path": "packages/payables/src/Payables.php",
"sha256": "dafc76371767b0a9794f0822553e60392a8aa2c270dea8d78ff701a56f5f5bc9",
"meaning": "source_present_only_not_operational_proof"
},
{
"id": "settlements",
"repository": "sgf",
"path": "packages/payables/src/SupplierSettlements.php",
"sha256": "4a719ae1456df974877e2555dd6d559f26ebc40b90ae3ff7e11874cfbf2f106b",
"meaning": "source_present_only_not_operational_proof"
},
{
"id": "settlement_delivery",
"repository": "sgf",
"path": "docs/SUPPLIER_SETTLEMENT_DELIVERY.md",
"sha256": "46d9836e70b17a78acb2230f76122de38096384e55b4b2f5298aa9c73ab1fd20",
"meaning": "source_present_only_not_operational_proof"
},
{
"id": "workshop_workflow",
"repository": "sgf",
"path": "app/Modules/Workshop/WorkshopWorkflow.php",
"sha256": "a09d7c14c7101c36a2539f346494584340493a56ca951c7b1e66418f43d80adb",
"meaning": "source_present_only_not_operational_proof"
},
{
"id": "direct_costs",
"repository": "sgf",
"path": "app/Modules/Workshop/DirectCosts.php",
"sha256": "b6c10cb71c30361013f33a11ee8678bfa183737ed143186747793c95cd5eef95",
"meaning": "source_present_only_not_operational_proof"
},
{
"id": "industrial_costs",
"repository": "sgf",
"path": "app/Modules/Industry/IndustrialCosts.php",
"sha256": "2c63f6dcd23f751fb7dce363c415fcc2a44e7dfcb54203dc0e4af55c3e9dbf07",
"meaning": "source_present_only_not_operational_proof"
},
{
"id": "workshop_billing",
"repository": "sgf",
"path": "app/Modules/Workshop/WorkshopBilling.php",
"sha256": "039fdfdab77a8856b070249e028894a740222199969cabd614bfaab0c9e5a2d2",
"meaning": "source_present_only_not_operational_proof"
},
{
"id": "service_invoicing",
"repository": "sgf",
"path": "app/Modules/Services/ServiceInvoicing.php",
"sha256": "b5ac9898f2089fad7799b9e62e5ce5db6df7fd64643e8e7e3b52c6a0e2d142a8",
"meaning": "source_present_only_not_operational_proof"
},
{
"id": "service_receivables",
"repository": "sgf",
"path": "app/Modules/Services/ServiceReceivables.php",
"sha256": "fb4aab2d47c4e9e5fb1115a44e796669402b891b56ff3623db725b21b4bcf714",
"meaning": "source_present_only_not_operational_proof"
},
{
"id": "catalogue_accounting",
"repository": "sgf",
"path": "app/Modules/Services/CatalogueAccounting.php",
"sha256": "15e72188334a0c6e9b65050e9609ac1c50a924899a753d47557e3375017e5d1c",
"meaning": "source_present_only_not_operational_proof"
},
{
"id": "accounting_menu",
"repository": "sgf",
"path": "docs/ACCOUNTING_MENU_DELIVERY.md",
"sha256": "566ce398e2a8d92dced2547d3587647549170c4ddb1c056fda2249e59f572c34",
"meaning": "source_present_only_not_operational_proof"
}
],
"stages": [
{
"id": "requisition_order",
"owner": "purchasing",
"effect": "approved_procurement_origin",
"state": "partial_synthetic",
"operational_integration_validated": false,
"gap": "Only basic requisitions demonstrated in 8039; full procurement composition not transferred."
},
{
"id": "accepted_receipt",
"owner": "purchasing",
"effect": "accepted_physical_receipt",
"state": "source_not_integrated",
"operational_integration_validated": false,
"gap": "No common SGF receipt/stock adapter demonstrated."
},
{
"id": "physical_stock",
"owner": "stock",
"effect": "physical_movement_once",
"state": "source_not_integrated",
"operational_integration_validated": false,
"gap": "Common scoped reader, authoritative writer and SGF warehouse mapping pending."
},
{
"id": "supplier_invoice",
"owner": "purchasing",
"effect": "verified_supplier_document",
"state": "partial_synthetic",
"operational_integration_validated": false,
"gap": "Does not assume every purchase is stock; existing eligibility/partial receipt rules must be preserved."
},
{
"id": "supplier_payable",
"owner": "finance",
"effect": "supplier_obligation_once",
"state": "partial_synthetic",
"operational_integration_validated": false,
"gap": "Synthetic core exists; common operational composition and historical source mapping remain delimited."
},
{
"id": "supplier_settlement",
"owner": "finance",
"effect": "confirmed_allocation_once",
"state": "partial_synthetic",
"operational_integration_validated": false,
"gap": "Synthetic payments/allocations exist; no bank execution or complete bank reconciliation delivered."
},
{
"id": "workshop_execution",
"owner": "workshop",
"effect": "verified_work_record",
"state": "partial_synthetic",
"operational_integration_validated": false,
"gap": "Verified observations exist; no automatic physical stock movement."
},
{
"id": "workshop_stock_consumption",
"owner": "stock",
"effect": "company_material_consumption_once",
"state": "planned",
"operational_integration_validated": false,
"gap": "Linking observed material to a physical movement is not implemented; do not replay old observations."
},
{
"id": "verified_cost",
"owner": "finance",
"effect": "validated_cost_version",
"state": "partial_synthetic",
"operational_integration_validated": false,
"gap": "Current costs are synthetic; physical movement linkage is future and absence of rate stays visible."
},
{
"id": "sales_draft",
"owner": "commercial",
"effect": "commercial_draft_from_unique_origins",
"state": "partial_synthetic",
"operational_integration_validated": false,
"gap": "Draft integration exists; cost is not sale price and draft does not decrement stock."
},
{
"id": "sales_invoice",
"owner": "commercial",
"effect": "issued_sales_document",
"state": "partial_synthetic",
"operational_integration_validated": false,
"gap": "Test issuance exists; real fiscal issuance remains guarded. Direct service origins remain valid."
},
{
"id": "customer_receivable",
"owner": "finance",
"effect": "customer_receipt_allocation_once",
"state": "partial_synthetic",
"operational_integration_validated": false,
"gap": "Synthetic receipts exist; fiscal receipt/bank reconciliation not presumed."
},
{
"id": "general_ledger",
"owner": "accounting",
"effect": "balanced_journal_once",
"state": "planned",
"operational_integration_validated": false,
"gap": "Classification/menu exist; journal, ledger, accounting periods, close and reporting engine absent."
}
],
"checks": {
"source_paths_and_hashes": true,
"single_owner_per_stage": true,
"mandatory_dependency_graph_acyclic": true,
"planned_consumers_explicit": true
},
"limitations": [
"Source existence is not execution, parity, acceptance or deployment evidence.",
"Dependencies represent the selected synthetic path, not universal product eligibility rules.",
"No stage transition engine, inventory adapter or journal engine implemented by this inventory."
],
"preservation": {
"database_connections": 0,
"source_execution": false,
"application_routes_changed": false,
"rights_changed": false,
"protected_six_records_untouched": true,
"blocked_cache_untouched": true,
"demos_changed": false,
"purchasing_activated": false,
"publication": false,
"checkpoint": false
},
"visual_review_pending": true,
"deployment_capacity_validated": false
}
@@ -0,0 +1,11 @@
{
"kind": "server_render_of_actual_native_stock_history_props",
"page_sha256": "fafd870e129cb169216bd2a7d13a547adaab410d24195f950327eb14af57e10f",
"component_sha256": "3c6d68bac8db5c7e0ac7f518fd07e8b3a6a4f0f704ea7612e332b457ee9a0938",
"render_passed": true,
"return_human_label_visible": true,
"author_and_responsible_rendered": true,
"actual_http_props_used": true,
"visual_review": false,
"browser_interactions_tested": false
}
@@ -0,0 +1,18 @@
{
"kind": "isolated_changed_entry_browser_bundle_and_types",
"inputs_sha256": {
"resources/js/pages/stock/returns.tsx": "e9fc4183b07f7cbebce83f770dc2958536905b0b4c2796c8065031e35aa9b1e7",
"resources/js/pages/stock/request.tsx": "f59a72c78f8c94260c5b64cad0d26cca08c8379726ad61c9b869e0a667c00f60",
"resources/js/pages/stock/operations.tsx": "3c6d68bac8db5c7e0ac7f518fd07e8b3a6a4f0f704ea7612e332b457ee9a0938"
},
"entry_bundle_passed": true,
"type_check_exit": 0,
"type_output_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"explicit_source_selection": true,
"unused_declaration_required_in_source": true,
"independent_receiving_declaration_required_in_source": true,
"live_or_demo_build_touched": false,
"full_application_build": false,
"browser_interactions_tested": false,
"visual_review": false
}
@@ -0,0 +1,413 @@
{
"date": "2026-11-02",
"increment": "NATIVE-WAREHOUSE-UNUSED-RETURN-SIM-v1",
"status": "local_synthetic_implementation",
"proofs": [
{
"file": "private/stock-receipt-115c5b17e171/return-native-1793639486315-junit.xml",
"sha256": "54a1436b5e76096ea9184af600215d004b316108e9cb79cfe6c86c3c5211948a",
"tests": 18,
"assertions": 420,
"errors": 0,
"failures": 0
},
{
"file": "private/stock-receipt-115c5b17e171/return-native-1793640514403-junit.xml",
"sha256": "dcbbfa2303ed213d93eab8a6533e25e23751dcdfb1594bdb5c3835221ddb6237",
"tests": 1,
"assertions": 20,
"errors": 0,
"failures": 0
},
{
"file": "private/stock-receipt-cc99dcb17e19/return-reversals-junit.xml",
"sha256": "b38945a85e73e6d78f4770a58f4577b8511b7a15f3523b13e157638b4ecdd0f2",
"tests": 16,
"assertions": 81,
"errors": 0,
"failures": 0
},
{
"file": "stock-read-1793636847404.xml",
"sha256": "88604d1110b31bd0906d3a139a29a95a662341936044eb8fb0757e12e04ab900",
"tests": 1,
"assertions": 23,
"errors": 0,
"failures": 0
}
],
"totals": {
"distinct_tests": 36,
"assertions": 544
},
"selected_cases": [
{
"name": "test_native_receipt_issue_acknowledgement_and_return_same_book_once",
"assertions": 54,
"proof": "private/stock-receipt-115c5b17e171/return-native-1793639486315-junit.xml"
},
{
"name": "test_stale_capacity_idempotency_versions_rights_and_context_refuse_effect",
"assertions": 22,
"proof": "private/stock-receipt-115c5b17e171/return-native-1793639486315-junit.xml"
},
{
"name": "test_decision_failure_rolls_back_physical_movement_and_retry_recovers",
"assertions": 15,
"proof": "private/stock-receipt-115c5b17e171/return-native-1793639486315-junit.xml"
},
{
"name": "test_undeclared_fraction_and_foreign_delivery_are_refused",
"assertions": 13,
"proof": "private/stock-receipt-115c5b17e171/return-native-1793639486315-junit.xml"
},
{
"name": "test_source_options_and_page_reuse_request_and_acknowledged_line",
"assertions": 54,
"proof": "private/stock-receipt-115c5b17e171/return-native-1793639486315-junit.xml"
},
{
"name": "test_source_issue_with_return_cannot_be_reversed_as_a_whole",
"assertions": 12,
"proof": "private/stock-receipt-115c5b17e171/return-native-1793639486315-junit.xml"
},
{
"name": "test_concurrent_native_confirmation_waits_then_replays_one_movement",
"assertions": 21,
"proof": "private/stock-receipt-115c5b17e171/return-native-1793639486315-junit.xml"
},
{
"name": "test_competing_native_returns_cannot_exceed_the_original_delivery",
"assertions": 20,
"proof": "private/stock-receipt-115c5b17e171/return-native-1793639486315-junit.xml"
},
{
"name": "test_expired_and_maintenance_profiles_are_revalidated_at_confirmation",
"assertions": 14,
"proof": "private/stock-receipt-115c5b17e171/return-native-1793639486315-junit.xml"
},
{
"name": "test_configured_context_and_permissions_cannot_be_inherited_from_people_profile",
"assertions": 19,
"proof": "private/stock-receipt-115c5b17e171/return-native-1793639486315-junit.xml"
},
{
"name": "test_return_signals_existing_replenishment_only_once_and_inside_transaction",
"assertions": 18,
"proof": "private/stock-receipt-115c5b17e171/return-native-1793639486315-junit.xml"
},
{
"name": "test_catalogue_rename_requires_new_review_preserving_original_and_unit_change_refuses",
"assertions": 18,
"proof": "private/stock-receipt-115c5b17e171/return-native-1793639486315-junit.xml"
},
{
"name": "test_unavailable_private_package_returns_503_and_rolls_back_before_recovery",
"assertions": 17,
"proof": "private/stock-receipt-115c5b17e171/return-native-1793639486315-junit.xml"
},
{
"name": "test_http_busy_response_leaves_proposal_unconfirmed_then_manual_retry_succeeds",
"assertions": 21,
"proof": "private/stock-receipt-115c5b17e171/return-native-1793639486315-junit.xml"
},
{
"name": "test_withdrawal_and_independent_rejection_close_pending_without_stock_effect",
"assertions": 37,
"proof": "private/stock-receipt-115c5b17e171/return-native-1793639486315-junit.xml"
},
{
"name": "test_withdrawal_wins_before_confirmation_without_a_movement",
"assertions": 19,
"proof": "private/stock-receipt-115c5b17e171/return-native-1793639486315-junit.xml"
},
{
"name": "test_confirmation_wins_before_withdrawal_without_duplicate_terminal_state",
"assertions": 19,
"proof": "private/stock-receipt-115c5b17e171/return-native-1793639486315-junit.xml"
},
{
"name": "test_history_pages_and_batch_preparer_lookup_cover_the_full_pending_universe",
"assertions": 27,
"proof": "private/stock-receipt-115c5b17e171/return-native-1793639486315-junit.xml"
},
{
"name": "test_return_changes_physical_history_without_silently_changing_gross_issue_forecast",
"assertions": 20,
"proof": "private/stock-receipt-115c5b17e171/return-native-1793640514403-junit.xml"
},
{
"name": "full issue reversal preserves the original and is exactly once even on an execution retry",
"assertions": 5,
"proof": "private/stock-receipt-cc99dcb17e19/return-reversals-junit.xml"
},
{
"name": "a corrected issue no longer satisfies a reservation and the same need can use a new actual issue",
"assertions": 10,
"proof": "private/stock-receipt-cc99dcb17e19/return-reversals-junit.xml"
},
{
"name": "a reversal outside a closed history period invalidates its signature and corrects effective consumption",
"assertions": 3,
"proof": "private/stock-receipt-cc99dcb17e19/return-reversals-junit.xml"
},
{
"name": "receipt reversal restores authorised quantities without deleting acceptance and a new correction receipt is not a duplicate",
"assertions": 8,
"proof": "private/stock-receipt-cc99dcb17e19/return-reversals-junit.xml"
},
{
"name": "receipt line reversal removes the full documentary quantities but only the accepted physical entry",
"assertions": 3,
"proof": "private/stock-receipt-cc99dcb17e19/return-reversals-junit.xml"
},
{
"name": "tracked transfer reversal removes original destination lots and quarantines the restored source identity",
"assertions": 8,
"proof": "private/stock-receipt-cc99dcb17e19/return-reversals-junit.xml"
},
{
"name": "mixed lot adjustments can be reversed without turning corrections into consumption",
"assertions": 4,
"proof": "private/stock-receipt-cc99dcb17e19/return-reversals-junit.xml"
},
{
"name": "restoring an old untracked issue after cutover creates an unidentified held lot without fabricating receipt origin",
"assertions": 6,
"proof": "private/stock-receipt-cc99dcb17e19/return-reversals-junit.xml"
},
{
"name": "receipt reversal cannot silently associate an old entry with a baseline lot",
"assertions": 2,
"proof": "private/stock-receipt-cc99dcb17e19/return-reversals-junit.xml"
},
{
"name": "a supplier return reversal restores net receipt entitlement but cannot itself be reversed",
"assertions": 6,
"proof": "private/stock-receipt-cc99dcb17e19/return-reversals-junit.xml"
},
{
"name": "an insufficient original lot or warehouse blocks an approved reversal without compensating from another lot",
"assertions": 4,
"proof": "private/stock-receipt-cc99dcb17e19/return-reversals-junit.xml"
},
{
"name": "approval independence and source isolation apply even with accumulated roles",
"assertions": 2,
"proof": "private/stock-receipt-cc99dcb17e19/return-reversals-junit.xml"
},
{
"name": "a reviewer cannot execute their own decision and duplicate approved plans cannot reverse the original twice",
"assertions": 3,
"proof": "private/stock-receipt-cc99dcb17e19/return-reversals-junit.xml"
},
{
"name": "a final audit failure rolls back all reversal movements and leaves the original approval intact",
"assertions": 4,
"proof": "private/stock-receipt-cc99dcb17e19/return-reversals-junit.xml"
},
{
"name": "HTTP permissions and source views expose the correction without changing original documents",
"assertions": 8,
"proof": "private/stock-receipt-cc99dcb17e19/return-reversals-junit.xml"
},
{
"name": "voided receipt matching blocks new invoices while preserving invoice facts already registered",
"assertions": 5,
"proof": "private/stock-receipt-cc99dcb17e19/return-reversals-junit.xml"
},
{
"name": "test_native_return_book_is_observed_without_copy_or_write",
"assertions": 23,
"proof": "stock-read-1793636847404.xml"
}
],
"evidence_selection": "18 native cases, one new forecast-boundary case, 16 affected reversal cases, one SGF observer case. Valid overlapping earlier runs are not added. Observer binds an archived retained fixture; subsequent native tests used new isolated tenants.",
"scenario": {
"receipt_milli": "10000",
"acknowledged_delivery_milli": "5000",
"physical_after_delivery": "5000",
"declared_unused_return_milli": "3000",
"physical_after_return": "8000",
"movements": 3,
"one_shared_writer": true,
"native_standalone_requires_sgf": false,
"sgf_read_only_observes_same_movement": true
},
"controls": {
"individual_unused_declaration": true,
"independent_physical_receipt": true,
"original_source_snapshots_preserved": true,
"append_only_decisions": true,
"versions_context_permissions_revalidated": true,
"withdrawal_and_rejection_without_stock_effect": true,
"source_reversal_after_partial_return_refused": true,
"transaction_failure_recovery": true,
"package_failure_503_recovery": true,
"history_metadata_rendered": true,
"replenishment_signal_once_inside_transaction": true
},
"concurrency": {
"real_processes": 2,
"company_row_blocker_observed": true,
"after_release_same_proposal": "200 replay; one movement",
"competing_returns": "one confirmed; second 409 after release",
"withdraw_confirm": "one terminal state in both lock orders",
"http_lock_timeout": "423 warehouse_return_busy; no effects; explicit retry after release succeeds"
},
"history": {
"fixture_records": 51,
"page_size": 25,
"supply_record_selects_for_page": 3,
"pages_disjoint": true,
"state_filters_cover_latest_versions": true,
"not_a_load_capacity_benchmark": true
},
"forecast_boundary": {
"gross_issue_milli": 5000,
"returned_milli": 3000,
"physical_before_milli": 5000,
"physical_after_milli": 8000,
"historical_mean_unchanged": true,
"source_hash_changed": true,
"planning_convention_unchanged": true,
"net_consumption_forecast_implemented": false
},
"package": {
"manifest_sha256": "2850a4f5cb678acfe3a9dbc7a7d62eb233bc72722ad0de374681c2679c90557c",
"canonical_matches_native_artifact": true,
"writer_unchanged": true
},
"observer": {
"proof_sha256": "69377ad1852f8299e37fdefc595c224c85412b02363d4bfa9070aa9e3c5c63ea",
"fixture_archive_sha256": "a9a6f9f3360f9d01174bbafec05b6120fd11315d863c9e92d07861dd58e65acf",
"kind": "native_return_same_book_sgf_observer",
"physical_milli": "8000",
"native_movements": 3,
"same_return_movement": true,
"observed_return_movement_id": 29,
"native_fixture_sha256": "a9a6f9f3360f9d01174bbafec05b6120fd11315d863c9e92d07861dd58e65acf",
"source_write_refused": true,
"no_local_copy_or_second_effect": true,
"return_manifest_sha256": "2850a4f5cb678acfe3a9dbc7a7d62eb233bc72722ad0de374681c2679c90557c"
},
"postchecks": {
"native_retained_book": {
"cluster": "sgf_modular_regression_2576427d1939",
"database": "compras_receipts_test_115c5b17e171",
"role": "stock_receipt_read_115c5b17e171",
"read_only": "on",
"elevated": false,
"select_book": true,
"can_write_book": false,
"select_native_operations": false,
"movements": 3,
"physical_milli": "8000",
"same_return": true
},
"sgf": {
"qa_identity": {
"db": "sgf_tempo_test",
"role": "sgf_test_runner",
"port": 55439,
"cluster": "sgf_modular_regression_2576427d1939"
},
"temporary_grants_remaining": 0,
"constraint_sha256": "40046092cba51f1b46d26d5f0da8af47e8336e90a8d50b8de3a8c390758f1783",
"operational_workshop_stock_bindings": 0,
"read_only": true
}
},
"ui": {
"proof": "docs/proofs/native-return-ui-20261102.json",
"sha256": "61ad362980e92de76f64cd39bad2fbe0a78f950cffe0dc18a85af61a388cfb50",
"kind": "isolated_changed_entry_browser_bundle_and_types",
"inputs_sha256": {
"resources/js/pages/stock/returns.tsx": "e9fc4183b07f7cbebce83f770dc2958536905b0b4c2796c8065031e35aa9b1e7",
"resources/js/pages/stock/request.tsx": "f59a72c78f8c94260c5b64cad0d26cca08c8379726ad61c9b869e0a667c00f60",
"resources/js/pages/stock/operations.tsx": "3c6d68bac8db5c7e0ac7f518fd07e8b3a6a4f0f704ea7612e332b457ee9a0938"
},
"entry_bundle_passed": true,
"type_check_exit": 0,
"type_output_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"explicit_source_selection": true,
"unused_declaration_required_in_source": true,
"independent_receiving_declaration_required_in_source": true,
"live_or_demo_build_touched": false,
"full_application_build": false,
"browser_interactions_tested": false,
"visual_review": false
},
"history_render": {
"proof": "docs/proofs/native-return-history-render-20261102.json",
"sha256": "71b8a50c96abc17fba71fb010afbcace8309c4976efb036d35220898cb777520",
"kind": "server_render_of_actual_native_stock_history_props",
"page_sha256": "fafd870e129cb169216bd2a7d13a547adaab410d24195f950327eb14af57e10f",
"component_sha256": "3c6d68bac8db5c7e0ac7f518fd07e8b3a6a4f0f704ea7612e332b457ee9a0938",
"render_passed": true,
"return_human_label_visible": true,
"author_and_responsible_rendered": true,
"actual_http_props_used": true,
"visual_review": false,
"browser_interactions_tested": false
},
"qualified_private_build": {
"kind": "private_application_asset_build_with_qa_configuration",
"passed": true,
"app_path_private": true,
"manifest_sha256": "bda389a4cedc3ed5d2b4e02dda0487fa15e06924ef1ad5b85ca0981d71ec226e",
"return_page_in_manifest": true,
"configuration_difference": "Font downloading and optional React compiler omitted in QA; application entries, Inertia, React JSX, Tailwind and Wayfinder built. Does not validate the default optimized build.",
"native_public_build_touched": false,
"demo_assets_touched": false,
"visual_review": false
},
"php_analysis": {
"tool": "phpstan",
"result": "passed",
"errors": 0
},
"source_sha256": {
"../compras/app/Services/WarehouseReturns.php": "0e3ba1f1b9547a9fc21ad85191ff2378a2e5da7d95aaf0625c55d69a5d7bc0d3",
"../compras/app/Services/WarehouseReturnMovement.php": "0a4fae10c24319b6f5bd030e99fa4281e337aaae5777e8287e608752e51bb5a3",
"../compras/app/Http/Controllers/WarehouseReturnController.php": "0bad62cfee16367507d0cd8c2d2c9da3b4a320728e4f2d94db72f39df1d2807d",
"../compras/app/Services/InventoryReversals.php": "3af954cb2fa6ab950b80b9098c4bccfb8d099a247d13f4d64a8d0a76fec07295",
"../compras/app/Services/SupplyHistory.php": "abc2598f20ccd66b6e3218bc4f9a5f3eab074b4f022cf8566da6c36003f9c041",
"../compras/app/Services/OrganizationAccess.php": "2c7529a2118ab849fd3bc192045a460cca7787a06b84d481ba32e5a8f612a0a1",
"../compras/config/stock_returns.php": "b46680d504945879bedd2910d2a0dd0164d13d331a6e85772edcdd182fddbd04",
"../compras/routes/web.php": "9fbda27eb41da56c9b62a216c43bdcd99b66ffc230d9accd6866080f89130b54",
"../compras/tests/Feature/WarehouseReturnIntegrationTest.php": "e4240a156ddef6184ef6f6ed4c35341dd6184332ef32d4487423c05bfd8a5f80",
"../compras/tests/Support/warehouse-return-worker.php": "9f58ec6d45ec67c03ab2380e0f081a48eb0540d01603e68afa8608a90384a776",
"resources/js/StockReadWorkspace.jsx": "ab29ffa445cfd68f5a9a2542dd4c375bff38e9f9a28cbf1cc033c3ceb76ea7e4",
"tests/Feature/StockReadTest.php": "dbfaf026d912ff31ac73f8f84d3f318c67f24b5efbaaad85ccc4bca8bfdf5590"
},
"reused_proofs": {
"docs/proofs/workshop-material-cycle-20261102.json": "4d79e563401df1e20d793ca8af9a1da228a24c86d6c887323a9e57c3ce65cc9a",
"docs/proofs/stock-read-load-20261102.json": "4fc1d7d13d480a30966b259611de1066fc22ef31f7a0e782da4872211801c72e",
"docs/proofs/module-association-http-lock-summary-20261102.json": "67547007f8f9df853639751983c5a6fd0841044cb0e04a7628db04c4b67692c6"
},
"preservation": {
"six_pending_associations_untouched": true,
"blocked_cache_untouched": true,
"demos_and_real_data_untouched": true,
"no_real_rights_granted": true,
"native_synthetic_profiles_retained_in_separate_qa_database": true,
"sgf_temporary_rights_restored": true,
"regression_not_reset": true,
"existing_proofs_preserved": true,
"activation": false,
"publication": false,
"checkpoint": false
},
"limits": [
"Native unused quantity is an explicit recipient declaration; no SGF technical-consumption register is consulted by the standalone native flow.",
"Only internal warehouse deliveries; no lots, equipment/spare parts, reservation-bearing articles, quality or quarantine.",
"No consumed-material compensation or automatic reversal of confirmed returns.",
"Historical forecast preserves gross issue convention; net return forecasting is not implemented.",
"SGF observation is isolated QA evidence, not installation of a full operational composition.",
"No write-load capacity, visual review, browser interaction or deployment validation.",
"Qualified private asset build omits optional React compiler and font downloading; default optimized build is not validated."
],
"visual_review_pending": true,
"deployment_capacity_validated": false
}
@@ -0,0 +1,284 @@
{
"proposal_id": "SGF-IR-INSTALL-5FAE-20261102",
"date": "2026-11-02",
"state": "proposed_not_authorised",
"destination": {
"root": "C:/laragon/www/sgf-tempo",
"environment": "local",
"database": "sgf_tempo_dev",
"host": "127.0.0.1",
"port": 55432,
"application_role": "sgf_dev_app",
"migration_role": "sgf_dev_owner",
"postgres_admin_for_isolated_restore": "sgf_local_admin",
"expected_existing_tables": 87,
"backup_root": "C:/laragon/data/sgf-tempo/backups/SGF-IR-INSTALL-5FAE-20261102",
"restore_before": "sgf_restore_ir_5fae_pre",
"restore_after": "sgf_restore_ir_5fae_post",
"candidate_staging": "C:/laragon/data/sgf-tempo/install/SGF-IR-INSTALL-5FAE-20261102",
"expected_existing_grants": 89,
"expected_existing_memberships": 2
},
"candidate": {
"id": "OPERATIONAL-CANDIDATE-5fae7cf7f99c42ba",
"format": "tempo.operational-review.v1",
"manifest_sha256": "b1ec47f7a9ad87e0b232bac41e402d4a00ee5f03f00a79b93effc692ce8b39a2",
"archive": "C:/laragon/www/compras/storage/app/private/candidate-archives/OPERATIONAL-CANDIDATE-5fae7cf7f99c42ba.zip",
"archive_sha256": "d14a3261d5aaab80f96250af781c700ab53376021f4638e3aee43c15ff37ceed",
"support_files_verified": 36,
"package_pointer_before": "0.1.1",
"package_pointer_after": "0.1.1"
},
"read_only_plans": {
"code": {
"target_sha256": "bab719ee4e08555a8e1de694dd3a93df82680c7aba653613f0714dd76e4065d6",
"pointer_sha256": "81899e531e9eec449717e694d8bdc106a9e220a828f5491ce918c1d2dc612787",
"host_files": {
"app/Modules/Identity/Services/Permissions.php": "97a860b632de0cb5022b2d9153261ecfa2211c100961eb6b9e6a09d30f798e63",
"app/Modules/Identity/Services/IdentityWorkflow.php": "c4f4af9a7625778a408d881ba087502b116fa0ccb15f2f0311f5a0e8ad40ce73",
"app/Modules/Purchasing/BudgetAdapter.php": "e8f261e2e6535973c72266cf5f448e24794e5c896a9910ca85468001fbc37116",
"app/Providers/AppServiceProvider.php": "42705455c3f12233369275cbfd7d80781109135ca1ef2d3e3adc2fac8d675e8e",
"app/Shared/Context/ModuleNavigation.php": "f75f323940e25826792dc88848fd2b77eb3325634100a86b14c60c5d381917a3"
},
"manifest_sha256": "b1ec47f7a9ad87e0b232bac41e402d4a00ee5f03f00a79b93effc692ce8b39a2",
"previous": null,
"deployment_id": "b1ec47f7a9ad87e0b232bac4",
"writes": false
},
"schema": {
"target_sha256": "169e6e863f28b67740f07b6e7cbc664fbe585a7760a83dccebc8d482ad8ab792",
"manifest_sha256": "b1ec47f7a9ad87e0b232bac41e402d4a00ee5f03f00a79b93effc692ce8b39a2",
"schema_prepared": false,
"activated": false
}
},
"migration_sha256": "c9e9f0ab3a561578de18c17d149d414640a4e594ef918ff393aecd8eee16e775",
"navigation": {
"functional_commit": "2a4169162bb4621a42a2ea1df627d52f860e7176",
"documentary_acceptance_commit": "fcf0ada22701337acd4c84b404207b8400f490a2",
"files": {
"app/Shared/Context/ModuleNavigation.php": {
"working_sha256": "f75f323940e25826792dc88848fd2b77eb3325634100a86b14c60c5d381917a3",
"matches_functional_commit_normalized": true,
"overlay": {
"before_sha256": "f75f323940e25826792dc88848fd2b77eb3325634100a86b14c60c5d381917a3",
"after_sha256": "f15a8dc725aa4c1c6ab7eab6799446b7c79b35df237c2791791e7fe3c3830568"
}
},
"app/Shared/Context/ModuleRecords.php": {
"working_sha256": "1813591487e3fb1885622f1078e80734d1745f427d2bf8fa93ebc0d96974b0d6",
"matches_functional_commit_normalized": true,
"overlay": null
},
"app/Shared/Context/RequireModuleContext.php": {
"working_sha256": "610b65868ad25d1e6f736d03d7c1da44245648ff22873f1c957c794490009192",
"matches_functional_commit_normalized": true,
"overlay": null
},
"app/Modules/Identity/Http/RequireCompanyContext.php": {
"working_sha256": "3fcc9d4d4466d3b6883dd60cc3e63e9bb2f58a43d13ca550d79e35882562db71",
"matches_functional_commit_normalized": true,
"overlay": null
},
"app/Modules/Identity/Http/ModuleRecordsController.php": {
"working_sha256": "f10ee4a14ed19e461bfc819288cd2f701e9d73ce4421a18f1b11e1ca545726fb",
"matches_functional_commit_normalized": true,
"overlay": null
},
"app/Modules/Identity/Services/Audit.php": {
"working_sha256": "89d69975b3059a3aedbeff0aca1febbb92c6c135030c31b0cc4bdd8d7e602ecb",
"matches_functional_commit_normalized": true,
"overlay": null
},
"app/Modules/Identity/Services/IdentityWorkflow.php": {
"working_sha256": "c4f4af9a7625778a408d881ba087502b116fa0ccb15f2f0311f5a0e8ad40ce73",
"matches_functional_commit_normalized": true,
"overlay": {
"before_sha256": "c4f4af9a7625778a408d881ba087502b116fa0ccb15f2f0311f5a0e8ad40ce73",
"after_sha256": "e568e578dfc090a8df29b215c0196eacf3d472c32952c8422597b14c3a4a4038"
}
},
"resources/js/ModuleNavigation.jsx": {
"working_sha256": "b53ee2d9f69a96bdabf1d3074f8662fd204c447caf8f354aea4dcf921bd336be",
"matches_functional_commit_normalized": true,
"overlay": null
},
"resources/js/WorkspaceNavigation.jsx": {
"working_sha256": "7be946f915e3dabfb511445f169fe822c2e558ca15fef6331c247af2a1643ebf",
"matches_functional_commit_normalized": true,
"overlay": null
},
"resources/js/app.jsx": {
"working_sha256": "33f087da73fe80ca0ae6e7609e107b805b2c8a1f1863cc3a1b2c7886fe7d3c44",
"matches_functional_commit_normalized": true,
"overlay": null
},
"resources/js/WorkspaceHome.jsx": {
"working_sha256": "c02d71c6e630f942c13562427c7256e1b7602c75b80b462d184d45852d9ea34a",
"matches_functional_commit_normalized": true,
"overlay": null
},
"resources/js/ModuleRecordsWorkspace.jsx": {
"working_sha256": "24399a5e6a08c78357f23fc6d304a706f477f33db879a4cf52fc53511541b78c",
"matches_functional_commit_normalized": true,
"overlay": null
},
"resources/js/ContextTransitionDialog.jsx": {
"working_sha256": "04bde71f2ea5d26185aae930bfcf8978e5d38d1637915073cacbc12033fe9780",
"matches_functional_commit_normalized": true,
"overlay": null
},
"resources/js/context-transition.js": {
"working_sha256": "3d76e21eca185ae97c1a6a6f5965ab33c242a28391c8c50f5af30dfc0a4a3c6a",
"matches_functional_commit_normalized": true,
"overlay": null
},
"resources/css/tempo-theme.css": {
"working_sha256": "4b961ce49b2bb50072ea1fcae0c0d168c9ada207f59323cc52205353b7871df9",
"matches_functional_commit_normalized": true,
"overlay": null
},
"public/sgf-module-context.js": {
"working_sha256": "f465ea30ecea0acf3fc7b838b602ea881260d73b90aa48f587327b8ee1581dc7",
"matches_functional_commit_normalized": true,
"overlay": null
},
"config/modules.php": {
"working_sha256": "31330076b98ca423acfef0fa4e1c87a3762e53a750bd3f94c2b5a7d53e3edde4",
"matches_functional_commit_normalized": true,
"overlay": null
},
"routes/web.php": {
"working_sha256": "aa314a92c7f926c56699880d795286a0dd9659e6fbc0f653529e2f58a1bb326c",
"matches_functional_commit_normalized": true,
"overlay": null
},
"tests/Feature/ModuleNavigationTest.php": {
"working_sha256": "7f7655950d5847ed5702f95613061e7591a353f97d3349921625b8805822bfd4",
"matches_functional_commit_normalized": true,
"overlay": null
}
}
},
"permissions": {
"functional_user_grants": [],
"new_users": [],
"initialisation_scopes": [],
"operational_scopes": [],
"operational_enabled": false,
"application_ddl_privileges_added": false
},
"cache_policy": "Preserve uncached multi-environment host; do not run global config:cache, route:cache or event:cache. Preserve/check existing packages.php and services.php.",
"proofs_reused": [
"modular-navigation-completion.json",
"modular-navigation-recheck-20261102.json",
"internal-requisitions-sgf.json",
"internal-requisitions-validation.json",
"sgf-access-delivery.json",
"sgf-operational-delivery.json",
"sgf-composition-delivery.json",
"sgf-code-deploy-delivery.json",
"sgf-update-cache-delivery.json"
],
"executed": {
"read_only_plans": true,
"installation": false,
"migration": false,
"grants": false,
"maintenance": false,
"service_stops": false,
"backup": false,
"publication": false,
"owner_transaction_read_only": true
},
"schema": {
"new_tables": [
"cb_centres",
"cb_origins",
"cb_budgets",
"cb_budget_entries",
"cb_budget_consumptions",
"cb_budget_reinforcements",
"cb_audit",
"ir_requests",
"ir_steps",
"ir_events",
"ir_commands",
"ir_policies",
"ir_policy_versions",
"sgc_installations"
],
"permission_column_after": "varchar(100)",
"revision": 1,
"expected_tables_after": 101,
"transactional": true,
"automatic_down": false
},
"operational_readiness": {
"enabled": false,
"basic_supported_types": [
"consumable",
"service",
"other"
],
"equipment_parts_supported": false,
"equipment_parts_block_basic_types": false,
"backend_catalogue_included": true,
"initial_authority_screen_included": true,
"native_react_unit_permission_choices": [
"unit.view",
"unit.edit"
],
"native_admin_ui_complete_for_new_rights": false,
"public_user_grants_proposed": 0,
"open_for_business": false,
"centres_and_approved_budget_bootstrap_available": false,
"budget_workspace_support_tables_in_candidate": false,
"missing_budget_workspace_tables": [
"cb_ui_commands",
"cb_consumption_sources"
]
},
"recovery": {
"fresh_before_dump_and_full_restore_required": true,
"fresh_prepared_dump_and_full_restore_required": true,
"restores_reconcile_tables": [
87,
101
],
"historical_restore_proof_tables": 22,
"keep_additive_schema_on_code_rollback": true,
"destructive_restore_over_live_database": false
},
"maintenance": {
"stop_shared_postgres": false,
"preserve_other_hosts": true,
"stop_only_identified_destination_writers": true,
"global_laravel_cache_build": false,
"unknown_writer_or_restart_environment": "abort_before_changes"
},
"reused_proof_check_counts": {
"internal-requisitions-sgf.json": 43,
"sgf-access-delivery.json": 24,
"sgf-operational-delivery.json": 20,
"sgf-composition-delivery.json": 27,
"sgf-code-deploy-delivery.json": 42,
"sgf-update-cache-delivery.json": 32
},
"database_preflight": {
"owner_connection_checked_read_only": true,
"owner": "sgf_dev_owner",
"database": "sgf_tempo_dev",
"owner_can_create_schema": true,
"owner_owns_permission_grants": true,
"runtime_schema_usage": true,
"runtime_schema_create": false,
"verified_default_privileges": {
"tables": "sgf_dev_app=arwd",
"sequences": "sgf_dev_app=rU"
},
"new_object_privileges_must_match_verified_defaults": true
},
"superseded_by": "SGF-IR-USABLE-401C-20261102",
"historical_only_do_not_execute": true
}
+72
View File
@@ -0,0 +1,72 @@
{
"passed": true,
"checks": [
"Host expl\u00edcito obrigat\u00f3rio",
"Bundle expl\u00edcito obrigat\u00f3rio",
"plan is read-only",
"Manifesto divergente",
"Cache Laravel personalizado",
"manuten\u00e7\u00e3o activa",
"servi\u00e7os de escrita parados",
"Destino de c\u00f3digo divergente",
"applied offline without activation",
"invalidates known Laravel caches without touching unrelated files",
"applied verified overlay app\/Modules\/Identity\/Services\/Permissions.php",
"applied verified overlay app\/Modules\/Identity\/Services\/IdentityWorkflow.php",
"applied verified overlay app\/Modules\/Purchasing\/BudgetAdapter.php",
"applied verified overlay app\/Modules\/Purchasing\/BudgetWorkspace.php",
"applied verified overlay app\/Providers\/AppServiceProvider.php",
"applied verified overlay app\/Shared\/Context\/ModuleNavigation.php",
"applied verified overlay resources\/js\/app.jsx",
"applied verified overlay resources\/js\/PurchasingHome.jsx",
"applied verified overlay public\/build\/manifest.json",
"apply retry does not duplicate installation",
"C\u00f3digo local alterado",
"refused rollback preserves bundle and local code",
"Cache recriado",
"rollback preserves maintenance and never touches data schema",
"rollback restores exact previous cache",
"restored original overlay app\/Modules\/Identity\/Services\/Permissions.php",
"restored original overlay app\/Modules\/Identity\/Services\/IdentityWorkflow.php",
"restored original overlay app\/Modules\/Purchasing\/BudgetAdapter.php",
"restored original overlay app\/Modules\/Purchasing\/BudgetWorkspace.php",
"restored original overlay app\/Providers\/AppServiceProvider.php",
"restored original overlay app\/Shared\/Context\/ModuleNavigation.php",
"restored original overlay resources\/js\/app.jsx",
"restored original overlay resources\/js\/PurchasingHome.jsx",
"restored original overlay public\/build\/manifest.json",
"withdrawn bundle preserved for diagnosis",
"clone remains on original package pointer",
"Injected deployment interruption",
"interruption retains maintenance",
"interrupted deployment recovers app\/Modules\/Identity\/Services\/Permissions.php",
"interrupted deployment recovers app\/Modules\/Identity\/Services\/IdentityWorkflow.php",
"interrupted deployment recovers app\/Modules\/Purchasing\/BudgetAdapter.php",
"interrupted deployment recovers app\/Modules\/Purchasing\/BudgetWorkspace.php",
"interrupted deployment recovers app\/Providers\/AppServiceProvider.php",
"interrupted deployment recovers app\/Shared\/Context\/ModuleNavigation.php",
"interrupted deployment recovers resources\/js\/app.jsx",
"interrupted deployment recovers resources\/js\/PurchasingHome.jsx",
"interrupted deployment recovers public\/build\/manifest.json",
"destination pointer untouched",
"Injected post-switch interruption",
"post-switch interruption recovers without exposing partial code",
"Outra implanta\u00e7\u00e3o em curso",
"CLI plan verifies bundle without writes",
"CLI apply leaves services and maintenance under operator control",
"CLI rollback preserves 0.1.1 pointer"
],
"candidate": "C:\\laragon\\www\\compras\/storage\/app\/private\/candidates\/OPERATIONAL-CANDIDATE-401ce31ae5f2dd20",
"clones": [
"C:\\Users\\macbook\\AppData\\Local\\Temp\/sgf-code-deploy-f2382065595e",
"C:\\Users\\macbook\\AppData\\Local\\Temp\/sgf-code-deploy-1de2f989fa65",
"C:\\Users\\macbook\\AppData\\Local\\Temp\/sgf-code-deploy-7dd4d6ad2e94",
"C:\\Users\\macbook\\AppData\\Local\\Temp\/sgf-code-deploy-eeca8efbf821"
],
"checked_at": "2026-11-02T07:09:25+00:00",
"destination_version": "0.1.1",
"destination_applied": false,
"old_suites_repeated": false,
"database_opened": false,
"services_restarted": false
}
+41
View File
@@ -0,0 +1,41 @@
{
"passed": true,
"checks": [
"provider really loaded from isolated copy",
"budget adapter really loaded from isolated copy",
"new bundle bootstrap accepted by installer integrity check",
"anonymous direct initialisation URL denied",
"native clone authentication 1",
"native clone context 1",
"native clone authentication 2",
"native clone context 2",
"provider registers initial authority page without prior functional rights",
"initial authority CSRF enforced",
"initial authority through normal middleware",
"work page requires explicit module selection",
"new requisition view right makes purchasing selectable",
"stale module generation refused",
"provider registers operational work page",
"different enterprise option refused by operational composition",
"native administrative delegation purchasing_requisitions.view",
"native administrative delegation purchasing_requisitions.approve.department_head",
"operational policy configured via HTTP",
"integrated operational draft",
"integrated submit uses existing budget adapter",
"integrated independent identity enforced",
"integrated approval by another identity",
"integrated authorised consultation and history",
"native revocation applies to direct module URL",
"uncontracted module refused at server",
"disabled composition exposes no executable work page"
],
"clone": "C:\\Users\\macbook\\AppData\\Local\\Temp\/sgf-composition-f4de0d0473a5",
"destination_activated": false,
"normal_provider_routes": true,
"browser_used": false,
"overlay": "C:\\laragon\\www\\compras\/storage\/app\/private\/candidates\/OPERATIONAL-CANDIDATE-4b25f81932efd69d",
"checked_at": "2026-11-02T06:07:41+00:00",
"destination_version": "0.1.1",
"prior_tests_repeated": false,
"isolated_database_removed": true
}
+299
View File
@@ -0,0 +1,299 @@
{
"passed": true,
"checks": [
"reproduced current 87-table schema without source rows",
"no accounts or grants imported from destination",
"runtime cannot create schema objects",
"injected dependency migration failure",
"failed migration restores original schema and identity data",
"successful migration preserves existing identity and grants",
"installation creates empty centres and allocations",
"runtime module SQL access denied before test-only privilege plan",
"minimal runtime excludes historical update and requisition deletion",
"runtime reads corrected revision without ownership",
"provider really loaded from isolated copy",
"new bundle bootstrap accepted by installer integrity check",
"anonymous direct initialisation URL denied",
"native clone authentication 1",
"native clone context 1",
"native clone authentication 2",
"native clone context 2",
"provider registers initial authority page without prior functional rights",
"initial authority CSRF enforced",
"initial authority through normal middleware",
"work page requires explicit module selection",
"new requisition view right makes purchasing selectable",
"stale module generation refused",
"provider registers operational work page",
"different enterprise option refused by operational composition",
"native administrative delegation purchasing_requisitions.view",
"native administrative delegation purchasing_requisitions.approve.department_head",
"native administrative delegation purchasing_budget.view",
"native administrative delegation purchasing_budget.approve",
"empty installation exposes authorised centre and budget preparation",
"centre created through authorised UI API with runtime role",
"centre retries preserve one source",
"existing budget API prepares synthetic allocation",
"budget approval requires independent identity",
"independent allocation approval uses existing budget kernel",
"workspace dependencies available on reproduced schema",
"direct budget movements cannot bypass requisition lifecycle",
"operational policy configured via HTTP",
"integrated operational draft",
"integrated submit uses existing budget adapter",
"integrated independent identity enforced",
"integrated approval by another identity",
"integrated authorised consultation and history",
"native administration receives complete unit catalogue",
"native administration receives canonical server labels",
"reviewer cannot inspect administrative catalogue without management right",
"forged delegation of an unowned catalogue right refused",
"packaged frontend dependency served before authentication",
"packaged frontend dependency served before authentication",
"native SGF entry renders the packaged frontend manifest",
"undeclared frontend asset refused",
"minimal plan removes inherited update and delete on new append-only sources",
"runtime cannot truncate requisitions",
"existing table ACL preserved a_billing_drafts",
"existing table ACL preserved a_clients",
"existing table ACL preserved a_commands",
"existing table ACL preserved a_events",
"existing table ACL preserved a_history",
"existing table ACL preserved a_outbox",
"existing table ACL preserved a_pending",
"existing table ACL preserved a_service_drafts",
"existing table ACL preserved a_services",
"existing table ACL preserved b_internal_confirmations",
"existing table ACL preserved ca_commands",
"existing table ACL preserved ca_decisions",
"existing table ACL preserved ca_proposals",
"existing table ACL preserved ca_resolutions",
"existing table ACL preserved ca_submissions",
"existing table ACL preserved cache",
"existing table ACL preserved cache_locks",
"existing table ACL preserved companies",
"existing table ACL preserved company_memberships",
"existing table ACL preserved dc_calculations",
"existing table ACL preserved dc_commands",
"existing table ACL preserved dc_decisions",
"existing table ACL preserved dc_events",
"existing table ACL preserved dc_outbox",
"existing table ACL preserved dc_rates",
"existing table ACL preserved doc_history",
"existing table ACL preserved doc_records",
"existing table ACL preserved document_preview_model_history",
"existing table ACL preserved document_preview_models",
"existing table ACL preserved failed_jobs",
"existing table ACL preserved ib_budgets",
"existing table ACL preserved ib_commands",
"existing table ACL preserved ib_comparisons",
"existing table ACL preserved ib_decisions",
"existing table ACL preserved ib_events",
"existing table ACL preserved ib_outbox",
"existing table ACL preserved ic_commands",
"existing table ACL preserved ic_decisions",
"existing table ACL preserved ic_events",
"existing table ACL preserved ic_inputs",
"existing table ACL preserved ic_lots",
"existing table ACL preserved ic_outbox",
"existing table ACL preserved ic_products",
"existing table ACL preserved ic_results",
"existing table ACL preserved identity_audit",
"existing table ACL preserved job_batches",
"existing table ACL preserved jobs",
"existing table ACL preserved migrations",
"existing table ACL preserved password_reset_tokens",
"existing table ACL preserved permission_grants",
"existing table ACL preserved service_calculation_profiles",
"existing table ACL preserved service_calculation_results",
"existing table ACL preserved sessions",
"existing table ACL preserved sf_activation_events",
"existing table ACL preserved sf_decisions",
"existing table ACL preserved sf_proposals",
"existing table ACL preserved si_commands",
"existing table ACL preserved si_correction_requests",
"existing table ACL preserved si_counters",
"existing table ACL preserved si_decisions",
"existing table ACL preserved si_events",
"existing table ACL preserved si_invoices",
"existing table ACL preserved si_outbox",
"existing table ACL preserved si_proposals",
"existing table ACL preserved sr_commands",
"existing table ACL preserved sr_deliveries",
"existing table ACL preserved sr_effects",
"existing table ACL preserved sr_events",
"existing table ACL preserved sr_outbox",
"existing table ACL preserved sr_records",
"existing table ACL preserved tenants",
"existing table ACL preserved units",
"existing table ACL preserved users",
"existing table ACL preserved wb_claims",
"existing table ACL preserved wb_commands",
"existing table ACL preserved wb_decisions",
"existing table ACL preserved wb_events",
"existing table ACL preserved wb_generations",
"existing table ACL preserved wb_outbox",
"existing table ACL preserved wb_proposals",
"existing table ACL preserved wo_commands",
"existing table ACL preserved wo_decisions",
"existing table ACL preserved wo_entries",
"existing table ACL preserved wo_equipment",
"existing table ACL preserved wo_events",
"existing table ACL preserved wo_orders",
"existing table ACL preserved wo_outbox",
"actual runtime CREATE denied",
"actual runtime ALTER of identity catalogue denied",
"centre creation requires own configuration and budget rights",
"centre context cannot be forged",
"refused centre operations leave original source intact",
"unsupported requisition type refused equipment",
"unsupported requisition type refused part",
"approved lifecycle covers the three supported basic types",
"unsupported types create neither a second request nor reservation",
"native revocation applies to direct module URL",
"uncontracted module refused at server",
"disabled composition exposes no executable work page",
"code-only successor installed over existing provenance",
"code-only successor rollback restores exact candidate",
"code update and rollback preserve every reproduced data table",
"code recovery preserves submitted origin decision and reservation",
"code recovery leaves baseline and maintenance intact"
],
"clone": "C:\\Users\\macbook\\AppData\\Local\\Temp\/sgf-update-625f1bba6e30",
"data_fingerprints": {
"a_billing_drafts": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"a_clients": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"a_commands": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"a_events": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"a_history": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"a_outbox": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"a_pending": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"a_service_drafts": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"a_services": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"b_internal_confirmations": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"ca_commands": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"ca_decisions": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"ca_proposals": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"ca_resolutions": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"ca_submissions": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"cache": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"cache_locks": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"cb_audit": "ccf5b17cacb6e9d1cbbebdc55baca6b2b51103f3573c32dd1bddb24a055d2e2b",
"cb_budget_consumptions": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"cb_budget_entries": "ba73d3b7eb20c25d833df7b3b85f7f1f7575d78365ee1a3c2246e7749f2448ad",
"cb_budget_reinforcements": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"cb_budgets": "8df00e7e6b821e2767118c352f58391d4c44bb8df1fcc38a3d40a6a9989543a5",
"cb_centres": "45bebc4ca0d417711e2a428b360c343e6dba17a64a4d799639165815e5aaef45",
"cb_consumption_sources": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"cb_origins": "f470bed486f1955724e99cde0404445c4b9753320faee2d202289fedffc4d561",
"cb_ui_commands": "424c4f2f643087911333a3ecf002bbb5fc5055c5ccf24f5cefd94c9db56b398b",
"companies": "e5098861f02b2904e068c604ecbe1379ec6597b39fcdc9575c9d9eaa3b459aec",
"company_memberships": "562084217604e0bd153e36375251db9e4e87f92c744c69d38d2a39c7821454e5",
"dc_calculations": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"dc_commands": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"dc_decisions": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"dc_events": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"dc_outbox": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"dc_rates": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"doc_history": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"doc_records": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"document_preview_model_history": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"document_preview_models": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"failed_jobs": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"ib_budgets": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"ib_commands": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"ib_comparisons": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"ib_decisions": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"ib_events": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"ib_outbox": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"ic_commands": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"ic_decisions": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"ic_events": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"ic_inputs": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"ic_lots": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"ic_outbox": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"ic_products": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"ic_results": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"identity_audit": "b714264c1c89e456f9217c285169fa91bc379bb744684e39c2028bb48a025ca7",
"ir_commands": "fa90f00d334ae11e38a4aea327720569da50f196ad5aa4876fcaa0b6154d78ad",
"ir_events": "8379dcb6a4fb3d1cad80cab5a4afe9a49b86a7145e2dc613d6d5371d18e96051",
"ir_policies": "7ff4f648cbf36386f78743ed2394eb12e6328fb6e7722c6ba1acb5fab36ca1d1",
"ir_policy_versions": "7ff4f648cbf36386f78743ed2394eb12e6328fb6e7722c6ba1acb5fab36ca1d1",
"ir_requests": "874bbaa494e41ddc2bee527f3660909123a19c270f7eaee0e19d534d8c355fd6",
"ir_steps": "dcde70900864b1e974f66a4778e80e8317907c14a3dc0545afadb468c6f9eef6",
"job_batches": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"jobs": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"migrations": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"password_reset_tokens": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"permission_grants": "2219ad7945c6cd3d4e28bfc4a06c04eb6141ceaa53097efd01ab5f89811fec13",
"service_calculation_profiles": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"service_calculation_results": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"sessions": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"sf_activation_events": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"sf_decisions": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"sf_proposals": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"sgc_installations": "75449b61764076870970ddf93e9b987e6b7b24889de47fb8d9046a5345065f1c",
"si_commands": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"si_correction_requests": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"si_counters": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"si_decisions": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"si_events": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"si_invoices": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"si_outbox": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"si_proposals": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"sr_commands": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"sr_deliveries": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"sr_effects": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"sr_events": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"sr_outbox": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"sr_records": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"tenants": "0487a4884eb77b28bd8c052e9d2bd1a8177bab511463657d326a17c0c77b3619",
"units": "c0a43a3bf8907bcbebf727f089e8c75399ed7a94049ad85b666fe6b90851842e",
"users": "ea313e4a8b0a16e17dc1b61cea28c6832a76feed78540fe40ab61bbf88c6200c",
"wb_claims": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"wb_commands": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"wb_decisions": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"wb_events": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"wb_generations": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"wb_outbox": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"wb_proposals": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"wo_commands": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"wo_decisions": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"wo_entries": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"wo_equipment": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"wo_events": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"wo_orders": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"wo_outbox": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945"
},
"destination_activated": false,
"normal_provider_routes": true,
"browser_used": false,
"data_recovery": {
"verified": true,
"tables_reconciled": 103,
"approved_origin_reservation_versions_preserved": true,
"runtime_read_verified": true,
"runtime_ddl_denied": true,
"schema_and_triggers_verified": true,
"sql_acl_reapplied_only_to_isolated_role": true
},
"destination_security_and_schema_preserved": true,
"artifact": {
"directory": "C:\\laragon\\www\\compras\/storage\/app\/private\/candidates\/OPERATIONAL-CANDIDATE-401ce31ae5f2dd20",
"archive": {
"file": "C:\\laragon\\www\\compras\/storage\/app\/private\/candidate-archives\/OPERATIONAL-CANDIDATE-401ce31ae5f2dd20.zip",
"sha256": "59dbdc64c4d9f14dfb4025a6177b829d136a4e2cb633ca036b10b5ae3197e703",
"manifest_sha256": "a6478223e17a5430652f0fcbf31a44a931ae2a99cd90b151c98d2df5df43c10b"
},
"installed": false
},
"source_schema_tables": 87,
"source_rows_exported": 0,
"source_schema_sha256": "b530e03c759305247f46cdad5013e64a6caae00bded3d9d5ae5b7b5aa06a4647",
"runtime_and_migrator_separate": true,
"destination_version": "0.1.1",
"destination_changed": false,
"prior_proofs_reused": true,
"checked_at": "2026-11-02T07:10:03+00:00",
"test_database_and_roles_removed": true
}
+206
View File
@@ -0,0 +1,206 @@
{
"passed": true,
"identity": {
"db": "sgf_modules_dev_2576427d1939",
"role": "sgf_modules_qa_2576427d1939",
"cluster": "sgf_modular_regression_2576427d1939",
"port": 55439
},
"scope": "1:1:1",
"added_grants": [
{
"id": 103,
"user_id": 1,
"tenant_id": 1,
"company_id": 1,
"unit_id": 1,
"permission": "purchasing_budget.approve",
"created_at": "2026-11-02 07:25:53",
"updated_at": "2026-11-02 07:25:53"
},
{
"id": 104,
"user_id": 1,
"tenant_id": 1,
"company_id": 1,
"unit_id": 1,
"permission": "purchasing_budget.create",
"created_at": "2026-11-02 07:25:53",
"updated_at": "2026-11-02 07:25:53"
},
{
"id": 105,
"user_id": 1,
"tenant_id": 1,
"company_id": 1,
"unit_id": 1,
"permission": "purchasing_budget.record",
"created_at": "2026-11-02 07:25:53",
"updated_at": "2026-11-02 07:25:53"
},
{
"id": 106,
"user_id": 1,
"tenant_id": 1,
"company_id": 1,
"unit_id": 1,
"permission": "purchasing_budget.view",
"created_at": "2026-11-02 07:25:53",
"updated_at": "2026-11-02 07:25:53"
},
{
"id": 107,
"user_id": 1,
"tenant_id": 1,
"company_id": 1,
"unit_id": 1,
"permission": "purchasing_requisitions.approve.department_head",
"created_at": "2026-11-02 07:25:53",
"updated_at": "2026-11-02 07:25:53"
},
{
"id": 108,
"user_id": 1,
"tenant_id": 1,
"company_id": 1,
"unit_id": 1,
"permission": "purchasing_requisitions.configure",
"created_at": "2026-11-02 07:25:53",
"updated_at": "2026-11-02 07:25:53"
},
{
"id": 109,
"user_id": 1,
"tenant_id": 1,
"company_id": 1,
"unit_id": 1,
"permission": "purchasing_requisitions.prepare",
"created_at": "2026-11-02 07:25:53",
"updated_at": "2026-11-02 07:25:53"
},
{
"id": 110,
"user_id": 1,
"tenant_id": 1,
"company_id": 1,
"unit_id": 1,
"permission": "purchasing_requisitions.view",
"created_at": "2026-11-02 07:25:53",
"updated_at": "2026-11-02 07:25:53"
},
{
"id": 111,
"user_id": 2,
"tenant_id": 1,
"company_id": 1,
"unit_id": 1,
"permission": "purchasing_requisitions.view",
"created_at": "2026-11-02 07:25:53",
"updated_at": "2026-11-02 07:25:53"
},
{
"id": 112,
"user_id": 2,
"tenant_id": 1,
"company_id": 1,
"unit_id": 1,
"permission": "purchasing_requisitions.approve.department_head",
"created_at": "2026-11-02 07:25:53",
"updated_at": "2026-11-02 07:25:53"
},
{
"id": 113,
"user_id": 2,
"tenant_id": 1,
"company_id": 1,
"unit_id": 1,
"permission": "purchasing_budget.view",
"created_at": "2026-11-02 07:25:54",
"updated_at": "2026-11-02 07:25:54"
},
{
"id": 114,
"user_id": 2,
"tenant_id": 1,
"company_id": 1,
"unit_id": 1,
"permission": "purchasing_budget.approve",
"created_at": "2026-11-02 07:25:54",
"updated_at": "2026-11-02 07:25:54"
},
{
"id": 115,
"user_id": 3,
"tenant_id": 1,
"company_id": 1,
"unit_id": 1,
"permission": "purchasing_requisitions.view",
"created_at": "2026-11-02 07:25:54",
"updated_at": "2026-11-02 07:25:54"
},
{
"id": 116,
"user_id": 3,
"tenant_id": 1,
"company_id": 1,
"unit_id": 1,
"permission": "purchasing_budget.view",
"created_at": "2026-11-02 07:25:54",
"updated_at": "2026-11-02 07:25:54"
}
],
"existing_grants_preserved": true,
"existing_accounts_preserved": true,
"single_approved_request": true,
"single_reservation": true,
"reservation": {
"id": 1,
"tenant_id": 1,
"company_id": 1,
"unit_id": 1,
"budget_id": 1,
"requisition_id": 1,
"created_by": 1,
"kind": "reserve",
"reserved_minor": 10000,
"committed_minor": 0,
"created_at": "2026-11-02 07:26:06"
},
"budget": {
"id": 1,
"tenant_id": 1,
"company_id": 1,
"unit_id": 1,
"cost_center_id": 1,
"year": 2026,
"kind": "operating",
"amount_minor": 1000000,
"includes_tax": true,
"reason": "Owner-authorised synthetic 10000 MZN allocation for 2026.",
"created_by": 1,
"approved_by": 2,
"approved_at": "2026-11-02 07:26:05",
"created_at": "2026-11-02 07:26:04",
"updated_at": "2026-11-02 07:26:05"
},
"decision": {
"id": 1,
"tenant_id": 1,
"company_id": 1,
"unit_id": 1,
"request_id": 1,
"position": 1,
"role": "department_head",
"decision": "approved",
"approver_id": 2,
"comment": null,
"decided_at": "2026-11-02 07:26:19"
},
"pointer_preserved": true,
"backup_sha256": "2eed6d9f775d8d5dc8c7b1606e230b8782c09a69098d31e659d9ad28a4d608fa",
"recovery_directory": "C:\/laragon\/data\/sgf-tempo\/run\/modular-regression-2576427d1939\/private\/requisitions-recovery",
"checked_at": "2026-11-02T07:27:43+00:00",
"owner_runtime_limitation": true,
"visual_review": false,
"read_only_record_visibility_limitation": true
}
+41
View File
@@ -0,0 +1,41 @@
{
"passed": true,
"url": "http://127.0.0.1:8039",
"scope": "1:1:1",
"rights": {
"1": [
"purchasing_requisitions.view",
"purchasing_requisitions.prepare",
"purchasing_requisitions.configure",
"purchasing_requisitions.approve.department_head",
"purchasing_budget.view",
"purchasing_budget.create",
"purchasing_budget.approve",
"purchasing_budget.record"
],
"2": [
"purchasing_requisitions.view",
"purchasing_requisitions.approve.department_head",
"purchasing_budget.view",
"purchasing_budget.approve"
],
"3": [
"purchasing_requisitions.view",
"purchasing_budget.view"
]
},
"centre_id": 1,
"budget_id": 1,
"request_id": 1,
"checks": [
"Existing three synthetic identities authenticate without password changes",
"Eight plus four plus two explicit authorised grants",
"Synthetic allocation 10000 MZN approved by second identity; self and read-only approvals refused",
"Full request lifecycle, independent approval and three-event history consulted by preparer and reviewer",
"Existing record visibility rule returns 404 to read-only third identity; listing remains accessible; no extra rights granted",
"Read-only profile refused centre, budget approval, policy, preparation, submission, decision and access administration"
],
"checked_at": "2026-11-02T07:26:58.680Z",
"visual_review": false,
"real_installation_changed": false
}
@@ -0,0 +1,269 @@
{
"identity": {
"db": "sgf_modules_dev_2576427d1939",
"role": "sgf_modules_qa_2576427d1939",
"port": 55439,
"cluster": "sgf_modular_regression_2576427d1939"
},
"read_only": true,
"previous_grants_preserved": true,
"new_grants": [
{
"id": 103,
"user_id": 1,
"tenant_id": 1,
"company_id": 1,
"unit_id": 1,
"permission": "purchasing_budget.approve",
"created_at": "2026-11-02 07:25:53",
"updated_at": "2026-11-02 07:25:53"
},
{
"id": 104,
"user_id": 1,
"tenant_id": 1,
"company_id": 1,
"unit_id": 1,
"permission": "purchasing_budget.create",
"created_at": "2026-11-02 07:25:53",
"updated_at": "2026-11-02 07:25:53"
},
{
"id": 105,
"user_id": 1,
"tenant_id": 1,
"company_id": 1,
"unit_id": 1,
"permission": "purchasing_budget.record",
"created_at": "2026-11-02 07:25:53",
"updated_at": "2026-11-02 07:25:53"
},
{
"id": 106,
"user_id": 1,
"tenant_id": 1,
"company_id": 1,
"unit_id": 1,
"permission": "purchasing_budget.view",
"created_at": "2026-11-02 07:25:53",
"updated_at": "2026-11-02 07:25:53"
},
{
"id": 107,
"user_id": 1,
"tenant_id": 1,
"company_id": 1,
"unit_id": 1,
"permission": "purchasing_requisitions.approve.department_head",
"created_at": "2026-11-02 07:25:53",
"updated_at": "2026-11-02 07:25:53"
},
{
"id": 108,
"user_id": 1,
"tenant_id": 1,
"company_id": 1,
"unit_id": 1,
"permission": "purchasing_requisitions.configure",
"created_at": "2026-11-02 07:25:53",
"updated_at": "2026-11-02 07:25:53"
},
{
"id": 109,
"user_id": 1,
"tenant_id": 1,
"company_id": 1,
"unit_id": 1,
"permission": "purchasing_requisitions.prepare",
"created_at": "2026-11-02 07:25:53",
"updated_at": "2026-11-02 07:25:53"
},
{
"id": 110,
"user_id": 1,
"tenant_id": 1,
"company_id": 1,
"unit_id": 1,
"permission": "purchasing_requisitions.view",
"created_at": "2026-11-02 07:25:53",
"updated_at": "2026-11-02 07:25:53"
},
{
"id": 111,
"user_id": 2,
"tenant_id": 1,
"company_id": 1,
"unit_id": 1,
"permission": "purchasing_requisitions.view",
"created_at": "2026-11-02 07:25:53",
"updated_at": "2026-11-02 07:25:53"
},
{
"id": 112,
"user_id": 2,
"tenant_id": 1,
"company_id": 1,
"unit_id": 1,
"permission": "purchasing_requisitions.approve.department_head",
"created_at": "2026-11-02 07:25:53",
"updated_at": "2026-11-02 07:25:53"
},
{
"id": 113,
"user_id": 2,
"tenant_id": 1,
"company_id": 1,
"unit_id": 1,
"permission": "purchasing_budget.view",
"created_at": "2026-11-02 07:25:54",
"updated_at": "2026-11-02 07:25:54"
},
{
"id": 114,
"user_id": 2,
"tenant_id": 1,
"company_id": 1,
"unit_id": 1,
"permission": "purchasing_budget.approve",
"created_at": "2026-11-02 07:25:54",
"updated_at": "2026-11-02 07:25:54"
},
{
"id": 115,
"user_id": 3,
"tenant_id": 1,
"company_id": 1,
"unit_id": 1,
"permission": "purchasing_requisitions.view",
"created_at": "2026-11-02 07:25:54",
"updated_at": "2026-11-02 07:25:54"
},
{
"id": 116,
"user_id": 3,
"tenant_id": 1,
"company_id": 1,
"unit_id": 1,
"permission": "purchasing_budget.view",
"created_at": "2026-11-02 07:25:54",
"updated_at": "2026-11-02 07:25:54"
}
],
"users_unchanged": true,
"backup_valid": true,
"backup_sha256": "2eed6d9f775d8d5dc8c7b1606e230b8782c09a69098d31e659d9ad28a4d608fa",
"centres": [
{
"id": 1,
"tenant_id": 1,
"company_id": 1,
"unit_id": 1,
"code": "SINTETICO-REPRO"
}
],
"budgets": [
{
"id": 1,
"tenant_id": 1,
"company_id": 1,
"unit_id": 1,
"cost_center_id": 1,
"year": 2026,
"kind": "operating",
"amount_minor": 1000000,
"includes_tax": true,
"reason": "Owner-authorised synthetic 10000 MZN allocation for 2026.",
"created_by": 1,
"approved_by": 2,
"approved_at": "2026-11-02 07:26:05",
"created_at": "2026-11-02 07:26:04",
"updated_at": "2026-11-02 07:26:05"
}
],
"requests": [
{
"id": 1,
"status": "approved",
"requester_id": 1,
"version": 3,
"total_minor": 10000
}
],
"steps": [
{
"id": 1,
"tenant_id": 1,
"company_id": 1,
"unit_id": 1,
"request_id": 1,
"position": 1,
"role": "department_head",
"decision": "approved",
"approver_id": 2,
"comment": null,
"decided_at": "2026-11-02 07:26:19"
}
],
"entries": [
{
"id": 1,
"tenant_id": 1,
"company_id": 1,
"unit_id": 1,
"budget_id": 1,
"requisition_id": 1,
"created_by": 1,
"kind": "reserve",
"reserved_minor": 10000,
"committed_minor": 0,
"created_at": "2026-11-02 07:26:06"
}
],
"policy": [
{
"id": 1,
"tenant_id": 1,
"company_id": 1,
"unit_id": 1,
"version": 1,
"actor_id": 1,
"payload": "{\"reason\": \"Owner-confirmed synthetic OPER policy, demonstration 8039 only.\", \"centres\": [{\"id\": 1, \"department_ref\": \"OPER\"}], \"enabled\": true, \"members\": [{\"user_id\": 1, \"department_ref\": \"OPER\"}, {\"user_id\": 2, \"department_ref\": \"OPER\"}], \"budget_required\": true, \"first_limit_minor\": 1000000, \"rules_provisional\": false, \"second_limit_minor\": 2000000, \"approval_includes_tax\": true}",
"created_at": "2026-11-02 07:26:05"
}
],
"initialisation_scopes": [],
"operational": {
"enabled": true,
"target": "57f6d55203a3f2ed18713549475f959d7d907165ff793c049450e78b535051bf",
"scopes": [
"1:1:1"
]
},
"pointer_unchanged": true,
"real_installation_snapshot_preserved": true,
"real_snapshot": {
"database": {
"database": "sgf_tempo_dev",
"role": "sgf_dev_app",
"port": 55432
},
"tables": {
"permission_grants": {
"rows": 89,
"fingerprint": "f4546a8af83c965f7088ba47f55e0fec"
},
"company_memberships": {
"rows": 2,
"fingerprint": "f5462c7d3b1f5c75d70450dc6b61990e"
},
"identity_audit": {
"rows": 162,
"fingerprint": "cbff39d0e77e9bd7c3cafb4a5d574591"
}
},
"guard_sha256": "42708432fa029e3e52743016b6c6b6d734a3e6cd5d3ed266a29ecfcf38a6e371",
"purchasing_pointer_sha256": "81899e531e9eec449717e694d8bdc106a9e220a828f5491ce918c1d2dc612787"
},
"execution_proofs_reused": true,
"checked_at": "2026-11-02T07:28:00.363Z"
}
@@ -0,0 +1,81 @@
{
"checked_at": "2026-11-02T06:43:39+00:00",
"host": "C:\\laragon\\www\\sgf-tempo",
"app_url": "http://127.0.0.1:8000",
"environment": "local",
"php": "8.4.27",
"database": {
"driver": "pgsql",
"configured_host": "127.0.0.1",
"configured_port": "55432",
"configured_database": "sgf_tempo_dev",
"actual": {
"database": "sgf_tempo_dev",
"address": "127.0.0.1/32",
"port": 55432
}
},
"schema": {
"public_table_count": 87,
"missing_foundation": [
],
"existing_budget_tables": [
],
"existing_integration_tables": [
],
"budget_ui_support_tables_present": [
],
"permission_column_length": 40,
"scope_constraint_present": true,
"scope_constraint_sha256": "25044df129dc69efe8e9411c6b2f82558982cc37da7b478b771d1e58842025e0",
"ddl_privileges": {
"can_create": false,
"can_alter_permissions": false
}
},
"database_roles": {
"runtime_role": "sgf_dev_app",
"permissions_owner": "sgf_dev_owner"
},
"config_cached": false,
"owner_capabilities": {
"can_login": true,
"can_create_public": true
},
"preservation_baseline": {
"permission_grants": {
"rows": 89,
"sha256": "714dfbbbed4a19c1d3e10077b020ec6d06334cbc2b538820808f73d06593bd59"
},
"company_memberships": {
"rows": 2,
"sha256": "562084217604e0bd153e36375251db9e4e87f92c744c69d38d2a39c7821454e5"
},
"identity_audit": {
"rows": 162,
"sha256": "6d05de68554ab9a06d8c6a8132bb3f1ff99e19d06ed6294353b40e6084a9e4b1"
}
},
"organisation_counts": {
"companies": 1,
"units": 1,
"company_admin_grants": 1
},
"purchasing_pointer": {
"version": "0.1.1",
"manifest_sha256": "91ba35ee3aa1ca226052c94ed682e430cb7870beb241f16b17d889046e1f711d",
"source_sha256": "692921d9e7e57579df876fbd9239d37790fc49d7b96b92fa10514bdc9a1dc250",
"previous": "0.1.0",
"audit_id": "8d922d5b757723be97f7c5f7"
},
"pointer_sha256": "81899e531e9eec449717e694d8bdc106a9e220a828f5491ce918c1d2dc612787",
"bundle_exists": false,
"maintenance_marker_present": false,
"operational_config_file_present": false,
"read_only_transaction": true,
"installed": false
}
+102
View File
@@ -0,0 +1,102 @@
-- PROPOSTA NAO AUTORIZADA. NAO EXECUTAR.
-- Depois da migracao revisao 2; ligacao migradora da base nova apenas.
BEGIN;
DO $$ BEGIN
IF current_database() <> 'sgf_ir_dev_401c_20261102' OR inet_server_port() <> 55441 OR current_user <> 'sgf_ir_owner_401c' THEN
RAISE EXCEPTION 'Destino/role de proposta divergente';
END IF;
IF NOT EXISTS (SELECT 1 FROM sgc_installations WHERE module='internal-requisitions' AND revision=2) THEN
RAISE EXCEPTION 'Migracao revisao 2 nao conferida';
END IF;
END $$;
REVOKE ALL PRIVILEGES ON TABLE public."cb_centres" FROM "sgf_ir_app_401c";
REVOKE ALL PRIVILEGES ON TABLE public."cb_centres" FROM PUBLIC;
GRANT SELECT, INSERT ON TABLE public."cb_centres" TO "sgf_ir_app_401c";
REVOKE ALL PRIVILEGES ON SEQUENCE public."cb_centres_id_seq" FROM "sgf_ir_app_401c";
REVOKE ALL PRIVILEGES ON SEQUENCE public."cb_centres_id_seq" FROM PUBLIC;
GRANT USAGE ON SEQUENCE public."cb_centres_id_seq" TO "sgf_ir_app_401c";
REVOKE ALL PRIVILEGES ON TABLE public."cb_origins" FROM "sgf_ir_app_401c";
REVOKE ALL PRIVILEGES ON TABLE public."cb_origins" FROM PUBLIC;
GRANT SELECT, INSERT ON TABLE public."cb_origins" TO "sgf_ir_app_401c";
REVOKE ALL PRIVILEGES ON SEQUENCE public."cb_origins_id_seq" FROM "sgf_ir_app_401c";
REVOKE ALL PRIVILEGES ON SEQUENCE public."cb_origins_id_seq" FROM PUBLIC;
GRANT USAGE ON SEQUENCE public."cb_origins_id_seq" TO "sgf_ir_app_401c";
REVOKE ALL PRIVILEGES ON TABLE public."cb_budgets" FROM "sgf_ir_app_401c";
REVOKE ALL PRIVILEGES ON TABLE public."cb_budgets" FROM PUBLIC;
GRANT SELECT, INSERT, UPDATE ON TABLE public."cb_budgets" TO "sgf_ir_app_401c";
REVOKE ALL PRIVILEGES ON SEQUENCE public."cb_budgets_id_seq" FROM "sgf_ir_app_401c";
REVOKE ALL PRIVILEGES ON SEQUENCE public."cb_budgets_id_seq" FROM PUBLIC;
GRANT USAGE ON SEQUENCE public."cb_budgets_id_seq" TO "sgf_ir_app_401c";
REVOKE ALL PRIVILEGES ON TABLE public."cb_budget_entries" FROM "sgf_ir_app_401c";
REVOKE ALL PRIVILEGES ON TABLE public."cb_budget_entries" FROM PUBLIC;
GRANT SELECT, INSERT ON TABLE public."cb_budget_entries" TO "sgf_ir_app_401c";
REVOKE ALL PRIVILEGES ON SEQUENCE public."cb_budget_entries_id_seq" FROM "sgf_ir_app_401c";
REVOKE ALL PRIVILEGES ON SEQUENCE public."cb_budget_entries_id_seq" FROM PUBLIC;
GRANT USAGE ON SEQUENCE public."cb_budget_entries_id_seq" TO "sgf_ir_app_401c";
REVOKE ALL PRIVILEGES ON TABLE public."cb_audit" FROM "sgf_ir_app_401c";
REVOKE ALL PRIVILEGES ON TABLE public."cb_audit" FROM PUBLIC;
GRANT SELECT, INSERT ON TABLE public."cb_audit" TO "sgf_ir_app_401c";
REVOKE ALL PRIVILEGES ON SEQUENCE public."cb_audit_id_seq" FROM "sgf_ir_app_401c";
REVOKE ALL PRIVILEGES ON SEQUENCE public."cb_audit_id_seq" FROM PUBLIC;
GRANT USAGE ON SEQUENCE public."cb_audit_id_seq" TO "sgf_ir_app_401c";
REVOKE ALL PRIVILEGES ON TABLE public."cb_ui_commands" FROM "sgf_ir_app_401c";
REVOKE ALL PRIVILEGES ON TABLE public."cb_ui_commands" FROM PUBLIC;
GRANT SELECT, INSERT ON TABLE public."cb_ui_commands" TO "sgf_ir_app_401c";
REVOKE ALL PRIVILEGES ON SEQUENCE public."cb_ui_commands_id_seq" FROM "sgf_ir_app_401c";
REVOKE ALL PRIVILEGES ON SEQUENCE public."cb_ui_commands_id_seq" FROM PUBLIC;
GRANT USAGE ON SEQUENCE public."cb_ui_commands_id_seq" TO "sgf_ir_app_401c";
REVOKE ALL PRIVILEGES ON TABLE public."cb_budget_consumptions" FROM "sgf_ir_app_401c";
REVOKE ALL PRIVILEGES ON TABLE public."cb_budget_consumptions" FROM PUBLIC;
GRANT SELECT ON TABLE public."cb_budget_consumptions" TO "sgf_ir_app_401c";
REVOKE ALL PRIVILEGES ON SEQUENCE public."cb_budget_consumptions_id_seq" FROM "sgf_ir_app_401c";
REVOKE ALL PRIVILEGES ON SEQUENCE public."cb_budget_consumptions_id_seq" FROM PUBLIC;
REVOKE ALL PRIVILEGES ON TABLE public."cb_budget_reinforcements" FROM "sgf_ir_app_401c";
REVOKE ALL PRIVILEGES ON TABLE public."cb_budget_reinforcements" FROM PUBLIC;
GRANT SELECT ON TABLE public."cb_budget_reinforcements" TO "sgf_ir_app_401c";
REVOKE ALL PRIVILEGES ON SEQUENCE public."cb_budget_reinforcements_id_seq" FROM "sgf_ir_app_401c";
REVOKE ALL PRIVILEGES ON SEQUENCE public."cb_budget_reinforcements_id_seq" FROM PUBLIC;
REVOKE ALL PRIVILEGES ON TABLE public."cb_consumption_sources" FROM "sgf_ir_app_401c";
REVOKE ALL PRIVILEGES ON TABLE public."cb_consumption_sources" FROM PUBLIC;
GRANT SELECT ON TABLE public."cb_consumption_sources" TO "sgf_ir_app_401c";
REVOKE ALL PRIVILEGES ON SEQUENCE public."cb_consumption_sources_id_seq" FROM "sgf_ir_app_401c";
REVOKE ALL PRIVILEGES ON SEQUENCE public."cb_consumption_sources_id_seq" FROM PUBLIC;
REVOKE ALL PRIVILEGES ON TABLE public."ir_requests" FROM "sgf_ir_app_401c";
REVOKE ALL PRIVILEGES ON TABLE public."ir_requests" FROM PUBLIC;
GRANT SELECT, INSERT, UPDATE ON TABLE public."ir_requests" TO "sgf_ir_app_401c";
REVOKE ALL PRIVILEGES ON SEQUENCE public."ir_requests_id_seq" FROM "sgf_ir_app_401c";
REVOKE ALL PRIVILEGES ON SEQUENCE public."ir_requests_id_seq" FROM PUBLIC;
GRANT USAGE ON SEQUENCE public."ir_requests_id_seq" TO "sgf_ir_app_401c";
REVOKE ALL PRIVILEGES ON TABLE public."ir_steps" FROM "sgf_ir_app_401c";
REVOKE ALL PRIVILEGES ON TABLE public."ir_steps" FROM PUBLIC;
GRANT SELECT, INSERT, UPDATE ON TABLE public."ir_steps" TO "sgf_ir_app_401c";
REVOKE ALL PRIVILEGES ON SEQUENCE public."ir_steps_id_seq" FROM "sgf_ir_app_401c";
REVOKE ALL PRIVILEGES ON SEQUENCE public."ir_steps_id_seq" FROM PUBLIC;
GRANT USAGE ON SEQUENCE public."ir_steps_id_seq" TO "sgf_ir_app_401c";
REVOKE ALL PRIVILEGES ON TABLE public."ir_policies" FROM "sgf_ir_app_401c";
REVOKE ALL PRIVILEGES ON TABLE public."ir_policies" FROM PUBLIC;
GRANT SELECT, INSERT, UPDATE ON TABLE public."ir_policies" TO "sgf_ir_app_401c";
REVOKE ALL PRIVILEGES ON SEQUENCE public."ir_policies_id_seq" FROM "sgf_ir_app_401c";
REVOKE ALL PRIVILEGES ON SEQUENCE public."ir_policies_id_seq" FROM PUBLIC;
GRANT USAGE ON SEQUENCE public."ir_policies_id_seq" TO "sgf_ir_app_401c";
REVOKE ALL PRIVILEGES ON TABLE public."ir_events" FROM "sgf_ir_app_401c";
REVOKE ALL PRIVILEGES ON TABLE public."ir_events" FROM PUBLIC;
GRANT SELECT, INSERT ON TABLE public."ir_events" TO "sgf_ir_app_401c";
REVOKE ALL PRIVILEGES ON SEQUENCE public."ir_events_id_seq" FROM "sgf_ir_app_401c";
REVOKE ALL PRIVILEGES ON SEQUENCE public."ir_events_id_seq" FROM PUBLIC;
GRANT USAGE ON SEQUENCE public."ir_events_id_seq" TO "sgf_ir_app_401c";
REVOKE ALL PRIVILEGES ON TABLE public."ir_commands" FROM "sgf_ir_app_401c";
REVOKE ALL PRIVILEGES ON TABLE public."ir_commands" FROM PUBLIC;
GRANT SELECT, INSERT ON TABLE public."ir_commands" TO "sgf_ir_app_401c";
REVOKE ALL PRIVILEGES ON SEQUENCE public."ir_commands_id_seq" FROM "sgf_ir_app_401c";
REVOKE ALL PRIVILEGES ON SEQUENCE public."ir_commands_id_seq" FROM PUBLIC;
GRANT USAGE ON SEQUENCE public."ir_commands_id_seq" TO "sgf_ir_app_401c";
REVOKE ALL PRIVILEGES ON TABLE public."ir_policy_versions" FROM "sgf_ir_app_401c";
REVOKE ALL PRIVILEGES ON TABLE public."ir_policy_versions" FROM PUBLIC;
GRANT SELECT, INSERT ON TABLE public."ir_policy_versions" TO "sgf_ir_app_401c";
REVOKE ALL PRIVILEGES ON SEQUENCE public."ir_policy_versions_id_seq" FROM "sgf_ir_app_401c";
REVOKE ALL PRIVILEGES ON SEQUENCE public."ir_policy_versions_id_seq" FROM PUBLIC;
GRANT USAGE ON SEQUENCE public."ir_policy_versions_id_seq" TO "sgf_ir_app_401c";
REVOKE ALL PRIVILEGES ON TABLE public."sgc_installations" FROM "sgf_ir_app_401c";
REVOKE ALL PRIVILEGES ON TABLE public."sgc_installations" FROM PUBLIC;
GRANT SELECT ON TABLE public."sgc_installations" TO "sgf_ir_app_401c";
COMMIT;
+25
View File
@@ -0,0 +1,25 @@
-- PROPOSTA NAO AUTORIZADA. NAO EXECUTAR.
-- Ligacao administrativa EXCLUSIVAMENTE ao cluster novo 55441.
-- Executar com ON_ERROR_STOP; sem reutilizar roles/bases existentes.
DO $$ BEGIN
IF inet_server_port() <> 55441 OR current_setting('cluster_name') <> 'sgf_ir_401c_20261102' THEN
RAISE EXCEPTION 'Cluster novo obrigatorio';
END IF;
IF EXISTS (SELECT 1 FROM pg_roles WHERE rolname IN ('sgf_ir_owner_401c','sgf_ir_app_401c'))
OR EXISTS (SELECT 1 FROM pg_database WHERE datname='sgf_ir_dev_401c_20261102') THEN
RAISE EXCEPTION 'Destino ja existe; reconciliar sem sobrepor';
END IF;
END $$;
CREATE ROLE sgf_ir_owner_401c NOLOGIN NOSUPERUSER NOCREATEDB NOCREATEROLE NOINHERIT NOREPLICATION NOBYPASSRLS;
CREATE ROLE sgf_ir_app_401c NOLOGIN NOSUPERUSER NOCREATEDB NOCREATEROLE NOINHERIT NOREPLICATION NOBYPASSRLS;
CREATE DATABASE sgf_ir_dev_401c_20261102 OWNER sgf_ir_owner_401c;
REVOKE ALL ON DATABASE sgf_ir_dev_401c_20261102 FROM PUBLIC;
GRANT CONNECT ON DATABASE sgf_ir_dev_401c_20261102 TO sgf_ir_app_401c;
-- Na base nova, depois de restaurar sem owner/ACL com sgf_ir_owner_401c:
-- REVOKE CREATE ON SCHEMA public FROM PUBLIC;
-- REVOKE CREATE ON SCHEMA public FROM sgf_ir_app_401c;
-- GRANT USAGE ON SCHEMA public TO sgf_ir_app_401c;
-- Sem filiacoes entre roles, GRANT ALL ou DEFAULT PRIVILEGES globais.
-- Provisionamento privado posterior: duas senhas SCRAM aleatorias/distintas,
-- activar LOGIN nas duas roles apenas com HBA restrita a esta base/loopback.
-- Nenhuma senha faz parte deste ficheiro; nenhuma role existente e alterada.
@@ -0,0 +1,119 @@
{
"proposal_id": "SGF-IR-USABLE-401C-20261102",
"state": "proposed_not_executed",
"synthetic_only": true,
"destination": {
"root": "C:/laragon/data/sgf-tempo/run/ir-usable-401c-20261102/app",
"environment": "local",
"url": "http://127.0.0.1:8041",
"database": "sgf_ir_dev_401c_20261102",
"cluster": "sgf_ir_401c_20261102",
"port": 55441,
"migrator": "sgf_ir_owner_401c",
"runtime": "sgf_ir_app_401c"
},
"source": {
"database": "sgf_modules_dev_2576427d1939",
"port": 55439,
"tables": 93,
"new_module_tables_present": false,
"source_is_synthetic": true,
"existing_runtime_owns_tables": true,
"existing_runtime_can_create": true,
"candidate_nine_baselines_match": true,
"modified": false
},
"scope": {
"tenant": 1,
"company": 1,
"unit": 1,
"company_name": "Empresa Horizonte ? Demonstra??o",
"unit_name": "Unidade Central ? Demonstra??o",
"centre": "SYN-IR-401C",
"department": "SYN-OPER"
},
"budget": {
"currency": "MZN",
"year": 2026,
"kind": "operating",
"amount_minor": 5000000,
"includes_tax": true
},
"policy": {
"enabled": true,
"budget_required": true,
"approval_includes_tax": true,
"first_limit_minor": 1000000,
"second_limit_minor": 2000000
},
"accounts": {
"reused_synthetic_ids": [
1,
2,
3
],
"new_synthetic_emails": [
"admin-ir-401c@example.test",
"compras-ir-401c@example.test",
"financeiro-ir-401c@example.test"
],
"real_accounts_changed": false
},
"migration": {
"revision": 2,
"expected_before": 93,
"new_tables": 16,
"expected_after": 109,
"runtime_sql_map": "SqlPrivileges::plan(sgf_ir_app_401c)",
"legacy_destination_hashes_not_reusable": true
},
"preservation": {
"real_database": "sgf_tempo_dev",
"real_database_write": false,
"existing_demo_write": false,
"purchasing_version": "0.1.1",
"visual_review_separate": true,
"legacy_associations_not_inferred": true,
"pagination_pending": true,
"publishing": false
},
"proof_reuse": {
"integrated_checks": 157,
"ui_checks": 17,
"deployment_checks": 54,
"new_destination_provisioned": false,
"new_destination_tests_executed": false
},
"confirmation_required": true,
"administrator_closure": {
"email": "admin-ir-401c@example.test",
"scope": "1:1:1",
"remove_via_audited_native_revocation": [
"purchasing_requisitions.prepare",
"purchasing_requisitions.approve.department_head",
"purchasing_requisitions.approve.procurement",
"purchasing_requisitions.approve.finance",
"purchasing_budget.approve",
"purchasing_budget.record"
],
"retain": [
"company.view",
"access.manage",
"unit.view",
"purchasing_requisitions.view",
"purchasing_requisitions.configure",
"purchasing_budget.view",
"purchasing_budget.create"
],
"initialisation_scopes_after": [],
"implicit_reinitialisation": false,
"delegation_of_removed_rights_after_closure": false,
"existing_preparer_access_manage_unchanged": true
},
"final_new_object_sql": {
"file": "sgf-ir-401c-new-objects.sql",
"role": "sgf_ir_app_401c",
"sha256": "c903156a5bbc3cc440b2cfcc6c05ff3a8ec606710572faf4744bcb7708ffcc14",
"executed": false
}
}
@@ -0,0 +1,205 @@
{
"date": "2026-11-02",
"increment": "SGF-PAYABLE-HISTORY-RECEIPT-SIM-v1",
"status": "local_synthetic_adapter_implemented",
"regression": {
"kind": "sgf_historical_payable_adapter_synthetic",
"cases": [
{
"name": "default-disabled-and-old-path-preserved",
"assertions": 4,
"passed": true
},
{
"name": "principal-confirmed-only-and-idempotency",
"assertions": 16,
"passed": true
},
{
"name": "receipt-integrity-and-identity-refusals",
"assertions": 6,
"passed": true
},
{
"name": "complete-compatible-payment-facts-required",
"assertions": 7,
"passed": true
},
{
"name": "changed-history-requires-new-conference",
"assertions": 3,
"passed": true
},
{
"name": "permissions-person-and-context-revalidated",
"assertions": 5,
"passed": true
},
{
"name": "audit-and-import-failure-atomic-recovery",
"assertions": 3,
"passed": true
},
{
"name": "receipt-append-only-and-existing-controller",
"assertions": 3,
"passed": true
},
{
"name": "invalid-receipt-keeps-history-readable-and-balance-indeterminate",
"assertions": 2,
"passed": true
},
{
"name": "concurrent-confirmations-wait-and-replay-one-import",
"assertions": 7,
"passed": true
}
],
"tests": 10,
"assertions": 56,
"principal_minor": 6000,
"confirmed_minor": 3000,
"pending_minor": 1000,
"rejected_minor": 500,
"balance_minor": 3000,
"shared_engine_unchanged": true,
"native_source_preparation_only": true,
"actual_http_kernel_tested": false,
"browser_interactions_tested": false,
"visual_review": false,
"deployment_capacity_validated": false
},
"actual_http": {
"kind": "sgf_historical_payable_actual_http_kernel",
"assertions": 17,
"passed": true,
"existing_html_reused": true,
"csrf_and_context_enforced": true,
"reader_write_refused": true,
"no_pending_payment_decision_route_added": true,
"one_obligation_same_balance_after_replay": true,
"visual_review": false,
"browser_interactions_tested": false
},
"postchecks": {
"native": {
"originals_unchanged": true,
"originals_sha256": "7cc42c8ce33ac04623ed50defde66083c1134903e4f11cd6825f10082214dc17",
"native_obligations": 0,
"payments": [
"confirmed",
"pending",
"rejected"
],
"read_only_observation": true
},
"sgf": {
"read_only": true,
"one_obligation": true,
"one_history_import": true,
"original_source_unchanged": true,
"source_receipt_sha256": "89120aea0ad23e3f1454f87e905d8ccb80123e04636f5e2cd60e71015fa7c376",
"imported_payments": 3,
"states": [
"confirmed",
"pending",
"rejected"
],
"recognition_events": 1,
"history_events": 1,
"principal_minor": 6000,
"confirmed_minor": 3000,
"pending_minor": 1000,
"rejected_minor": 500,
"pending_decision_schema_installed": false,
"default_feature_enabled": false
}
},
"private_evidence_sha256": {
"source.json": "bae0a2ab8bc0f6ff2b02fc1bab80192aa96e24d6babe879a278c093e642e02e7",
"regression.json": "3cb8d648249e22c00447602107c1939abc03650173a6d11ccb0f23df59e0fe44",
"http-proof.json": "86783db1c62563f7e718297d1cbefa5d850dc00cd1f85db83491cee040f1b27a",
"native-post.json": "b7952b8c7f6dae5fa0ae4a38d5c3fc29c87d77ed4d4f345a9e72dd7bc401c812",
"sgf-post.json": "a9507f617e22ec497c2d7b9a62a2f8bab6ae4218d4290708b4cd41ac88ecc6af"
},
"source_provenance": {
"actual_native_receipt_and_invoice_workflows": true,
"actual_original_payment_registration_and_independent_review": true,
"native_history_capture_by_existing_engine": true,
"native_common_obligation_recognised": false,
"source_only_fresh_owned_qa_database": true,
"bank_details_and_encrypted_references_not_exported": true,
"receipt_checksum_proves_integrity_not_external_authenticity": true,
"sgf_receipt_mapping_explicit_in_qa_seed": true
},
"scenario": {
"currency": "MZN",
"principal_minor": 6000,
"confirmed_minor": 3000,
"pending_minor": 1000,
"rejected_minor": 500,
"balance_minor": 3000,
"due_on": null,
"days_overdue": null,
"no_pending_payment_decision": true,
"no_new_financial_engine": true
},
"concurrency": {
"processes": 2,
"company_row_blocker_observed_with_pg_blocking_pids": true,
"second_waited_then_replayed_original": true,
"obligations": 1,
"history_imports": 1,
"imported_payments": 3
},
"isolation": {
"dedicated_native_and_sgf_databases": true,
"port": 55439,
"restricted_qa_roles": true,
"read_write_permission_and_company_context_revalidated": true,
"no_real_or_demo_access_grants": true
},
"source_sha256": {
"app/Modules/Purchasing/SupplierHistoryReceipts.php": "002966f5559261d79d57c600d8cdde31d701e0beb812e04b4ac5cea48f6cfc47",
"app/Modules/Purchasing/SupplierPayables.php": "5f5c11df105400c7f658bb0c0b91cb23d4fd54104ceadfc3432846b5ba66d573",
"config/supplier_payable_history.php": "5331b7987fdb5f8fdb9647e6cf74145f91aca333a7e4c21f98092827893b85ce",
"app/Modules/Purchasing/SupplierPayablesController.php": "a2adad624794a96d22358ff8e9a5e64846b68111674ed2cef9fd8cf7afafb883",
"routes/web.php": "33f1e1c11d978d018e33dd57e284d0038b95cdb2bf91a99bd4bfcbabc6d80993",
"packages/payables/src/Payables.php": "dafc76371767b0a9794f0822553e60392a8aa2c270dea8d78ff701a56f5f5bc9",
"packages/payables/src/HistoricalPayments.php": "59576afb1b2209fe08e4d1d45be22e364746a815316749ddcfa19930281dbb3d",
"packages/payables/ui/page.php": "a6757dda5b59eea4ae8565bbbfb2eba6cdd56b1e11ccff4a3943323a520deb9e",
"scripts/payable-history-sgf-run.mjs": "677621591056e057f2e76625f22030e7a5099739424b60e1d45b2628ad616622",
"scripts/payable-history-sgf-proof.php": "0abd69b6595959413c3a33150c6cdde1add8a81ea378fec4d56f42c103b2d1b8",
"scripts/payable-history-sgf-cases.php": "22324185e398e62b3d7207dea4dbb74b7e47f5a581d6335f10e1fd7114e2ec11",
"scripts/payable-history-sgf-http.mjs": "ff2f965d27e3ff60cb02fa87bedf00ea17362dbde032972e574a4749905d3fb0",
"scripts/payable-history-sgf-http-router.php": "82b110af26e4dcfcdf1b078108adb701ca51711485c7a385c726a5812a8b9afe"
},
"reused_proofs": {
"docs/proofs/workshop-stock-closure-20261102.json": "261d5502f6905d53ef8046e0e900c9bee159c8c9d7e1bae4fddd8ec698313bf7",
"docs/proofs/native-warehouse-return-20261102.json": "587795ab4d2b2e65d51feaf7ed5e368df715d69cb7a0480f5f2b1d802d019869",
"docs/proofs/module-association-http-lock-summary-20261102.json": "67547007f8f9df853639751983c5a6fd0841044cb0e04a7628db04c4b67692c6"
},
"verification_scope": "Ten directed scenarios (56 assertions) plus 17 actual HTTP checks. Current adapter callbacks, shared controller/UI, receipt validation and concurrency exercised. Native original facts postchecked read-only. Earlier suites not repeated; no JavaScript or Vite build required for this PHP/template change.",
"preservation": {
"six_pending_associations_untouched": true,
"blocked_cache_untouched": true,
"demos_and_installed_databases_untouched": true,
"previous_proofs_preserved": true,
"no_real_migration_or_rights": true,
"qa_databases_and_evidence_retained": true,
"purchasing_activation": false,
"publication": false,
"checkpoint": false
},
"limits": [
"Reads explicitly seeded immutable historical receipts, not live native payment history.",
"No operational receipt publisher/importer, authentication of external provenance or responsibility cutover installed. Hashes alone do not authenticate an external source.",
"No common financial obligation was recognised in the native source; this is QA adapter evidence, not proof that simultaneously operated native/SGF installations share financial authority.",
"Pending/rejected original payments retain state; imported pending-payment decisions, new payments and banking are not added in SGF.",
"Existing financial listing remains unpaginated; no load/capacity claim or general financial consolidation claim.",
"No accounting postings, operational activation, browser interaction or visual review."
],
"visual_review_pending": true,
"deployment_capacity_validated": false
}
@@ -0,0 +1,104 @@
{
"runtime_role": "sgf_dev_app",
"confirmation_required": true,
"automatically_applied": false,
"statements": [
"REVOKE ALL PRIVILEGES ON TABLE public.\"cb_centres\" FROM \"sgf_dev_app\"",
"REVOKE ALL PRIVILEGES ON TABLE public.\"cb_centres\" FROM PUBLIC",
"GRANT SELECT, INSERT ON TABLE public.\"cb_centres\" TO \"sgf_dev_app\"",
"REVOKE ALL PRIVILEGES ON SEQUENCE public.\"cb_centres_id_seq\" FROM \"sgf_dev_app\"",
"REVOKE ALL PRIVILEGES ON SEQUENCE public.\"cb_centres_id_seq\" FROM PUBLIC",
"GRANT USAGE ON SEQUENCE public.\"cb_centres_id_seq\" TO \"sgf_dev_app\"",
"REVOKE ALL PRIVILEGES ON TABLE public.\"cb_origins\" FROM \"sgf_dev_app\"",
"REVOKE ALL PRIVILEGES ON TABLE public.\"cb_origins\" FROM PUBLIC",
"GRANT SELECT, INSERT ON TABLE public.\"cb_origins\" TO \"sgf_dev_app\"",
"REVOKE ALL PRIVILEGES ON SEQUENCE public.\"cb_origins_id_seq\" FROM \"sgf_dev_app\"",
"REVOKE ALL PRIVILEGES ON SEQUENCE public.\"cb_origins_id_seq\" FROM PUBLIC",
"GRANT USAGE ON SEQUENCE public.\"cb_origins_id_seq\" TO \"sgf_dev_app\"",
"REVOKE ALL PRIVILEGES ON TABLE public.\"cb_budgets\" FROM \"sgf_dev_app\"",
"REVOKE ALL PRIVILEGES ON TABLE public.\"cb_budgets\" FROM PUBLIC",
"GRANT SELECT, INSERT, UPDATE ON TABLE public.\"cb_budgets\" TO \"sgf_dev_app\"",
"REVOKE ALL PRIVILEGES ON SEQUENCE public.\"cb_budgets_id_seq\" FROM \"sgf_dev_app\"",
"REVOKE ALL PRIVILEGES ON SEQUENCE public.\"cb_budgets_id_seq\" FROM PUBLIC",
"GRANT USAGE ON SEQUENCE public.\"cb_budgets_id_seq\" TO \"sgf_dev_app\"",
"REVOKE ALL PRIVILEGES ON TABLE public.\"cb_budget_entries\" FROM \"sgf_dev_app\"",
"REVOKE ALL PRIVILEGES ON TABLE public.\"cb_budget_entries\" FROM PUBLIC",
"GRANT SELECT, INSERT ON TABLE public.\"cb_budget_entries\" TO \"sgf_dev_app\"",
"REVOKE ALL PRIVILEGES ON SEQUENCE public.\"cb_budget_entries_id_seq\" FROM \"sgf_dev_app\"",
"REVOKE ALL PRIVILEGES ON SEQUENCE public.\"cb_budget_entries_id_seq\" FROM PUBLIC",
"GRANT USAGE ON SEQUENCE public.\"cb_budget_entries_id_seq\" TO \"sgf_dev_app\"",
"REVOKE ALL PRIVILEGES ON TABLE public.\"cb_audit\" FROM \"sgf_dev_app\"",
"REVOKE ALL PRIVILEGES ON TABLE public.\"cb_audit\" FROM PUBLIC",
"GRANT SELECT, INSERT ON TABLE public.\"cb_audit\" TO \"sgf_dev_app\"",
"REVOKE ALL PRIVILEGES ON SEQUENCE public.\"cb_audit_id_seq\" FROM \"sgf_dev_app\"",
"REVOKE ALL PRIVILEGES ON SEQUENCE public.\"cb_audit_id_seq\" FROM PUBLIC",
"GRANT USAGE ON SEQUENCE public.\"cb_audit_id_seq\" TO \"sgf_dev_app\"",
"REVOKE ALL PRIVILEGES ON TABLE public.\"cb_ui_commands\" FROM \"sgf_dev_app\"",
"REVOKE ALL PRIVILEGES ON TABLE public.\"cb_ui_commands\" FROM PUBLIC",
"GRANT SELECT, INSERT ON TABLE public.\"cb_ui_commands\" TO \"sgf_dev_app\"",
"REVOKE ALL PRIVILEGES ON SEQUENCE public.\"cb_ui_commands_id_seq\" FROM \"sgf_dev_app\"",
"REVOKE ALL PRIVILEGES ON SEQUENCE public.\"cb_ui_commands_id_seq\" FROM PUBLIC",
"GRANT USAGE ON SEQUENCE public.\"cb_ui_commands_id_seq\" TO \"sgf_dev_app\"",
"REVOKE ALL PRIVILEGES ON TABLE public.\"cb_budget_consumptions\" FROM \"sgf_dev_app\"",
"REVOKE ALL PRIVILEGES ON TABLE public.\"cb_budget_consumptions\" FROM PUBLIC",
"GRANT SELECT ON TABLE public.\"cb_budget_consumptions\" TO \"sgf_dev_app\"",
"REVOKE ALL PRIVILEGES ON SEQUENCE public.\"cb_budget_consumptions_id_seq\" FROM \"sgf_dev_app\"",
"REVOKE ALL PRIVILEGES ON SEQUENCE public.\"cb_budget_consumptions_id_seq\" FROM PUBLIC",
"REVOKE ALL PRIVILEGES ON TABLE public.\"cb_budget_reinforcements\" FROM \"sgf_dev_app\"",
"REVOKE ALL PRIVILEGES ON TABLE public.\"cb_budget_reinforcements\" FROM PUBLIC",
"GRANT SELECT ON TABLE public.\"cb_budget_reinforcements\" TO \"sgf_dev_app\"",
"REVOKE ALL PRIVILEGES ON SEQUENCE public.\"cb_budget_reinforcements_id_seq\" FROM \"sgf_dev_app\"",
"REVOKE ALL PRIVILEGES ON SEQUENCE public.\"cb_budget_reinforcements_id_seq\" FROM PUBLIC",
"REVOKE ALL PRIVILEGES ON TABLE public.\"cb_consumption_sources\" FROM \"sgf_dev_app\"",
"REVOKE ALL PRIVILEGES ON TABLE public.\"cb_consumption_sources\" FROM PUBLIC",
"GRANT SELECT ON TABLE public.\"cb_consumption_sources\" TO \"sgf_dev_app\"",
"REVOKE ALL PRIVILEGES ON SEQUENCE public.\"cb_consumption_sources_id_seq\" FROM \"sgf_dev_app\"",
"REVOKE ALL PRIVILEGES ON SEQUENCE public.\"cb_consumption_sources_id_seq\" FROM PUBLIC",
"REVOKE ALL PRIVILEGES ON TABLE public.\"ir_requests\" FROM \"sgf_dev_app\"",
"REVOKE ALL PRIVILEGES ON TABLE public.\"ir_requests\" FROM PUBLIC",
"GRANT SELECT, INSERT, UPDATE ON TABLE public.\"ir_requests\" TO \"sgf_dev_app\"",
"REVOKE ALL PRIVILEGES ON SEQUENCE public.\"ir_requests_id_seq\" FROM \"sgf_dev_app\"",
"REVOKE ALL PRIVILEGES ON SEQUENCE public.\"ir_requests_id_seq\" FROM PUBLIC",
"GRANT USAGE ON SEQUENCE public.\"ir_requests_id_seq\" TO \"sgf_dev_app\"",
"REVOKE ALL PRIVILEGES ON TABLE public.\"ir_steps\" FROM \"sgf_dev_app\"",
"REVOKE ALL PRIVILEGES ON TABLE public.\"ir_steps\" FROM PUBLIC",
"GRANT SELECT, INSERT, UPDATE ON TABLE public.\"ir_steps\" TO \"sgf_dev_app\"",
"REVOKE ALL PRIVILEGES ON SEQUENCE public.\"ir_steps_id_seq\" FROM \"sgf_dev_app\"",
"REVOKE ALL PRIVILEGES ON SEQUENCE public.\"ir_steps_id_seq\" FROM PUBLIC",
"GRANT USAGE ON SEQUENCE public.\"ir_steps_id_seq\" TO \"sgf_dev_app\"",
"REVOKE ALL PRIVILEGES ON TABLE public.\"ir_policies\" FROM \"sgf_dev_app\"",
"REVOKE ALL PRIVILEGES ON TABLE public.\"ir_policies\" FROM PUBLIC",
"GRANT SELECT, INSERT, UPDATE ON TABLE public.\"ir_policies\" TO \"sgf_dev_app\"",
"REVOKE ALL PRIVILEGES ON SEQUENCE public.\"ir_policies_id_seq\" FROM \"sgf_dev_app\"",
"REVOKE ALL PRIVILEGES ON SEQUENCE public.\"ir_policies_id_seq\" FROM PUBLIC",
"GRANT USAGE ON SEQUENCE public.\"ir_policies_id_seq\" TO \"sgf_dev_app\"",
"REVOKE ALL PRIVILEGES ON TABLE public.\"ir_events\" FROM \"sgf_dev_app\"",
"REVOKE ALL PRIVILEGES ON TABLE public.\"ir_events\" FROM PUBLIC",
"GRANT SELECT, INSERT ON TABLE public.\"ir_events\" TO \"sgf_dev_app\"",
"REVOKE ALL PRIVILEGES ON SEQUENCE public.\"ir_events_id_seq\" FROM \"sgf_dev_app\"",
"REVOKE ALL PRIVILEGES ON SEQUENCE public.\"ir_events_id_seq\" FROM PUBLIC",
"GRANT USAGE ON SEQUENCE public.\"ir_events_id_seq\" TO \"sgf_dev_app\"",
"REVOKE ALL PRIVILEGES ON TABLE public.\"ir_commands\" FROM \"sgf_dev_app\"",
"REVOKE ALL PRIVILEGES ON TABLE public.\"ir_commands\" FROM PUBLIC",
"GRANT SELECT, INSERT ON TABLE public.\"ir_commands\" TO \"sgf_dev_app\"",
"REVOKE ALL PRIVILEGES ON SEQUENCE public.\"ir_commands_id_seq\" FROM \"sgf_dev_app\"",
"REVOKE ALL PRIVILEGES ON SEQUENCE public.\"ir_commands_id_seq\" FROM PUBLIC",
"GRANT USAGE ON SEQUENCE public.\"ir_commands_id_seq\" TO \"sgf_dev_app\"",
"REVOKE ALL PRIVILEGES ON TABLE public.\"ir_policy_versions\" FROM \"sgf_dev_app\"",
"REVOKE ALL PRIVILEGES ON TABLE public.\"ir_policy_versions\" FROM PUBLIC",
"GRANT SELECT, INSERT ON TABLE public.\"ir_policy_versions\" TO \"sgf_dev_app\"",
"REVOKE ALL PRIVILEGES ON SEQUENCE public.\"ir_policy_versions_id_seq\" FROM \"sgf_dev_app\"",
"REVOKE ALL PRIVILEGES ON SEQUENCE public.\"ir_policy_versions_id_seq\" FROM PUBLIC",
"GRANT USAGE ON SEQUENCE public.\"ir_policy_versions_id_seq\" TO \"sgf_dev_app\"",
"REVOKE ALL PRIVILEGES ON TABLE public.\"sgc_installations\" FROM \"sgf_dev_app\"",
"REVOKE ALL PRIVILEGES ON TABLE public.\"sgc_installations\" FROM PUBLIC",
"GRANT SELECT ON TABLE public.\"sgc_installations\" TO \"sgf_dev_app\""
],
"excluded": [
"CREATE",
"ownership",
"DELETE",
"UPDATE on append-only history",
"all-tables/default-privileges grants"
]
}
@@ -0,0 +1,421 @@
{
"passed": true,
"checks": [
"reproduced current 87-table schema without source rows",
"no accounts or grants imported from destination",
"runtime cannot create schema objects",
"injected dependency migration failure",
"failed migration restores original schema and identity data",
"successful migration preserves existing identity and grants",
"installation creates empty centres and allocations",
"runtime module SQL access denied before test-only privilege plan",
"minimal runtime excludes historical update and requisition deletion",
"runtime reads corrected revision without ownership",
"provider really loaded from isolated copy",
"new bundle bootstrap accepted by installer integrity check",
"anonymous direct initialisation URL denied",
"native clone authentication 1",
"native clone context 1",
"native clone authentication 2",
"native clone context 2",
"provider registers initial authority page without prior functional rights",
"initial authority CSRF enforced",
"initial authority through normal middleware",
"work page requires explicit module selection",
"new requisition view right makes purchasing selectable",
"stale module generation refused",
"provider registers operational work page",
"different enterprise option refused by operational composition",
"native administrative delegation purchasing_requisitions.view",
"native administrative delegation purchasing_requisitions.approve.department_head",
"native administrative delegation purchasing_budget.view",
"native administrative delegation purchasing_budget.approve",
"empty installation exposes authorised centre and budget preparation",
"centre created through authorised UI API with runtime role",
"centre retries preserve one source",
"existing budget API prepares synthetic allocation",
"budget approval requires independent identity",
"independent allocation approval uses existing budget kernel",
"workspace dependencies available on reproduced schema",
"direct budget movements cannot bypass requisition lifecycle",
"operational policy configured via HTTP",
"integrated operational draft",
"integrated submit uses existing budget adapter",
"integrated independent identity enforced",
"integrated approval by another identity",
"integrated authorised consultation and history",
"native administration receives complete unit catalogue",
"native administration receives canonical server labels",
"reviewer cannot inspect administrative catalogue without management right",
"forged delegation of an unowned catalogue right refused",
"packaged frontend dependency served before authentication",
"packaged frontend dependency served before authentication",
"native SGF entry renders the packaged frontend manifest",
"undeclared frontend asset refused",
"minimal plan removes inherited update and delete on new append-only sources",
"runtime cannot truncate requisitions",
"existing table ACL preserved a_billing_drafts",
"existing table ACL preserved a_clients",
"existing table ACL preserved a_commands",
"existing table ACL preserved a_events",
"existing table ACL preserved a_history",
"existing table ACL preserved a_outbox",
"existing table ACL preserved a_pending",
"existing table ACL preserved a_service_drafts",
"existing table ACL preserved a_services",
"existing table ACL preserved b_internal_confirmations",
"existing table ACL preserved ca_commands",
"existing table ACL preserved ca_decisions",
"existing table ACL preserved ca_proposals",
"existing table ACL preserved ca_resolutions",
"existing table ACL preserved ca_submissions",
"existing table ACL preserved cache",
"existing table ACL preserved cache_locks",
"existing table ACL preserved companies",
"existing table ACL preserved company_memberships",
"existing table ACL preserved dc_calculations",
"existing table ACL preserved dc_commands",
"existing table ACL preserved dc_decisions",
"existing table ACL preserved dc_events",
"existing table ACL preserved dc_outbox",
"existing table ACL preserved dc_rates",
"existing table ACL preserved doc_history",
"existing table ACL preserved doc_records",
"existing table ACL preserved document_preview_model_history",
"existing table ACL preserved document_preview_models",
"existing table ACL preserved failed_jobs",
"existing table ACL preserved ib_budgets",
"existing table ACL preserved ib_commands",
"existing table ACL preserved ib_comparisons",
"existing table ACL preserved ib_decisions",
"existing table ACL preserved ib_events",
"existing table ACL preserved ib_outbox",
"existing table ACL preserved ic_commands",
"existing table ACL preserved ic_decisions",
"existing table ACL preserved ic_events",
"existing table ACL preserved ic_inputs",
"existing table ACL preserved ic_lots",
"existing table ACL preserved ic_outbox",
"existing table ACL preserved ic_products",
"existing table ACL preserved ic_results",
"existing table ACL preserved identity_audit",
"existing table ACL preserved job_batches",
"existing table ACL preserved jobs",
"existing table ACL preserved migrations",
"existing table ACL preserved password_reset_tokens",
"existing table ACL preserved permission_grants",
"existing table ACL preserved service_calculation_profiles",
"existing table ACL preserved service_calculation_results",
"existing table ACL preserved sessions",
"existing table ACL preserved sf_activation_events",
"existing table ACL preserved sf_decisions",
"existing table ACL preserved sf_proposals",
"existing table ACL preserved si_commands",
"existing table ACL preserved si_correction_requests",
"existing table ACL preserved si_counters",
"existing table ACL preserved si_decisions",
"existing table ACL preserved si_events",
"existing table ACL preserved si_invoices",
"existing table ACL preserved si_outbox",
"existing table ACL preserved si_proposals",
"existing table ACL preserved sr_commands",
"existing table ACL preserved sr_deliveries",
"existing table ACL preserved sr_effects",
"existing table ACL preserved sr_events",
"existing table ACL preserved sr_outbox",
"existing table ACL preserved sr_records",
"existing table ACL preserved tenants",
"existing table ACL preserved units",
"existing table ACL preserved users",
"existing table ACL preserved wb_claims",
"existing table ACL preserved wb_commands",
"existing table ACL preserved wb_decisions",
"existing table ACL preserved wb_events",
"existing table ACL preserved wb_generations",
"existing table ACL preserved wb_outbox",
"existing table ACL preserved wb_proposals",
"existing table ACL preserved wo_commands",
"existing table ACL preserved wo_decisions",
"existing table ACL preserved wo_entries",
"existing table ACL preserved wo_equipment",
"existing table ACL preserved wo_events",
"existing table ACL preserved wo_orders",
"existing table ACL preserved wo_outbox",
"actual runtime CREATE denied",
"actual runtime ALTER of identity catalogue denied",
"centre creation requires own configuration and budget rights",
"centre context cannot be forged",
"refused centre operations leave original source intact",
"unsupported requisition type refused equipment",
"unsupported requisition type refused part",
"approved lifecycle covers the three supported basic types",
"unsupported types create neither a second request nor reservation",
"native revocation applies to direct module URL",
"uncontracted module refused at server",
"disabled composition exposes no executable work page",
"code-only successor installed over existing provenance",
"code-only successor rollback restores exact candidate",
"code update and rollback preserve every reproduced data table",
"code recovery preserves submitted origin decision and reservation",
"code recovery leaves baseline and maintenance intact"
],
"clone": "C:\\Users\\macbook\\AppData\\Local\\Temp/sgf-update-625f1bba6e30",
"data_fingerprints": {
"a_billing_drafts": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"a_clients": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"a_commands": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"a_events": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"a_history": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"a_outbox": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"a_pending": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"a_service_drafts": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"a_services": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"b_internal_confirmations": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"ca_commands": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"ca_decisions": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"ca_proposals": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"ca_resolutions": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"ca_submissions": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"cache": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"cache_locks": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"cb_audit": "ccf5b17cacb6e9d1cbbebdc55baca6b2b51103f3573c32dd1bddb24a055d2e2b",
"cb_budget_consumptions": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"cb_budget_entries": "ba73d3b7eb20c25d833df7b3b85f7f1f7575d78365ee1a3c2246e7749f2448ad",
"cb_budget_reinforcements": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"cb_budgets": "8df00e7e6b821e2767118c352f58391d4c44bb8df1fcc38a3d40a6a9989543a5",
"cb_centres": "45bebc4ca0d417711e2a428b360c343e6dba17a64a4d799639165815e5aaef45",
"cb_consumption_sources": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"cb_origins": "f470bed486f1955724e99cde0404445c4b9753320faee2d202289fedffc4d561",
"cb_ui_commands": "424c4f2f643087911333a3ecf002bbb5fc5055c5ccf24f5cefd94c9db56b398b",
"companies": "e5098861f02b2904e068c604ecbe1379ec6597b39fcdc9575c9d9eaa3b459aec",
"company_memberships": "562084217604e0bd153e36375251db9e4e87f92c744c69d38d2a39c7821454e5",
"dc_calculations": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"dc_commands": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"dc_decisions": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"dc_events": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"dc_outbox": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"dc_rates": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"doc_history": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"doc_records": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"document_preview_model_history": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"document_preview_models": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"failed_jobs": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"ib_budgets": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"ib_commands": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"ib_comparisons": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"ib_decisions": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"ib_events": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"ib_outbox": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"ic_commands": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"ic_decisions": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"ic_events": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"ic_inputs": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"ic_lots": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"ic_outbox": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"ic_products": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"ic_results": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"identity_audit": "b714264c1c89e456f9217c285169fa91bc379bb744684e39c2028bb48a025ca7",
"ir_commands": "fa90f00d334ae11e38a4aea327720569da50f196ad5aa4876fcaa0b6154d78ad",
"ir_events": "8379dcb6a4fb3d1cad80cab5a4afe9a49b86a7145e2dc613d6d5371d18e96051",
"ir_policies": "7ff4f648cbf36386f78743ed2394eb12e6328fb6e7722c6ba1acb5fab36ca1d1",
"ir_policy_versions": "7ff4f648cbf36386f78743ed2394eb12e6328fb6e7722c6ba1acb5fab36ca1d1",
"ir_requests": "874bbaa494e41ddc2bee527f3660909123a19c270f7eaee0e19d534d8c355fd6",
"ir_steps": "dcde70900864b1e974f66a4778e80e8317907c14a3dc0545afadb468c6f9eef6",
"job_batches": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"jobs": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"migrations": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"password_reset_tokens": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"permission_grants": "2219ad7945c6cd3d4e28bfc4a06c04eb6141ceaa53097efd01ab5f89811fec13",
"service_calculation_profiles": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"service_calculation_results": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"sessions": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"sf_activation_events": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"sf_decisions": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"sf_proposals": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"sgc_installations": "75449b61764076870970ddf93e9b987e6b7b24889de47fb8d9046a5345065f1c",
"si_commands": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"si_correction_requests": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"si_counters": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"si_decisions": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"si_events": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"si_invoices": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"si_outbox": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"si_proposals": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"sr_commands": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"sr_deliveries": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"sr_effects": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"sr_events": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"sr_outbox": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"sr_records": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"tenants": "0487a4884eb77b28bd8c052e9d2bd1a8177bab511463657d326a17c0c77b3619",
"units": "c0a43a3bf8907bcbebf727f089e8c75399ed7a94049ad85b666fe6b90851842e",
"users": "ea313e4a8b0a16e17dc1b61cea28c6832a76feed78540fe40ab61bbf88c6200c",
"wb_claims": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"wb_commands": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"wb_decisions": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"wb_events": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"wb_generations": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"wb_outbox": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"wb_proposals": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"wo_commands": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"wo_decisions": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"wo_entries": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"wo_equipment": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"wo_events": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"wo_orders": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
"wo_outbox": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945"
},
"destination_activated": false,
"normal_provider_routes": true,
"browser_used": false,
"data_recovery": {
"verified": true,
"tables_reconciled": 103,
"approved_origin_reservation_versions_preserved": true,
"runtime_read_verified": true,
"runtime_ddl_denied": true,
"schema_and_triggers_verified": true,
"sql_acl_reapplied_only_to_isolated_role": true
},
"destination_security_and_schema_preserved": true,
"artifact": {
"directory": "C:\\laragon\\www\\compras/storage/app/private/candidates/OPERATIONAL-CANDIDATE-401ce31ae5f2dd20",
"archive": {
"file": "C:\\laragon\\www\\compras/storage/app/private/candidate-archives/OPERATIONAL-CANDIDATE-401ce31ae5f2dd20.zip",
"sha256": "59dbdc64c4d9f14dfb4025a6177b829d136a4e2cb633ca036b10b5ae3197e703",
"manifest_sha256": "a6478223e17a5430652f0fcbf31a44a931ae2a99cd90b151c98d2df5df43c10b"
},
"installed": false
},
"source_schema_tables": 87,
"source_rows_exported": 0,
"source_schema_sha256": "b530e03c759305247f46cdad5013e64a6caae00bded3d9d5ae5b7b5aa06a4647",
"runtime_and_migrator_separate": true,
"destination_version": "0.1.1",
"destination_changed": false,
"prior_proofs_reused": true,
"checked_at": "2026-11-02T07:10:03+00:00",
"test_database_and_roles_removed": true,
"ui_render": {
"passed": true,
"checks": [
"native selector offers server catalogue requisition right",
"native selector uses server labels",
"budget creation right has server label",
"preparer cannot delegate budget approval",
"preparer cannot delegate absent decision authority",
"reviewer sees only own approval grant",
"reviewer cannot delegate preparation",
"foreign unit grant never becomes a local option",
"client cannot invent a catalogue entry from a grant",
"no hardcoded new rights before server catalogue loads",
"existing grants render their server labels",
"general navigation remains separate",
"module entry links to requisition only under own right",
"frontend asset bound to installed bundle",
"referenced compiled dependency included",
"frontend asset bound to installed bundle",
"referenced compiled dependency included"
],
"browser_used": false,
"source_host_modified": false
},
"navigation": {
"functional_commit": "2a4169162bb4621a42a2ea1df627d52f860e7176",
"documentary_commit": "fcf0ada22701337acd4c84b404207b8400f490a2",
"host_file_sha256": {
"app/Shared/Context/ModuleNavigation.php": "f75f323940e25826792dc88848fd2b77eb3325634100a86b14c60c5d381917a3",
"app/Shared/Context/ModuleRecords.php": "1813591487e3fb1885622f1078e80734d1745f427d2bf8fa93ebc0d96974b0d6",
"app/Shared/Context/RequireModuleContext.php": "610b65868ad25d1e6f736d03d7c1da44245648ff22873f1c957c794490009192",
"app/Modules/Identity/Http/RequireCompanyContext.php": "3fcc9d4d4466d3b6883dd60cc3e63e9bb2f58a43d13ca550d79e35882562db71",
"app/Modules/Identity/Http/ModuleRecordsController.php": "f10ee4a14ed19e461bfc819288cd2f701e9d73ce4421a18f1b11e1ca545726fb",
"app/Modules/Identity/Services/Audit.php": "89d69975b3059a3aedbeff0aca1febbb92c6c135030c31b0cc4bdd8d7e602ecb",
"app/Modules/Identity/Services/IdentityWorkflow.php": "c4f4af9a7625778a408d881ba087502b116fa0ccb15f2f0311f5a0e8ad40ce73",
"resources/js/ModuleNavigation.jsx": "b53ee2d9f69a96bdabf1d3074f8662fd204c447caf8f354aea4dcf921bd336be",
"resources/js/WorkspaceNavigation.jsx": "7be946f915e3dabfb511445f169fe822c2e558ca15fef6331c247af2a1643ebf",
"resources/js/app.jsx": "33f087da73fe80ca0ae6e7609e107b805b2c8a1f1863cc3a1b2c7886fe7d3c44",
"resources/js/WorkspaceHome.jsx": "c02d71c6e630f942c13562427c7256e1b7602c75b80b462d184d45852d9ea34a",
"resources/js/ModuleRecordsWorkspace.jsx": "24399a5e6a08c78357f23fc6d304a706f477f33db879a4cf52fc53511541b78c",
"resources/js/ContextTransitionDialog.jsx": "04bde71f2ea5d26185aae930bfcf8978e5d38d1637915073cacbc12033fe9780",
"resources/js/context-transition.js": "3d76e21eca185ae97c1a6a6f5965ab33c242a28391c8c50f5af30dfc0a4a3c6a",
"resources/css/tempo-theme.css": "4b961ce49b2bb50072ea1fcae0c0d168c9ada207f59323cc52205353b7871df9",
"public/sgf-module-context.js": "f465ea30ecea0acf3fc7b838b602ea881260d73b90aa48f587327b8ee1581dc7",
"config/modules.php": "31330076b98ca423acfef0fa4e1c87a3762e53a750bd3f94c2b5a7d53e3edde4",
"routes/web.php": "aa314a92c7f926c56699880d795286a0dd9659e6fbc0f653529e2f58a1bb326c",
"tests/Feature/ModuleNavigationTest.php": "7f7655950d5847ed5702f95613061e7591a353f97d3349921625b8805822bfd4"
}
},
"installed_snapshot": {
"database": {
"database": "sgf_tempo_dev",
"role": "sgf_dev_app",
"port": 55432
},
"tables": {
"permission_grants": {
"rows": 89,
"fingerprint": "f4546a8af83c965f7088ba47f55e0fec"
},
"company_memberships": {
"rows": 2,
"fingerprint": "f5462c7d3b1f5c75d70450dc6b61990e"
},
"identity_audit": {
"rows": 162,
"fingerprint": "cbff39d0e77e9bd7c3cafb4a5d574591"
}
},
"guard_sha256": "42708432fa029e3e52743016b6c6b6d734a3e6cd5d3ed266a29ecfcf38a6e371",
"purchasing_pointer_sha256": "81899e531e9eec449717e694d8bdc106a9e220a828f5491ce918c1d2dc612787"
},
"host_overlays": {
"app/Modules/Identity/Services/Permissions.php": {
"before_sha256": "97a860b632de0cb5022b2d9153261ecfa2211c100961eb6b9e6a09d30f798e63",
"after_sha256": "19e40f47e2df222c3151d99a7840f86e3ec00c4fe021f53301bc1482ab3d5670"
},
"app/Modules/Identity/Services/IdentityWorkflow.php": {
"before_sha256": "c4f4af9a7625778a408d881ba087502b116fa0ccb15f2f0311f5a0e8ad40ce73",
"after_sha256": "0d0e6e90748cf1cd93bc724fb0bd51573ab1377ca6d1eb3360219b3d5fd0c25d"
},
"app/Modules/Purchasing/BudgetAdapter.php": {
"before_sha256": "e8f261e2e6535973c72266cf5f448e24794e5c896a9910ca85468001fbc37116",
"after_sha256": "cea6b4f8e7b9b96854de79ba3085b69affc7855cda46ded67b4b22fd62dd38f9"
},
"app/Modules/Purchasing/BudgetWorkspace.php": {
"before_sha256": "b144422b959cd6c6f693001ccdd5a21e163a88732a17b00cb6d8d7a8cf0562de",
"after_sha256": "ecec7e3880b2fec46d1cdc3a346c965b2d489c48cc32077ae28ec7c2027182be"
},
"app/Providers/AppServiceProvider.php": {
"before_sha256": "42705455c3f12233369275cbfd7d80781109135ca1ef2d3e3adc2fac8d675e8e",
"after_sha256": "463ef17bbbac91871b600c39dbf0309ed7a5795a450620b05823c3ad50acd2d3"
},
"app/Shared/Context/ModuleNavigation.php": {
"before_sha256": "f75f323940e25826792dc88848fd2b77eb3325634100a86b14c60c5d381917a3",
"after_sha256": "f15a8dc725aa4c1c6ab7eab6799446b7c79b35df237c2791791e7fe3c3830568"
},
"resources/js/app.jsx": {
"before_sha256": "33f087da73fe80ca0ae6e7609e107b805b2c8a1f1863cc3a1b2c7886fe7d3c44",
"after_sha256": "4b7ba24eca42e20db693ffdfe6825844406c6513932f8074edcf9c97b5562fa4"
},
"resources/js/PurchasingHome.jsx": {
"before_sha256": "3e985e7132525eb57b1a26baeb95c38aee7691051ddaf108e6faaa95efd22cbf",
"after_sha256": "10fe6d2265a9027fbe00d8ca1ffce9ca53aba40dc81467602cb5186489e5d86b"
},
"public/build/manifest.json": {
"before_sha256": "5a61b3b44fa0c04b624163b15d11ce8931de194847fcd901552ddc0806f57b85",
"after_sha256": "22c2708aab2c812cb20ec0c7b433fdb8383df2d0415684e2a55c47633ee4248b"
}
},
"read_only_plan": {
"code_target_sha256": "d29833b1c48b9d666522d20d87040d5ad30370cf114c9a70f272cd041eea59e9",
"schema_target_sha256": "169e6e863f28b67740f07b6e7cbc664fbe585a7760a83dccebc8d482ad8ab792"
},
"supersedes_proposal": "SGF-IR-INSTALL-5FAE-20261102",
"migration_sha256": "4ca4f5827c46e5ca29cb329c667df0b996ecbf5e318c0b157091c94e9d44ae92",
"integrity": {
"support_files_verified": 49,
"php_linted": 42,
"archive_and_manifest_unchanged": true
},
"installed_snapshot_matches_prior": true
}
@@ -0,0 +1,57 @@
{
"passed": true,
"checks": [
"portable review ZIP matches approved bundle and manifest",
"sem proveni\u00eancia",
"Transi\u00e7\u00e3o de schema",
"plan binds update to active installation",
"new version applied without source connection",
"previous version preserved locally",
"fora de ordem",
"vers\u00e3o activa",
"C\u00f3digo aplicado alterado",
"Conte\u00fado extra",
"rollback restores previous bundle exactly",
"rollback restores active provenance",
"new attempt preserves rolled-back journal",
"Injected update switch failure",
"interrupted transition recovers previous version",
"reapply creates a separate audited attempt",
"complete rollback restores original host composition",
"native Laravel config route and event caches built",
"version update invalidates previous native caches",
"Injected cache compilation interruption",
"partial native cache build is journalled under maintenance",
"cache CLI recovers interrupted native compilation",
"invalid partial config cache cannot block native recovery",
"cached deployment remains in native maintenance",
"cached module route survives restart and denies anonymous access",
"Cache mudou ap\u00f3s compila\u00e7\u00e3o",
"rollback invalidates registered rebuilt caches",
"repeated rollback preserves previous-version rebuilt caches",
"previous version restarts with native caches and maintenance",
"restarted baseline exposes no removed module route",
"baseline starts after cached deployment rollback",
"destination remains untouched on 0.1.1"
],
"old_candidate": "C:\\laragon\\www\\compras\/storage\/app\/private\/candidates\/OPERATIONAL-CANDIDATE-10dce6cd57fa1f31",
"new_candidate": "C:\\laragon\\www\\compras\/storage\/app\/private\/candidates\/OPERATIONAL-CANDIDATE-5fae7cf7f99c42ba",
"archive": {
"file": "C:\\laragon\\www\\compras\/storage\/app\/private\/candidate-archives\/OPERATIONAL-CANDIDATE-5fae7cf7f99c42ba.zip",
"sha256": "d14a3261d5aaab80f96250af781c700ab53376021f4638e3aee43c15ff37ceed",
"manifest_sha256": "b1ec47f7a9ad87e0b232bac41e402d4a00ee5f03f00a79b93effc692ce8b39a2"
},
"copies": [
"C:\\Users\\macbook\\AppData\\Local\\Temp\/sgf-update-46398e665d32",
"C:\\Users\\macbook\\AppData\\Local\\Temp\/sgf-update-21bc02db1fe2",
"C:\\Users\\macbook\\AppData\\Local\\Temp\/sgf-update-d88b6daafc0a",
"C:\\Users\\macbook\\AppData\\Local\\Temp\/sgf-update-schema-2df473386fc1"
],
"checked_at": "2026-11-02T06:32:56+00:00",
"destination_version": "0.1.1",
"destination_applied": false,
"prior_suites_repeated": false,
"actual_destination_services_touched": false,
"native_caches_built": true,
"isolated_server_restarts_verified": true
}
@@ -0,0 +1,157 @@
{
"date": "2026-11-02",
"increment": "COMMON-STOCK-READ-COMPOSITION-SIM-v1",
"status": "two_application_read_api_compositions_verified",
"package": {
"id": "tempo-inventory-read",
"version": "0.1.0",
"manifest_sha256": "bbd97f63b0eeb671bd3ad57bbd62bd34fcf67b8e943320423715d514a2a2c19c",
"files": {
"bootstrap.php": "65cba0924869ba93afa00a4786b361ad71d5c2e67bd021b3d1fda172b1190476",
"src/InventoryReader.php": "9b0591600da07719d655324ccf0b740f06de07db2806540684c9730d048e44b6",
"src/InventoryReadSession.php": "e5ea1ec6771e34478367218d73ba1d1d90464ddc87d1c5fa3d679622ffb81111"
},
"identical_verified_artifact": true,
"customer_dependency_on_sgf_source": false
},
"tests": {
"compras": {
"tests": 1,
"assertions": 73,
"errors": 0,
"failures": 0,
"sha256": "8424556122bc597b2de9a7af6fbaf18e278df4ebbf2f9eec9da82172f854c1af"
},
"sgf_functional": {
"tests": 2,
"assertions": 77,
"errors": 0,
"failures": 0,
"sha256": "093a0b0f6a59e86e86a1c0a70c7f92a78b3ba13a81cd4bb5bbb9e572ba10d649"
},
"two_composition_parity": {
"tests": 1,
"assertions": 48,
"errors": 0,
"failures": 0,
"sha256": "fce35672024498620638d783ca9bbef3949cafa2ea40de24ab53423ad03d03c3"
}
},
"cases": {
"view=items&per_page=25": {
"sha256": "0b1258720163f692a209578ca0c54efc960701272df814f4f435bf7cfebb799d",
"total": 101,
"equivalent": true
},
"view=items&per_page=100": {
"sha256": "3da79fc189150f7ce2b1977dadbc0b100aa956deaea9cc6366aa3cb35a134ef2",
"total": 101,
"equivalent": true
},
"view=warehouses&per_page=25": {
"sha256": "a612221561c03a3c2f5b3673d60df66647fa953a36531d0069dd5df2b1c8b36d",
"total": 2,
"equivalent": true
},
"view=warehouses&per_page=100": {
"sha256": "c3a7b2fe624c60f1d1f872ad743e6daf1b665fc1a652227d7f2d7bce38270014",
"total": 2,
"equivalent": true
},
"view=balances&per_page=25": {
"sha256": "f28f5bb8ab8ad9ac1f45c22a7ff743f7a87f25cac6734bc354910563237bfbcc",
"total": 100,
"equivalent": true
},
"view=balances&per_page=100": {
"sha256": "d33ef5f1cce5181f6bd6f5e3fa9bc57c719712e609001ce729f13fa182a0f554",
"total": 100,
"equivalent": true
},
"view=movements&per_page=25": {
"sha256": "db9ac3c0ba4acbcc90058fc0c836bd0778b3b77ec850cb686a9cd9ec6eaeaef5",
"total": 200,
"equivalent": true
},
"view=movements&per_page=100": {
"sha256": "9d1354e38caae00733732ab79f60637b88afce8633f244314ef515364838b6a0",
"total": 200,
"equivalent": true
},
"view=balances&per_page=25&page=2": {
"sha256": "8c5fbc2cee5d017612863fe1313e12df74d60933a9eef08a6b96f933a752fa3b",
"total": 100,
"equivalent": true
},
"view=items&per_page=25&page=5": {
"sha256": "9966a26f6f61c4a49c6787990867383326e6ebeb41319ed2e90a1ff86a0c66d0",
"total": 101,
"equivalent": true
},
"view=balances&warehouse_id=12": {
"sha256": "d23d7f73218fe90f1b07e734252e2bf135e7bb1dd03e6d039be6c63b6a6d129f",
"total": 0,
"equivalent": true
},
"view=items&search=QA-000001": {
"sha256": "33ee125e781da9e0d544853c57d24586fd7566cb7055e6790437a4fff59e1f36",
"total": 1,
"equivalent": true
}
},
"cross_host_token_refused": true,
"native_checks": {
"roles_and_configured_profiles": true,
"warehouse_isolation": true,
"stale_snapshot": true,
"unknown_source": true
},
"source_hashes": {
"sgf_adapter": "9df30b043568b8f2df1bb38346b19cfef5c5820282c4bf7c82536194c5669d74",
"compras_adapter": "06990fd57a265b57d031b130027c5814d8550665450d662a9dbee3e16ad295f4"
},
"preservation": {
"native_read_only_postcheck": {
"database": "stock_read_compras_c76629d0f45d",
"role": "stock_read_qa_c76629d0f45d",
"cluster": "sgf_modular_regression_2576427d1939",
"superuser": false,
"create_database": false,
"create_role": false,
"replication": false,
"bypass_rls": false
},
"sgf_read_only_postcheck": {
"identity": {
"database": "sgf_tempo_test",
"role": "sgf_test_runner",
"port": 55439,
"cluster": "sgf_modular_regression_2576427d1939"
},
"read_only": true,
"temporary_stock_grants_remaining": 0,
"original_constraint_restored_without_stock_right": true,
"constraint_sha256": "40046092cba51f1b46d26d5f0da8af47e8336e90a8d50b8de3a8c390758f1783",
"operational_source_bindings": 0
},
"new_native_qa_database_retained": true,
"existing_databases_migrated": false,
"prior_association_proofs_unchanged": true,
"existing_stock_load_reused_sha256": "4fc1d7d13d480a30966b259611de1066fc22ef31f7a0e782da4872211801c72e",
"protected_six_records_untouched": true,
"blocked_cache_untouched": true,
"public_rights_changed": false,
"purchasing_candidate_activated": false,
"demos_updated": false,
"publication": false,
"checkpoint": false
},
"limits": [
"Real application kernels/routes/middleware, preauthenticated synthetic users; no network login/MFA/TLS/browser proof.",
"Read-only API composition; existing native Stock page/writer unchanged.",
"Stock source is QA fixture, not migrated customer data; no receipt/consumption/business command executed.",
"No new load measurements; reader SQL unchanged and valid historical load retained."
],
"visual_review_pending": true,
"deployment_capacity_validated": false
}
+779
View File
@@ -0,0 +1,779 @@
{
"date": "2026-11-02",
"kind": "new_inventory_reader_not_association_rebenchmark",
"profiles": [
{
"records": 1000,
"view": "items",
"page_size": 25,
"median_ms": 16.919,
"samples": [
{
"queries": 15,
"database_ms": 12.010000000000002,
"elapsed_ms": 18.913,
"incremental_php_bytes": 65472,
"peak_php_bytes": 45006352,
"response_bytes": 2901
},
{
"queries": 15,
"database_ms": 9.48,
"elapsed_ms": 15.34,
"incremental_php_bytes": 73056,
"peak_php_bytes": 45060992,
"response_bytes": 2901
},
{
"queries": 15,
"database_ms": 10.909999999999998,
"elapsed_ms": 16.919,
"incremental_php_bytes": 73056,
"peak_php_bytes": 45062208,
"response_bytes": 2901
}
]
},
{
"records": 1000,
"view": "items",
"page_size": 100,
"median_ms": 16.071,
"samples": [
{
"queries": 15,
"database_ms": 9.16,
"elapsed_ms": 15.269,
"incremental_php_bytes": 101096,
"peak_php_bytes": 45101320,
"response_bytes": 8004
},
{
"queries": 15,
"database_ms": 9.670000000000002,
"elapsed_ms": 16.071,
"incremental_php_bytes": 108680,
"peak_php_bytes": 45197512,
"response_bytes": 8004
},
{
"queries": 15,
"database_ms": 10.72,
"elapsed_ms": 17.432,
"incremental_php_bytes": 109000,
"peak_php_bytes": 45199048,
"response_bytes": 8004
}
]
},
{
"records": 1000,
"view": "warehouses",
"page_size": 25,
"median_ms": 15.225,
"samples": [
{
"queries": 15,
"database_ms": 13.27,
"elapsed_ms": 20.319,
"incremental_php_bytes": 65472,
"peak_php_bytes": 45165904,
"response_bytes": 1310
},
{
"queries": 15,
"database_ms": 9.450000000000001,
"elapsed_ms": 14.765,
"incremental_php_bytes": 73088,
"peak_php_bytes": 45043576,
"response_bytes": 1310
},
{
"queries": 15,
"database_ms": 10.1,
"elapsed_ms": 15.225,
"incremental_php_bytes": 73088,
"peak_php_bytes": 45044792,
"response_bytes": 1310
}
]
},
{
"records": 1000,
"view": "warehouses",
"page_size": 100,
"median_ms": 15.476,
"samples": [
{
"queries": 15,
"database_ms": 10.06,
"elapsed_ms": 15.476,
"incremental_php_bytes": 65472,
"peak_php_bytes": 45047240,
"response_bytes": 1311
},
{
"queries": 15,
"database_ms": 9.719999999999999,
"elapsed_ms": 14.553,
"incremental_php_bytes": 73088,
"peak_php_bytes": 45048672,
"response_bytes": 1311
},
{
"queries": 15,
"database_ms": 11.75,
"elapsed_ms": 18.882,
"incremental_php_bytes": 73088,
"peak_php_bytes": 45049888,
"response_bytes": 1311
}
]
},
{
"records": 1000,
"view": "balances",
"page_size": 25,
"median_ms": 28.57,
"samples": [
{
"queries": 15,
"database_ms": 22.119999999999997,
"elapsed_ms": 28.206,
"incremental_php_bytes": 73384,
"peak_php_bytes": 45060848,
"response_bytes": 7854
},
{
"queries": 15,
"database_ms": 22.78,
"elapsed_ms": 28.981,
"incremental_php_bytes": 80992,
"peak_php_bytes": 45129240,
"response_bytes": 7854
},
{
"queries": 15,
"database_ms": 22.91,
"elapsed_ms": 28.57,
"incremental_php_bytes": 80992,
"peak_php_bytes": 45130456,
"response_bytes": 7854
}
]
},
{
"records": 1000,
"view": "balances",
"page_size": 100,
"median_ms": 32.412,
"samples": [
{
"queries": 15,
"database_ms": 40.309999999999995,
"elapsed_ms": 47.208,
"incremental_php_bytes": 202048,
"peak_php_bytes": 45261552,
"response_bytes": 27807
},
{
"queries": 15,
"database_ms": 25.26,
"elapsed_ms": 32.412,
"incremental_php_bytes": 181392,
"peak_php_bytes": 45442640,
"response_bytes": 27807
},
{
"queries": 15,
"database_ms": 22.92,
"elapsed_ms": 29.493,
"incremental_php_bytes": 181392,
"peak_php_bytes": 45443856,
"response_bytes": 27807
}
]
},
{
"records": 1000,
"view": "movements",
"page_size": 25,
"median_ms": 27.426,
"samples": [
{
"queries": 15,
"database_ms": 26.21,
"elapsed_ms": 34.066,
"incremental_php_bytes": 75104,
"peak_php_bytes": 45347616,
"response_bytes": 8012
},
{
"queries": 15,
"database_ms": 20.939999999999998,
"elapsed_ms": 27.426,
"incremental_php_bytes": 82720,
"peak_php_bytes": 45144856,
"response_bytes": 8012
},
{
"queries": 15,
"database_ms": 20.02,
"elapsed_ms": 26.194,
"incremental_php_bytes": 82720,
"peak_php_bytes": 45146072,
"response_bytes": 8012
}
]
},
{
"records": 1000,
"view": "movements",
"page_size": 100,
"median_ms": 25.314,
"samples": [
{
"queries": 15,
"database_ms": 18.82,
"elapsed_ms": 25.314,
"incremental_php_bytes": 212848,
"peak_php_bytes": 45286248,
"response_bytes": 28492
},
{
"queries": 15,
"database_ms": 18.810000000000002,
"elapsed_ms": 24.952,
"incremental_php_bytes": 187920,
"peak_php_bytes": 45473864,
"response_bytes": 28492
},
{
"queries": 15,
"database_ms": 20.14,
"elapsed_ms": 26.799,
"incremental_php_bytes": 189200,
"peak_php_bytes": 45476360,
"response_bytes": 28492
}
]
},
{
"records": 5000,
"view": "items",
"page_size": 25,
"median_ms": 32.046,
"samples": [
{
"queries": 15,
"database_ms": 24.290000000000003,
"elapsed_ms": 32.046,
"incremental_php_bytes": 65472,
"peak_php_bytes": 45391824,
"response_bytes": 2932
},
{
"queries": 15,
"database_ms": 23.220000000000002,
"elapsed_ms": 28.768,
"incremental_php_bytes": 73056,
"peak_php_bytes": 45144984,
"response_bytes": 2932
},
{
"queries": 15,
"database_ms": 35.3,
"elapsed_ms": 43.458,
"incremental_php_bytes": 73056,
"peak_php_bytes": 45146200,
"response_bytes": 2932
}
]
},
{
"records": 5000,
"view": "items",
"page_size": 100,
"median_ms": 36.666,
"samples": [
{
"queries": 15,
"database_ms": 25.93,
"elapsed_ms": 32.249,
"incremental_php_bytes": 101096,
"peak_php_bytes": 45184416,
"response_bytes": 8034
},
{
"queries": 15,
"database_ms": 30.490000000000006,
"elapsed_ms": 36.666,
"incremental_php_bytes": 108680,
"peak_php_bytes": 45280608,
"response_bytes": 8034
},
{
"queries": 15,
"database_ms": 34.53,
"elapsed_ms": 41.724,
"incremental_php_bytes": 108680,
"peak_php_bytes": 45281824,
"response_bytes": 8034
}
]
},
{
"records": 5000,
"view": "warehouses",
"page_size": 25,
"median_ms": 42.828,
"samples": [
{
"queries": 15,
"database_ms": 29.71,
"elapsed_ms": 36.894,
"incremental_php_bytes": 65472,
"peak_php_bytes": 45248680,
"response_bytes": 1340
},
{
"queries": 15,
"database_ms": 28.58,
"elapsed_ms": 43.264,
"incremental_php_bytes": 73088,
"peak_php_bytes": 45126352,
"response_bytes": 1340
},
{
"queries": 15,
"database_ms": 33.13,
"elapsed_ms": 42.828,
"incremental_php_bytes": 73088,
"peak_php_bytes": 45127568,
"response_bytes": 1340
}
]
},
{
"records": 5000,
"view": "warehouses",
"page_size": 100,
"median_ms": 38.669,
"samples": [
{
"queries": 15,
"database_ms": 35.45,
"elapsed_ms": 42.782,
"incremental_php_bytes": 65472,
"peak_php_bytes": 45130016,
"response_bytes": 1341
},
{
"queries": 15,
"database_ms": 29.66,
"elapsed_ms": 38.669,
"incremental_php_bytes": 73088,
"peak_php_bytes": 45131448,
"response_bytes": 1341
},
{
"queries": 15,
"database_ms": 25.959999999999997,
"elapsed_ms": 34.054,
"incremental_php_bytes": 73088,
"peak_php_bytes": 45132664,
"response_bytes": 1341
}
]
},
{
"records": 5000,
"view": "balances",
"page_size": 25,
"median_ms": 99.207,
"samples": [
{
"queries": 15,
"database_ms": 82.33,
"elapsed_ms": 89.577,
"incremental_php_bytes": 73384,
"peak_php_bytes": 45142984,
"response_bytes": 7885
},
{
"queries": 15,
"database_ms": 92.47,
"elapsed_ms": 99.207,
"incremental_php_bytes": 80992,
"peak_php_bytes": 45211376,
"response_bytes": 7885
},
{
"queries": 15,
"database_ms": 104.98,
"elapsed_ms": 113.573,
"incremental_php_bytes": 80992,
"peak_php_bytes": 45212592,
"response_bytes": 7885
}
]
},
{
"records": 5000,
"view": "balances",
"page_size": 100,
"median_ms": 92.208,
"samples": [
{
"queries": 15,
"database_ms": 80.97,
"elapsed_ms": 89.424,
"incremental_php_bytes": 202048,
"peak_php_bytes": 45349320,
"response_bytes": 27837
},
{
"queries": 15,
"database_ms": 85.38,
"elapsed_ms": 92.208,
"incremental_php_bytes": 181392,
"peak_php_bytes": 45530408,
"response_bytes": 27837
},
{
"queries": 15,
"database_ms": 99.84,
"elapsed_ms": 107.714,
"incremental_php_bytes": 181392,
"peak_php_bytes": 45531624,
"response_bytes": 27837
}
]
},
{
"records": 5000,
"view": "movements",
"page_size": 25,
"median_ms": 96.232,
"samples": [
{
"queries": 15,
"database_ms": 88.48,
"elapsed_ms": 96.232,
"incremental_php_bytes": 75104,
"peak_php_bytes": 45435384,
"response_bytes": 8044
},
{
"queries": 15,
"database_ms": 93,
"elapsed_ms": 100.649,
"incremental_php_bytes": 82720,
"peak_php_bytes": 45232624,
"response_bytes": 8044
},
{
"queries": 15,
"database_ms": 70.94,
"elapsed_ms": 79.507,
"incremental_php_bytes": 82720,
"peak_php_bytes": 45233840,
"response_bytes": 8044
}
]
},
{
"records": 5000,
"view": "movements",
"page_size": 100,
"median_ms": 76.294,
"samples": [
{
"queries": 15,
"database_ms": 74.6,
"elapsed_ms": 80.654,
"incremental_php_bytes": 212848,
"peak_php_bytes": 45374016,
"response_bytes": 28524
},
{
"queries": 15,
"database_ms": 68.18,
"elapsed_ms": 76.294,
"incremental_php_bytes": 187920,
"peak_php_bytes": 45561632,
"response_bytes": 28524
},
{
"queries": 15,
"database_ms": 68.53,
"elapsed_ms": 75.194,
"incremental_php_bytes": 187920,
"peak_php_bytes": 45562848,
"response_bytes": 28524
}
]
},
{
"records": 10000,
"view": "items",
"page_size": 25,
"median_ms": 63.729,
"samples": [
{
"queries": 15,
"database_ms": 55.09,
"elapsed_ms": 63.729,
"incremental_php_bytes": 65472,
"peak_php_bytes": 45641168,
"response_bytes": 2933
},
{
"queries": 15,
"database_ms": 69.98,
"elapsed_ms": 80.337,
"incremental_php_bytes": 73056,
"peak_php_bytes": 45398424,
"response_bytes": 2933
},
{
"queries": 15,
"database_ms": 49.14,
"elapsed_ms": 58.236,
"incremental_php_bytes": 73056,
"peak_php_bytes": 45399640,
"response_bytes": 2933
}
]
},
{
"records": 10000,
"view": "items",
"page_size": 100,
"median_ms": 43.684,
"samples": [
{
"queries": 15,
"database_ms": 44.22,
"elapsed_ms": 51.456,
"incremental_php_bytes": 101096,
"peak_php_bytes": 45438016,
"response_bytes": 8036
},
{
"queries": 15,
"database_ms": 38.07,
"elapsed_ms": 43.684,
"incremental_php_bytes": 108680,
"peak_php_bytes": 45534208,
"response_bytes": 8036
},
{
"queries": 15,
"database_ms": 37.18,
"elapsed_ms": 43.267,
"incremental_php_bytes": 108680,
"peak_php_bytes": 45535424,
"response_bytes": 8036
}
]
},
{
"records": 10000,
"view": "warehouses",
"page_size": 25,
"median_ms": 39.995,
"samples": [
{
"queries": 15,
"database_ms": 33.11000000000001,
"elapsed_ms": 38.771,
"incremental_php_bytes": 65472,
"peak_php_bytes": 45502280,
"response_bytes": 1340
},
{
"queries": 15,
"database_ms": 33.6,
"elapsed_ms": 39.995,
"incremental_php_bytes": 73088,
"peak_php_bytes": 45379952,
"response_bytes": 1340
},
{
"queries": 15,
"database_ms": 34.059999999999995,
"elapsed_ms": 40.038,
"incremental_php_bytes": 73088,
"peak_php_bytes": 45381168,
"response_bytes": 1340
}
]
},
{
"records": 10000,
"view": "warehouses",
"page_size": 100,
"median_ms": 43.793,
"samples": [
{
"queries": 15,
"database_ms": 35.800000000000004,
"elapsed_ms": 41.348,
"incremental_php_bytes": 65472,
"peak_php_bytes": 45383616,
"response_bytes": 1341
},
{
"queries": 15,
"database_ms": 37.99,
"elapsed_ms": 43.793,
"incremental_php_bytes": 73088,
"peak_php_bytes": 45385048,
"response_bytes": 1341
},
{
"queries": 15,
"database_ms": 37.48999999999999,
"elapsed_ms": 45.022,
"incremental_php_bytes": 73088,
"peak_php_bytes": 45386264,
"response_bytes": 1341
}
]
},
{
"records": 10000,
"view": "balances",
"page_size": 25,
"median_ms": 143.295,
"samples": [
{
"queries": 15,
"database_ms": 141.85,
"elapsed_ms": 148.065,
"incremental_php_bytes": 73384,
"peak_php_bytes": 45396584,
"response_bytes": 7911
},
{
"queries": 15,
"database_ms": 137.49,
"elapsed_ms": 143.295,
"incremental_php_bytes": 80992,
"peak_php_bytes": 45464976,
"response_bytes": 7911
},
{
"queries": 15,
"database_ms": 134.95,
"elapsed_ms": 140.908,
"incremental_php_bytes": 80992,
"peak_php_bytes": 45466192,
"response_bytes": 7911
}
]
},
{
"records": 10000,
"view": "balances",
"page_size": 100,
"median_ms": 146.565,
"samples": [
{
"queries": 15,
"database_ms": 140.84,
"elapsed_ms": 146.565,
"incremental_php_bytes": 202048,
"peak_php_bytes": 45597288,
"response_bytes": 27939
},
{
"queries": 15,
"database_ms": 142.23000000000002,
"elapsed_ms": 148.635,
"incremental_php_bytes": 181392,
"peak_php_bytes": 45778376,
"response_bytes": 27939
},
{
"queries": 15,
"database_ms": 139.66,
"elapsed_ms": 145.615,
"incremental_php_bytes": 181392,
"peak_php_bytes": 45779592,
"response_bytes": 27939
}
]
},
{
"records": 10000,
"view": "movements",
"page_size": 25,
"median_ms": 122.667,
"samples": [
{
"queries": 15,
"database_ms": 119.6,
"elapsed_ms": 125.981,
"incremental_php_bytes": 75104,
"peak_php_bytes": 45683352,
"response_bytes": 8044
},
{
"queries": 15,
"database_ms": 117,
"elapsed_ms": 122.667,
"incremental_php_bytes": 82720,
"peak_php_bytes": 45480592,
"response_bytes": 8044
},
{
"queries": 15,
"database_ms": 113.22,
"elapsed_ms": 119.433,
"incremental_php_bytes": 82720,
"peak_php_bytes": 45481808,
"response_bytes": 8044
}
]
},
{
"records": 10000,
"view": "movements",
"page_size": 100,
"median_ms": 121.913,
"samples": [
{
"queries": 15,
"database_ms": 120.09,
"elapsed_ms": 127.452,
"incremental_php_bytes": 212848,
"peak_php_bytes": 45621984,
"response_bytes": 28524
},
{
"queries": 15,
"database_ms": 115.59,
"elapsed_ms": 121.913,
"incremental_php_bytes": 187920,
"peak_php_bytes": 45809600,
"response_bytes": 28524
},
{
"queries": 15,
"database_ms": 113.34,
"elapsed_ms": 120.243,
"incremental_php_bytes": 187920,
"peak_php_bytes": 45810816,
"response_bytes": 28524
}
]
}
],
"source_composition": "SGF adapter and common reader in isolated regression only; Purchasing HTTP composition not yet connected",
"indexes": "Primary keys only; no index experiment",
"fixtures": "New QA-only schemas and identities retained; no reset or protected-record changes",
"source_sha256": "9b0591600da07719d655324ccf0b740f06de07db2806540684c9730d048e44b6",
"controller_sha256": "e71e3522b6f8ba19a67c3084f0b9c3aac9cc37e7ff88f7c50a104625aea61405"
}
@@ -0,0 +1,13 @@
{
"identity": {
"database": "sgf_tempo_test",
"role": "sgf_test_runner",
"port": 55439,
"cluster": "sgf_modular_regression_2576427d1939"
},
"read_only": true,
"temporary_stock_grants_remaining": 0,
"original_constraint_restored_without_stock_right": true,
"constraint_sha256": "40046092cba51f1b46d26d5f0da8af47e8336e90a8d50b8de3a8c390758f1783",
"operational_source_bindings": 0
}
@@ -0,0 +1,948 @@
{
"date": "2026-11-02",
"increment": "SGF-STOCK-READ-SIM-v1",
"status": "partial_synthetic_sgf_read_adapter",
"tests": {
"initial_stock_suite": {
"tests": 3,
"assertions": 465,
"errors": 0,
"failures": 0,
"sha256": "ab46f339709f32f606f47db3935209080e6954d7a3ae7126ff7c7686792e0c37"
},
"final_functional": {
"tests": 2,
"assertions": 77,
"errors": 0,
"failures": 0,
"sha256": "b4a58c3701b2d46c73f04c6cc9e51c6c529a54983d57148f1ff87be7de3e3b00"
},
"navigation": {
"tests": 8,
"assertions": 90,
"errors": 0,
"failures": 0,
"sha256": "723d7c92c0c99671c85baa31fcd93cfbd058cdd20d5acdeddbf9a2474e04394d"
}
},
"provenance": {
"reader_sha256": "9b0591600da07719d655324ccf0b740f06de07db2806540684c9730d048e44b6",
"measured_controller_sha256": "e71e3522b6f8ba19a67c3084f0b9c3aac9cc37e7ff88f7c50a104625aea61405",
"final_controller_sha256": "58465ac0f30dfe170f71f484261251d90d73fabd18a9413211f66c54a678bdbe",
"followup": "Error handling for missing/incompatible source and timeout added after load measurement; successful query path/reader unchanged. Final functional cases rerun; load not repeated."
},
"profiles": [
{
"records": 1000,
"view": "items",
"page_size": 25,
"median_ms": 16.919,
"samples": [
{
"queries": 15,
"database_ms": 12.010000000000002,
"elapsed_ms": 18.913,
"incremental_php_bytes": 65472,
"peak_php_bytes": 45006352,
"response_bytes": 2901
},
{
"queries": 15,
"database_ms": 9.48,
"elapsed_ms": 15.34,
"incremental_php_bytes": 73056,
"peak_php_bytes": 45060992,
"response_bytes": 2901
},
{
"queries": 15,
"database_ms": 10.909999999999998,
"elapsed_ms": 16.919,
"incremental_php_bytes": 73056,
"peak_php_bytes": 45062208,
"response_bytes": 2901
}
],
"queries": [
15
],
"max_incremental_php_bytes": 73056
},
{
"records": 1000,
"view": "items",
"page_size": 100,
"median_ms": 16.071,
"samples": [
{
"queries": 15,
"database_ms": 9.16,
"elapsed_ms": 15.269,
"incremental_php_bytes": 101096,
"peak_php_bytes": 45101320,
"response_bytes": 8004
},
{
"queries": 15,
"database_ms": 9.670000000000002,
"elapsed_ms": 16.071,
"incremental_php_bytes": 108680,
"peak_php_bytes": 45197512,
"response_bytes": 8004
},
{
"queries": 15,
"database_ms": 10.72,
"elapsed_ms": 17.432,
"incremental_php_bytes": 109000,
"peak_php_bytes": 45199048,
"response_bytes": 8004
}
],
"queries": [
15
],
"max_incremental_php_bytes": 109000
},
{
"records": 1000,
"view": "warehouses",
"page_size": 25,
"median_ms": 15.225,
"samples": [
{
"queries": 15,
"database_ms": 13.27,
"elapsed_ms": 20.319,
"incremental_php_bytes": 65472,
"peak_php_bytes": 45165904,
"response_bytes": 1310
},
{
"queries": 15,
"database_ms": 9.450000000000001,
"elapsed_ms": 14.765,
"incremental_php_bytes": 73088,
"peak_php_bytes": 45043576,
"response_bytes": 1310
},
{
"queries": 15,
"database_ms": 10.1,
"elapsed_ms": 15.225,
"incremental_php_bytes": 73088,
"peak_php_bytes": 45044792,
"response_bytes": 1310
}
],
"queries": [
15
],
"max_incremental_php_bytes": 73088
},
{
"records": 1000,
"view": "warehouses",
"page_size": 100,
"median_ms": 15.476,
"samples": [
{
"queries": 15,
"database_ms": 10.06,
"elapsed_ms": 15.476,
"incremental_php_bytes": 65472,
"peak_php_bytes": 45047240,
"response_bytes": 1311
},
{
"queries": 15,
"database_ms": 9.719999999999999,
"elapsed_ms": 14.553,
"incremental_php_bytes": 73088,
"peak_php_bytes": 45048672,
"response_bytes": 1311
},
{
"queries": 15,
"database_ms": 11.75,
"elapsed_ms": 18.882,
"incremental_php_bytes": 73088,
"peak_php_bytes": 45049888,
"response_bytes": 1311
}
],
"queries": [
15
],
"max_incremental_php_bytes": 73088
},
{
"records": 1000,
"view": "balances",
"page_size": 25,
"median_ms": 28.57,
"samples": [
{
"queries": 15,
"database_ms": 22.119999999999997,
"elapsed_ms": 28.206,
"incremental_php_bytes": 73384,
"peak_php_bytes": 45060848,
"response_bytes": 7854
},
{
"queries": 15,
"database_ms": 22.78,
"elapsed_ms": 28.981,
"incremental_php_bytes": 80992,
"peak_php_bytes": 45129240,
"response_bytes": 7854
},
{
"queries": 15,
"database_ms": 22.91,
"elapsed_ms": 28.57,
"incremental_php_bytes": 80992,
"peak_php_bytes": 45130456,
"response_bytes": 7854
}
],
"queries": [
15
],
"max_incremental_php_bytes": 80992
},
{
"records": 1000,
"view": "balances",
"page_size": 100,
"median_ms": 32.412,
"samples": [
{
"queries": 15,
"database_ms": 40.309999999999995,
"elapsed_ms": 47.208,
"incremental_php_bytes": 202048,
"peak_php_bytes": 45261552,
"response_bytes": 27807
},
{
"queries": 15,
"database_ms": 25.26,
"elapsed_ms": 32.412,
"incremental_php_bytes": 181392,
"peak_php_bytes": 45442640,
"response_bytes": 27807
},
{
"queries": 15,
"database_ms": 22.92,
"elapsed_ms": 29.493,
"incremental_php_bytes": 181392,
"peak_php_bytes": 45443856,
"response_bytes": 27807
}
],
"queries": [
15
],
"max_incremental_php_bytes": 202048
},
{
"records": 1000,
"view": "movements",
"page_size": 25,
"median_ms": 27.426,
"samples": [
{
"queries": 15,
"database_ms": 26.21,
"elapsed_ms": 34.066,
"incremental_php_bytes": 75104,
"peak_php_bytes": 45347616,
"response_bytes": 8012
},
{
"queries": 15,
"database_ms": 20.939999999999998,
"elapsed_ms": 27.426,
"incremental_php_bytes": 82720,
"peak_php_bytes": 45144856,
"response_bytes": 8012
},
{
"queries": 15,
"database_ms": 20.02,
"elapsed_ms": 26.194,
"incremental_php_bytes": 82720,
"peak_php_bytes": 45146072,
"response_bytes": 8012
}
],
"queries": [
15
],
"max_incremental_php_bytes": 82720
},
{
"records": 1000,
"view": "movements",
"page_size": 100,
"median_ms": 25.314,
"samples": [
{
"queries": 15,
"database_ms": 18.82,
"elapsed_ms": 25.314,
"incremental_php_bytes": 212848,
"peak_php_bytes": 45286248,
"response_bytes": 28492
},
{
"queries": 15,
"database_ms": 18.810000000000002,
"elapsed_ms": 24.952,
"incremental_php_bytes": 187920,
"peak_php_bytes": 45473864,
"response_bytes": 28492
},
{
"queries": 15,
"database_ms": 20.14,
"elapsed_ms": 26.799,
"incremental_php_bytes": 189200,
"peak_php_bytes": 45476360,
"response_bytes": 28492
}
],
"queries": [
15
],
"max_incremental_php_bytes": 212848
},
{
"records": 5000,
"view": "items",
"page_size": 25,
"median_ms": 32.046,
"samples": [
{
"queries": 15,
"database_ms": 24.290000000000003,
"elapsed_ms": 32.046,
"incremental_php_bytes": 65472,
"peak_php_bytes": 45391824,
"response_bytes": 2932
},
{
"queries": 15,
"database_ms": 23.220000000000002,
"elapsed_ms": 28.768,
"incremental_php_bytes": 73056,
"peak_php_bytes": 45144984,
"response_bytes": 2932
},
{
"queries": 15,
"database_ms": 35.3,
"elapsed_ms": 43.458,
"incremental_php_bytes": 73056,
"peak_php_bytes": 45146200,
"response_bytes": 2932
}
],
"queries": [
15
],
"max_incremental_php_bytes": 73056
},
{
"records": 5000,
"view": "items",
"page_size": 100,
"median_ms": 36.666,
"samples": [
{
"queries": 15,
"database_ms": 25.93,
"elapsed_ms": 32.249,
"incremental_php_bytes": 101096,
"peak_php_bytes": 45184416,
"response_bytes": 8034
},
{
"queries": 15,
"database_ms": 30.490000000000006,
"elapsed_ms": 36.666,
"incremental_php_bytes": 108680,
"peak_php_bytes": 45280608,
"response_bytes": 8034
},
{
"queries": 15,
"database_ms": 34.53,
"elapsed_ms": 41.724,
"incremental_php_bytes": 108680,
"peak_php_bytes": 45281824,
"response_bytes": 8034
}
],
"queries": [
15
],
"max_incremental_php_bytes": 108680
},
{
"records": 5000,
"view": "warehouses",
"page_size": 25,
"median_ms": 42.828,
"samples": [
{
"queries": 15,
"database_ms": 29.71,
"elapsed_ms": 36.894,
"incremental_php_bytes": 65472,
"peak_php_bytes": 45248680,
"response_bytes": 1340
},
{
"queries": 15,
"database_ms": 28.58,
"elapsed_ms": 43.264,
"incremental_php_bytes": 73088,
"peak_php_bytes": 45126352,
"response_bytes": 1340
},
{
"queries": 15,
"database_ms": 33.13,
"elapsed_ms": 42.828,
"incremental_php_bytes": 73088,
"peak_php_bytes": 45127568,
"response_bytes": 1340
}
],
"queries": [
15
],
"max_incremental_php_bytes": 73088
},
{
"records": 5000,
"view": "warehouses",
"page_size": 100,
"median_ms": 38.669,
"samples": [
{
"queries": 15,
"database_ms": 35.45,
"elapsed_ms": 42.782,
"incremental_php_bytes": 65472,
"peak_php_bytes": 45130016,
"response_bytes": 1341
},
{
"queries": 15,
"database_ms": 29.66,
"elapsed_ms": 38.669,
"incremental_php_bytes": 73088,
"peak_php_bytes": 45131448,
"response_bytes": 1341
},
{
"queries": 15,
"database_ms": 25.959999999999997,
"elapsed_ms": 34.054,
"incremental_php_bytes": 73088,
"peak_php_bytes": 45132664,
"response_bytes": 1341
}
],
"queries": [
15
],
"max_incremental_php_bytes": 73088
},
{
"records": 5000,
"view": "balances",
"page_size": 25,
"median_ms": 99.207,
"samples": [
{
"queries": 15,
"database_ms": 82.33,
"elapsed_ms": 89.577,
"incremental_php_bytes": 73384,
"peak_php_bytes": 45142984,
"response_bytes": 7885
},
{
"queries": 15,
"database_ms": 92.47,
"elapsed_ms": 99.207,
"incremental_php_bytes": 80992,
"peak_php_bytes": 45211376,
"response_bytes": 7885
},
{
"queries": 15,
"database_ms": 104.98,
"elapsed_ms": 113.573,
"incremental_php_bytes": 80992,
"peak_php_bytes": 45212592,
"response_bytes": 7885
}
],
"queries": [
15
],
"max_incremental_php_bytes": 80992
},
{
"records": 5000,
"view": "balances",
"page_size": 100,
"median_ms": 92.208,
"samples": [
{
"queries": 15,
"database_ms": 80.97,
"elapsed_ms": 89.424,
"incremental_php_bytes": 202048,
"peak_php_bytes": 45349320,
"response_bytes": 27837
},
{
"queries": 15,
"database_ms": 85.38,
"elapsed_ms": 92.208,
"incremental_php_bytes": 181392,
"peak_php_bytes": 45530408,
"response_bytes": 27837
},
{
"queries": 15,
"database_ms": 99.84,
"elapsed_ms": 107.714,
"incremental_php_bytes": 181392,
"peak_php_bytes": 45531624,
"response_bytes": 27837
}
],
"queries": [
15
],
"max_incremental_php_bytes": 202048
},
{
"records": 5000,
"view": "movements",
"page_size": 25,
"median_ms": 96.232,
"samples": [
{
"queries": 15,
"database_ms": 88.48,
"elapsed_ms": 96.232,
"incremental_php_bytes": 75104,
"peak_php_bytes": 45435384,
"response_bytes": 8044
},
{
"queries": 15,
"database_ms": 93,
"elapsed_ms": 100.649,
"incremental_php_bytes": 82720,
"peak_php_bytes": 45232624,
"response_bytes": 8044
},
{
"queries": 15,
"database_ms": 70.94,
"elapsed_ms": 79.507,
"incremental_php_bytes": 82720,
"peak_php_bytes": 45233840,
"response_bytes": 8044
}
],
"queries": [
15
],
"max_incremental_php_bytes": 82720
},
{
"records": 5000,
"view": "movements",
"page_size": 100,
"median_ms": 76.294,
"samples": [
{
"queries": 15,
"database_ms": 74.6,
"elapsed_ms": 80.654,
"incremental_php_bytes": 212848,
"peak_php_bytes": 45374016,
"response_bytes": 28524
},
{
"queries": 15,
"database_ms": 68.18,
"elapsed_ms": 76.294,
"incremental_php_bytes": 187920,
"peak_php_bytes": 45561632,
"response_bytes": 28524
},
{
"queries": 15,
"database_ms": 68.53,
"elapsed_ms": 75.194,
"incremental_php_bytes": 187920,
"peak_php_bytes": 45562848,
"response_bytes": 28524
}
],
"queries": [
15
],
"max_incremental_php_bytes": 212848
},
{
"records": 10000,
"view": "items",
"page_size": 25,
"median_ms": 63.729,
"samples": [
{
"queries": 15,
"database_ms": 55.09,
"elapsed_ms": 63.729,
"incremental_php_bytes": 65472,
"peak_php_bytes": 45641168,
"response_bytes": 2933
},
{
"queries": 15,
"database_ms": 69.98,
"elapsed_ms": 80.337,
"incremental_php_bytes": 73056,
"peak_php_bytes": 45398424,
"response_bytes": 2933
},
{
"queries": 15,
"database_ms": 49.14,
"elapsed_ms": 58.236,
"incremental_php_bytes": 73056,
"peak_php_bytes": 45399640,
"response_bytes": 2933
}
],
"queries": [
15
],
"max_incremental_php_bytes": 73056
},
{
"records": 10000,
"view": "items",
"page_size": 100,
"median_ms": 43.684,
"samples": [
{
"queries": 15,
"database_ms": 44.22,
"elapsed_ms": 51.456,
"incremental_php_bytes": 101096,
"peak_php_bytes": 45438016,
"response_bytes": 8036
},
{
"queries": 15,
"database_ms": 38.07,
"elapsed_ms": 43.684,
"incremental_php_bytes": 108680,
"peak_php_bytes": 45534208,
"response_bytes": 8036
},
{
"queries": 15,
"database_ms": 37.18,
"elapsed_ms": 43.267,
"incremental_php_bytes": 108680,
"peak_php_bytes": 45535424,
"response_bytes": 8036
}
],
"queries": [
15
],
"max_incremental_php_bytes": 108680
},
{
"records": 10000,
"view": "warehouses",
"page_size": 25,
"median_ms": 39.995,
"samples": [
{
"queries": 15,
"database_ms": 33.11000000000001,
"elapsed_ms": 38.771,
"incremental_php_bytes": 65472,
"peak_php_bytes": 45502280,
"response_bytes": 1340
},
{
"queries": 15,
"database_ms": 33.6,
"elapsed_ms": 39.995,
"incremental_php_bytes": 73088,
"peak_php_bytes": 45379952,
"response_bytes": 1340
},
{
"queries": 15,
"database_ms": 34.059999999999995,
"elapsed_ms": 40.038,
"incremental_php_bytes": 73088,
"peak_php_bytes": 45381168,
"response_bytes": 1340
}
],
"queries": [
15
],
"max_incremental_php_bytes": 73088
},
{
"records": 10000,
"view": "warehouses",
"page_size": 100,
"median_ms": 43.793,
"samples": [
{
"queries": 15,
"database_ms": 35.800000000000004,
"elapsed_ms": 41.348,
"incremental_php_bytes": 65472,
"peak_php_bytes": 45383616,
"response_bytes": 1341
},
{
"queries": 15,
"database_ms": 37.99,
"elapsed_ms": 43.793,
"incremental_php_bytes": 73088,
"peak_php_bytes": 45385048,
"response_bytes": 1341
},
{
"queries": 15,
"database_ms": 37.48999999999999,
"elapsed_ms": 45.022,
"incremental_php_bytes": 73088,
"peak_php_bytes": 45386264,
"response_bytes": 1341
}
],
"queries": [
15
],
"max_incremental_php_bytes": 73088
},
{
"records": 10000,
"view": "balances",
"page_size": 25,
"median_ms": 143.295,
"samples": [
{
"queries": 15,
"database_ms": 141.85,
"elapsed_ms": 148.065,
"incremental_php_bytes": 73384,
"peak_php_bytes": 45396584,
"response_bytes": 7911
},
{
"queries": 15,
"database_ms": 137.49,
"elapsed_ms": 143.295,
"incremental_php_bytes": 80992,
"peak_php_bytes": 45464976,
"response_bytes": 7911
},
{
"queries": 15,
"database_ms": 134.95,
"elapsed_ms": 140.908,
"incremental_php_bytes": 80992,
"peak_php_bytes": 45466192,
"response_bytes": 7911
}
],
"queries": [
15
],
"max_incremental_php_bytes": 80992
},
{
"records": 10000,
"view": "balances",
"page_size": 100,
"median_ms": 146.565,
"samples": [
{
"queries": 15,
"database_ms": 140.84,
"elapsed_ms": 146.565,
"incremental_php_bytes": 202048,
"peak_php_bytes": 45597288,
"response_bytes": 27939
},
{
"queries": 15,
"database_ms": 142.23000000000002,
"elapsed_ms": 148.635,
"incremental_php_bytes": 181392,
"peak_php_bytes": 45778376,
"response_bytes": 27939
},
{
"queries": 15,
"database_ms": 139.66,
"elapsed_ms": 145.615,
"incremental_php_bytes": 181392,
"peak_php_bytes": 45779592,
"response_bytes": 27939
}
],
"queries": [
15
],
"max_incremental_php_bytes": 202048
},
{
"records": 10000,
"view": "movements",
"page_size": 25,
"median_ms": 122.667,
"samples": [
{
"queries": 15,
"database_ms": 119.6,
"elapsed_ms": 125.981,
"incremental_php_bytes": 75104,
"peak_php_bytes": 45683352,
"response_bytes": 8044
},
{
"queries": 15,
"database_ms": 117,
"elapsed_ms": 122.667,
"incremental_php_bytes": 82720,
"peak_php_bytes": 45480592,
"response_bytes": 8044
},
{
"queries": 15,
"database_ms": 113.22,
"elapsed_ms": 119.433,
"incremental_php_bytes": 82720,
"peak_php_bytes": 45481808,
"response_bytes": 8044
}
],
"queries": [
15
],
"max_incremental_php_bytes": 82720
},
{
"records": 10000,
"view": "movements",
"page_size": 100,
"median_ms": 121.913,
"samples": [
{
"queries": 15,
"database_ms": 120.09,
"elapsed_ms": 127.452,
"incremental_php_bytes": 212848,
"peak_php_bytes": 45621984,
"response_bytes": 28524
},
{
"queries": 15,
"database_ms": 115.59,
"elapsed_ms": 121.913,
"incremental_php_bytes": 187920,
"peak_php_bytes": 45809600,
"response_bytes": 28524
},
{
"queries": 15,
"database_ms": 113.34,
"elapsed_ms": 120.243,
"incremental_php_bytes": 187920,
"peak_php_bytes": 45810816,
"response_bytes": 28524
}
],
"queries": [
15
],
"max_incremental_php_bytes": 212848
}
],
"measured_requests": 72,
"full_balance_page_traversal": [
1000,
5000,
10000
],
"indexes": "Primary keys only; no experimental or destination indexes",
"sources": {
"packages/inventory-read/src/InventoryReader.php": "9b0591600da07719d655324ccf0b740f06de07db2806540684c9730d048e44b6",
"app/Modules/Inventory/StockReadController.php": "58465ac0f30dfe170f71f484261251d90d73fabd18a9413211f66c54a678bdbe",
"config/stock_read.php": "c1cb5a2009d1140952072ba030b2cecf7ca6e0f6298687564b061006ec81dcdc",
"resources/js/StockReadWorkspace.jsx": "96ff89f9d27a471f48bc8587a1b2bcaf78fb5aedf80adc1d69c3d7db13c2343d",
"resources/js/StockMenuWorkspace.jsx": "ddef528851f6c3ab19fa8c5b3a459d6bfb157df81616810cd7da2f049aebe6a4",
"routes/web.php": "9f09b31877617dfb252363c644d216e02864b29e7777a1d323f8d8ac1d4145fc",
"app/Shared/Context/ModuleNavigation.php": "33bc9e49f002042c9a7785d1f0d19638482f742294f77d4eabe6974d71096263"
},
"preservation": {
"identity": {
"database": "sgf_tempo_test",
"role": "sgf_test_runner",
"port": 55439,
"cluster": "sgf_modular_regression_2576427d1939"
},
"read_only": true,
"temporary_stock_grants_remaining": 0,
"original_constraint_restored_without_stock_right": true,
"constraint_sha256": "40046092cba51f1b46d26d5f0da8af47e8336e90a8d50b8de3a8c390758f1783",
"operational_source_bindings": 0,
"protected_six_records_untouched": true,
"blocked_cache_untouched": true,
"previous_proof_hashes_unchanged": true,
"qa_fixtures_retained": true,
"real_or_demo_database_connected": false,
"public_rights_changed": false,
"purchasing_source_modified": false,
"purchasing_activated": false,
"publication": false,
"checkpoint": false
},
"limits": [
"Testing-only source bindings, empty by default. No existing demo updated.",
"Shared read projection uses Purchasing ledger structure; Purchasing HTTP adapter/two-host parity remains pending.",
"Physical stock only; reservations, blocked, available and valuation not established.",
"No stock commands, receipt/consumption linkage or journal engine added.",
"Static UI/build is not visual review; warm in-process load is not deployment capacity."
],
"visual_review_pending": true,
"deployment_capacity_validated": false
}
+9
View File
@@ -0,0 +1,9 @@
{
"kind": "static_render_and_exact_quantity",
"company_permission_not_stock_permission": true,
"read_only_controls": true,
"unknown_not_zero": true,
"bigint_exact": true,
"backend_requests": 0,
"visual_review": false
}
@@ -0,0 +1,143 @@
{
"date": "2026-11-02",
"increment": "COMMON-RECEIPT-STOCK-SIM-v1",
"status": "native_receipt_shared_effect_and_sgf_read_verified",
"tests": {
"native_link": {
"tests": 1,
"assertions": 33,
"errors": 0,
"failures": 0,
"sha256": "39f751da24e4286672e9e7f68da1772ae7639942c20cd50c0dd089d61759a2a4"
},
"affected_receipts": {
"tests": 31,
"assertions": 193,
"errors": 0,
"failures": 0,
"sha256": "15d58947c8e9c8999b53708fc52f33c913d62efb55e3df3f537eb700af04acf9"
},
"affected_lot_receipts": {
"tests": 3,
"assertions": 20,
"errors": 0,
"failures": 0,
"sha256": "08343998fa8b9f33580adc3e697d7071e0a4649252fb30c5ea1d68683c6b9344"
},
"final_native_adapter_replay": {
"tests": 1,
"assertions": 8,
"errors": 0,
"failures": 0,
"sha256": "186385af4fa5f1b2eaf1dab0c117c5a8ab56419adb17b2da386ceac66726d1d8"
},
"sgf_functional": {
"tests": 2,
"assertions": 77,
"errors": 0,
"failures": 0,
"sha256": "c7d7a56e52f132dc549ff940d8413fa35fea4f650922a77b57a644ecfd97fdbd"
},
"sgf_actual_book_link": {
"tests": 1,
"assertions": 31,
"errors": 0,
"failures": 0,
"sha256": "6c4c5c8888bb2f63ced27a96d86771993531cdbfae060d64ea7495d4659dc20c"
}
},
"scenario": {
"first_received_milli": 6000,
"first_accepted_milli": 4000,
"first_rejected_milli": 2000,
"second_received_milli": 2000,
"second_accepted_milli": 0,
"second_rejected_milli": 2000,
"final_physical_milli": "4000",
"movement_count": 1
},
"source_hash_stale_refused": true,
"core_replay_same_movement": true,
"fault_atomic_and_recovered": true,
"concurrency": {
"actual_lock_wait": true,
"wait_event": "transactionid",
"same_receipt": true,
"one_movement": true
},
"same_native_movement_observed_by_sgf": true,
"read_does_not_copy_or_mutate_stock": true,
"source_connection_failure_503_and_recovery": true,
"package": {
"id": "tempo-inventory-receipt-write",
"version": "0.1.0",
"files": {
"bootstrap.php": "b6ea8939536008c9277724216df2a968f416d9e7374189587a1172c02ecacb75",
"src/ReceiptMovementWriter.php": "279cec2ec915e27cf431355fca1e36f21cb3c15a77d02834723a41ec7a6f8f40"
},
"manifest_sha256": "f0b99e591f9a4df135e685f64ceffad77bed259222debe0f34c20f95e3cad800",
"canonical_and_artifact_identical": true
},
"source_hashes": {
"packages/inventory-write/src/ReceiptMovementWriter.php": "279cec2ec915e27cf431355fca1e36f21cb3c15a77d02834723a41ec7a6f8f40",
"app/Modules/Inventory/StockReadController.php": "c6131733974b6902c556593709729356769d11aea9eada3fc5397246102068f4",
"../compras/app/Services/ReceiptWorkflow.php": "a7325d4fdb09d1767d0d4fa3661bcf9b254e8506285080d6063bbed487bb522c",
"../compras/app/Services/ReceiptStockMovement.php": "bd95d201563e4b028f7412eea77d5b157bbc464ddb5b34907bdf17b44d3c1637"
},
"source_postcheck": {
"reader": {
"database": "compras_receipts_test_c20d57941803",
"role": "stock_receipt_read_c20d57941803",
"cluster": "sgf_modular_regression_2576427d1939",
"default_read_only": "on",
"elevated": false,
"stock_select": true,
"stock_write": false,
"receipt_select": false
},
"book": {
"movements": 1,
"physical_milli": "4000",
"receipt_confirmations": 2,
"author_and_date_present": true,
"movement_origin_hash": "6e7dc7721f92b0445c0b850b00e6bbaeb084a30426cd596902340985b76bf7ae"
}
},
"sgf_postcheck": {
"identity": {
"database": "sgf_tempo_test",
"role": "sgf_test_runner",
"port": 55439,
"cluster": "sgf_modular_regression_2576427d1939"
},
"read_only": true,
"temporary_stock_grants_remaining": 0,
"original_constraint_restored_without_stock_right": true,
"constraint_sha256": "40046092cba51f1b46d26d5f0da8af47e8336e90a8d50b8de3a8c390758f1783",
"operational_source_bindings": 0
},
"preservation": {
"new_qa_databases_only": true,
"fixtures_retained": true,
"real_or_demo_database_connected": false,
"protected_six_records_untouched": true,
"blocked_cache_untouched": true,
"prior_association_proofs_unchanged": true,
"purchasing_candidates_activated": false,
"public_rights_changed": false,
"publication": false,
"checkpoint": false
},
"reused_proofs": {
"stock_load_sha256": "4fc1d7d13d480a30966b259611de1066fc22ef31f7a0e782da4872211801c72e",
"stock_composition_sha256": "bb129ab22f424a5d3333f9b851062bc6284fd514b9962e0df04b3efd22d951a6"
},
"limits": [
"Existing native receipt validation remains authoritative; no independent SGF receipt preparation/confirmation UI or command delivered.",
"Source connection is confined to the local QA book and a SELECT-only role; it is not a required remote connector or production architecture.",
"StockWorkflow issues/transfers/corrections and workshop consumption are not extracted by this receipt-only writer.",
"PostgreSQL tested; other database drivers not validated in this increment. No new load benchmark or deployment capacity claim."
],
"visual_review_pending": true,
"deployment_capacity_validated": false
}
@@ -0,0 +1,209 @@
{
"date": "2026-11-02",
"increment": "WORKSHOP-DELIVERY-LINK-SIM-v1",
"status": "implemented_and_proved_synthetically",
"tests": {
"affected_existing": {
"file": "workshop-stock-1793633268880.xml",
"sha256": "d5094fd19571c96190ae2fa1d2adadcf30d05add4372f6b02b169345fef98319",
"tests": 6,
"assertions": 222,
"cases": [
"test_individual_impact_independence_exact_issue_and_replay",
"test_client_unverified_fraction_and_unknown_delivery_do_not_debit",
"test_stale_book_mapping_permission_scope_and_failure_recovery",
"test_corrected_source_requires_review_and_never_consumes_the_same_origin_twice",
"test_other_company_cannot_read_or_confirm_origin_and_changed_command_is_refused",
"test_concurrent_confirmation_has_one_claim_and_movement"
],
"selected_cases_only": true,
"parent_run_errors": 3,
"parent_run_failures": 0
},
"delivery": {
"file": "workshop-stock-1793633372636.xml",
"sha256": "d660ba55ab6773efcacf0ba202e33f240b1332347a2609d7c9c9521159890ecb",
"tests": 5,
"assertions": 163,
"cases": [
"test_delivery_link_has_zero_effect_independent_decision_and_no_duplicate",
"test_delivery_link_refuses_mismatch_stale_book_and_recovers_from_failure",
"test_delivery_link_can_reconcile_fully_depleted_stock_without_new_issue",
"test_delivery_link_rejects_reversal_and_does_not_adopt_history",
"test_delivery_link_concurrent_confirmation_has_one_claim_without_movement"
],
"selected_cases_only": false,
"parent_run_errors": 0,
"parent_run_failures": 0
},
"additional_integrity_and_isolation": {
"file": "workshop-stock-1793633481884.xml",
"sha256": "0789b68768ce2f21c02b7d694c03681edd293e89dfdb657955b18390880874a4",
"tests": 2,
"assertions": 47,
"cases": [
"test_delivery_link_refuses_missing_original_hash",
"test_delivery_link_other_company_cannot_prepare_or_confirm"
],
"selected_cases_only": false,
"parent_run_errors": 0,
"parent_run_failures": 0
}
},
"totals": {
"tests": 13,
"assertions": 432
},
"selection_note": "Six affected existing cases passed in a run containing three new fixture-bootstrap errors; those errored cases are excluded. The five delivery cases then passed after bootstrap correction and stricter integrity checks; two additional integrity/isolation cases passed separately. Valid native proofs reused without rerunning unchanged native code.",
"scenarios_asserted": {
"initial_milli": "10000",
"already_issued_milli": "2000",
"before_link_milli": "8000",
"after_link_milli": "8000",
"new_physical_movements": 0,
"total_physical_movements": 2,
"total_operations": 1,
"claims": 1,
"original_movement_unchanged": true,
"same_book_stock_read": true,
"preparer_cannot_confirm": true,
"replay_same_movement": true,
"competing_proposal_refused": true,
"quantity_mismatch_refused": true,
"stale_book_refused": true,
"eligibility_revocation_refused": true,
"permission_revocation_refused": true,
"missing_operation_hash_refused": true,
"reversal_book_refused": true,
"other_company_prepare_and_confirm_refused": true,
"other_company_list_empty": true,
"failure_rollback_and_retry_without_duplicate": true,
"fully_depleted_book_can_link_without_debit": true
},
"concurrency_asserted": {
"processes": 2,
"company_row_lock_observed": true,
"first_backend_identified_by_pg_blocking_pids": true,
"after_release": "200/replay/same movement",
"claims": 1,
"physical_milli": "8000"
},
"source_sha256": {
"app/Modules/Workshop/WorkshopStock.php": "ad8701485fdcdc39fad5d9befef2079aef0c5b84c2ade03e6c3600cc0bd879ac",
"app/Modules/Workshop/Http/WorkshopStockController.php": "6a960ab558f77094119993a4f9a7fb45beb69b04275122b80667313761f2794d",
"resources/js/WorkshopStockWorkspace.jsx": "150c265f31411142635d9f83d6bb6f9be26369aea1cb189b282fc2edec9ce88a",
"routes/web.php": "0340363a57dfd0be5e0f4207b54ea2fafaee32c1e8ec62efd927e89c7277f650",
"tests/Feature/WorkshopStockTest.php": "2dcd62fadd205cf6e567742d69a813e1c6a28fa4ee34616b82bd02c58f0ff80a",
"tests/Support/workshop-stock-worker.php": "bdad20fd4f58714c36c20d3c271ac31fdd92a4083cedf31341938b501fd73c2d"
},
"qa_postcheck": {
"qa_identity": {
"db": "sgf_tempo_test",
"role": "sgf_test_runner",
"port": 55439,
"cluster": "sgf_modular_regression_2576427d1939"
},
"temporary_grants_remaining": 0,
"constraint_sha256": "40046092cba51f1b46d26d5f0da8af47e8336e90a8d50b8de3a8c390758f1783",
"operational_workshop_stock_bindings": 0,
"read_only": true
},
"static_ui": {
"path": "docs/proofs/workshop-delivery-ui-20261102.json",
"sha256": "1c5bc4735e6a29d3ff3cab4c499ccc1d3567f0ce9dafa02a34d57c19ae5b3184",
"kind": "static_impact_render_and_source_checks",
"zero_new_physical_effect_visible": true,
"existing_movement_and_quantity_visible": true,
"explicit_treatment_selection_in_source": true,
"component_sha256": "150c265f31411142635d9f83d6bb6f9be26369aea1cb189b282fc2edec9ce88a",
"backend_requests": 0,
"visual_review": false,
"browser_interactions_tested": false
},
"build": {
"passed": true,
"node": "24.22.1",
"vite": "8.3.5",
"manifest_sha256": "81aa20db890f896c6bb10affc2ff1540d5851d876fb316269db649ee5784e896"
},
"reused_proofs": {
"workshop_stock": {
"path": "docs/proofs/workshop-stock-20261102.json",
"sha256": "c13b22eed190e379d8311a8e02586e201f993a89bfc4490be5d9d325d6ca00c3"
},
"shared_writer_manifest_sha256": "3c24d9e9fb99bfbb274077495c3a42ddb7eccab06b5c6a956cd739b2bc9b56f0",
"native_issue_tests": {
"file": "private/stock-receipt-54f39ed20d16/issue-affected-junit.xml",
"sha256": "aed6359ba4216e10bb89f34d40e0314fc9efb0f8dedeea40551c3302f31b8525",
"tests": 25,
"assertions": 125,
"cases": [
"issues are exact, idempotent and cannot make stock negative",
"transfer creates exactly two opposite ledger entries and rejects repeated references",
"counts preserve theoretical quantities and adjustments apply a justified difference once",
"intervening receipts and issues invalidate counts and stale count forms",
"operational role cannot be replaced by administration or other profiles with data set &quot;(App\\Enums\\PurchasingRole Enum (Admin, 'admin'))&quot;",
"operational role cannot be replaced by administration or other profiles with data set &quot;(App\\Enums\\PurchasingRole Enum (Finance, 'finance'))&quot;",
"operational role cannot be replaced by administration or other profiles with data set &quot;(App\\Enums\\PurchasingRole Enum (Procurement, 'procurement'))&quot;",
"operational role cannot be replaced by administration or other profiles with data set &quot;(App\\Enums\\PurchasingRole Enum (DepartmentHead, 'department_head'))&quot;",
"operational role cannot be replaced by administration or other profiles with data set &quot;(App\\Enums\\PurchasingRole Enum (Requester, 'requester'))&quot;",
"foreign company resources cannot be used with data set &quot;('warehouse_id')&quot;",
"foreign company resources cannot be used with data set &quot;('destination_warehouse_id')&quot;",
"foreign company resources cannot be used with data set &quot;('stock_item_id')&quot;",
"foreign company resources cannot be used with data set &quot;('responsible_id')&quot;",
"audit failure rolls back both halves of transfer and operation",
"operations are immutable and new public screen contains only demonstration props",
"invalid precision and missing justification or destination do not write with data set &quot;('quantity', '-1')&quot;",
"invalid precision and missing justification or destination do not write with data set &quot;('quantity', '0')&quot;",
"invalid precision and missing justification or destination do not write with data set &quot;('quantity', '0.0001')&quot;",
"invalid precision and missing justification or destination do not write with data set &quot;('reason', ' ')&quot;",
"invalid precision and missing justification or destination do not write with data set &quot;('destination', '')&quot;",
"invalid precision and missing justification or destination do not write with data set &quot;('responsible_id', null)&quot;",
"positive adjustments credit only the difference and matching counts create no movements",
"failure creating transfer credit rolls back its debit",
"stock views isolate operations and counts from other companies",
"form encoded retry identifiers and equivalent quantities retain idempotency"
],
"selection": false,
"whole_run_tests": 25,
"whole_run_failures": 0,
"whole_run_errors": 0
},
"native_lot_tests": {
"file": "private/stock-receipt-0119bb873c56/issue-lots-junit.xml",
"sha256": "4ea8597200ebd761cb9460acf165e1baaa4f7b7b1b84690a0bfe749b73ddf6dc",
"tests": 2,
"assertions": 10,
"cases": [
"FEFO consumes earliest expiry and preserves the single physical ledger with exact partitions",
"expiry and hold remove usable quantity without changing physical stock"
],
"selection": false,
"whole_run_tests": 2,
"whole_run_failures": 0,
"whole_run_errors": 0
}
},
"preservation": {
"new_synthetic_fixtures_only": true,
"regression_not_reset": true,
"temporary_rights_restored": true,
"six_protected_records_untouched": true,
"blocked_cache_untouched": true,
"demos_untouched": true,
"prior_association_proofs_unchanged": true,
"real_data_or_rights_changed": false,
"purchasing_activation": false,
"publication": false,
"checkpoint": false
},
"limits": [
"Only explicit QA movement-to-order eligibility; no automatic or historical adoption.",
"Only full equal quantities, simple unreversed common-writer issues, no lots/reservations/spare parts.",
"Partial allocations, returns, compensation and amendment of confirmed links not implemented.",
"Operational configuration/installation and one installed procurement-to-consumption scenario remain pending.",
"No new write-load/deployment capacity proof, no browser interaction or visual review."
],
"visual_review_pending": true,
"deployment_capacity_validated": false
}
@@ -0,0 +1,10 @@
{
"kind": "static_impact_render_and_source_checks",
"zero_new_physical_effect_visible": true,
"existing_movement_and_quantity_visible": true,
"explicit_treatment_selection_in_source": true,
"component_sha256": "150c265f31411142635d9f83d6bb6f9be26369aea1cb189b282fc2edec9ce88a",
"backend_requests": 0,
"visual_review": false,
"browser_interactions_tested": false
}
@@ -0,0 +1,293 @@
{
"date": "2026-11-02",
"increment": "WORKSHOP-MATERIAL-CYCLE-SIM-v1",
"status": "local_synthetic_implementation",
"proofs": [
{
"file": "workshop-stock-1793634406841.xml",
"sha256": "eabad22dca4fe162777bc04adbec9806fcbdf20ccedce2cd7ef97aa270211e13",
"tests": 20,
"assertions": 740,
"errors": 0,
"failures": 0
},
{
"file": "workshop-stock-1793634619557.xml",
"sha256": "dd5a1f08095d33adad82180ade2d92ecac37c62728f2f4a79208818192569362",
"tests": 5,
"assertions": 219,
"errors": 0,
"failures": 0
},
{
"file": "workshop-stock-1793634796037.xml",
"sha256": "c22d26fc7c607027727d1f37ab21f881033ca0be44962e38a5ab9fa1957b9101",
"tests": 9,
"assertions": 363,
"errors": 0,
"failures": 0
},
{
"file": "workshop-stock-1793634950240.xml",
"sha256": "d08140e0984173c271737f42b28f22f6da66648fd816604900866225469eacb3",
"tests": 1,
"assertions": 63,
"errors": 0,
"failures": 0
}
],
"selection": "Latest passing evidence selected per test name; repeated affected cases are not counted twice. Earlier intermediate failure is excluded. Later warehouse receipt declaration, history controls and ordered opening-stock timestamp were verified only in affected cases.",
"totals": {
"distinct_tests": 22,
"assertions": 820
},
"selected_cases": [
{
"name": "test_stock_return_unconsumed_material_restores_only_remaining_quantity_once",
"assertions": 63,
"proof": "workshop-stock-1793634950240.xml"
},
{
"name": "test_stock_return_refuses_consumed_client_unverified_excess_and_stale_capacity",
"assertions": 52,
"proof": "workshop-stock-1793634619557.xml"
},
{
"name": "test_stock_return_failure_after_decision_rolls_back_movement_and_recovers",
"assertions": 32,
"proof": "workshop-stock-1793634619557.xml"
},
{
"name": "test_stock_return_concurrency_cannot_restore_quantity_twice",
"assertions": 40,
"proof": "workshop-stock-1793634619557.xml"
},
{
"name": "test_partial_delivery_links_multiple_origins_without_debit_and_rechecks_remaining",
"assertions": 60,
"proof": "workshop-stock-1793634796037.xml"
},
{
"name": "test_partial_delivery_requires_enabled_capability_and_rolls_back_allocation_failure",
"assertions": 26,
"proof": "workshop-stock-1793634406841.xml"
},
{
"name": "test_partial_delivery_concurrent_proposals_cannot_overallocate",
"assertions": 41,
"proof": "workshop-stock-1793634406841.xml"
},
{
"name": "test_delivery_link_has_zero_effect_independent_decision_and_no_duplicate",
"assertions": 44,
"proof": "workshop-stock-1793634796037.xml"
},
{
"name": "test_delivery_link_refuses_mismatch_stale_book_and_recovers_from_failure",
"assertions": 39,
"proof": "workshop-stock-1793634406841.xml"
},
{
"name": "test_delivery_link_can_reconcile_fully_depleted_stock_without_new_issue",
"assertions": 30,
"proof": "workshop-stock-1793634406841.xml"
},
{
"name": "test_delivery_link_rejects_reversal_and_does_not_adopt_history",
"assertions": 20,
"proof": "workshop-stock-1793634796037.xml"
},
{
"name": "test_delivery_link_refuses_missing_original_hash",
"assertions": 21,
"proof": "workshop-stock-1793634406841.xml"
},
{
"name": "test_delivery_link_other_company_cannot_prepare_or_confirm",
"assertions": 26,
"proof": "workshop-stock-1793634796037.xml"
},
{
"name": "test_individual_impact_independence_exact_issue_and_replay",
"assertions": 45,
"proof": "workshop-stock-1793634796037.xml"
},
{
"name": "test_client_unverified_fraction_and_unknown_delivery_do_not_debit",
"assertions": 48,
"proof": "workshop-stock-1793634406841.xml"
},
{
"name": "test_stale_book_mapping_permission_scope_and_failure_recovery",
"assertions": 31,
"proof": "workshop-stock-1793634406841.xml"
},
{
"name": "test_corrected_source_requires_review_and_never_consumes_the_same_origin_twice",
"assertions": 39,
"proof": "workshop-stock-1793634796037.xml"
},
{
"name": "test_other_company_cannot_read_or_confirm_origin_and_changed_command_is_refused",
"assertions": 29,
"proof": "workshop-stock-1793634796037.xml"
},
{
"name": "test_concurrent_confirmation_has_one_claim_and_movement",
"assertions": 30,
"proof": "workshop-stock-1793634406841.xml"
},
{
"name": "test_delivery_link_concurrent_confirmation_has_one_claim_without_movement",
"assertions": 30,
"proof": "workshop-stock-1793634406841.xml"
},
{
"name": "test_stock_return_revoked_right_stale_context_and_foreign_company_do_not_write",
"assertions": 36,
"proof": "workshop-stock-1793634619557.xml"
},
{
"name": "test_history_filters_and_pagination_preserve_order_and_scope",
"assertions": 38,
"proof": "workshop-stock-1793634796037.xml"
}
],
"scenario_asserted": {
"opening_milli": "10000",
"delivered_milli": "5000",
"physical_after_issue": "5000",
"consumed_allocation_milli": "2000",
"physical_after_allocation": "5000",
"returned_milli": "3000",
"physical_after_return": "8000",
"unallocated_after_return": "0",
"total_movements": 3,
"original_issue_unchanged": true,
"opening_entry_precedes_issue": true,
"stock_read_sees_same_book": true,
"explicit_warehouse_receipt_required": true,
"service_and_writer_replay_original_return": true
},
"partial_allocations_asserted": {
"multiple_origins_one_delivery": true,
"quantity_bound_by_delivery": true,
"physical_effect_zero": true,
"stale_remaining_refused": true,
"already_allocated_origin_not_consumed_again": true,
"disabling_capability_does_not_erase_history_protection": true,
"failure_atomic_and_retry_once": true
},
"return_asserted": {
"consumed_client_unverified_unrepresentable_and_excess_refused": true,
"stale_capacity_refused": true,
"independent_confirmation_required": true,
"missing_receiving_declaration_422": true,
"right_revoked_403": true,
"stale_context_409": true,
"other_company_403_and_empty_history": true,
"decision_failure_rolls_back_movement_and_operation": true
},
"concurrency_asserted": {
"processes": 2,
"company_row_blocker_observed_with_pg_blocking_pids": true,
"competing_allocations_3_plus_3_against_5": "first associates 3; second after release refuses 409",
"competing_returns_3_plus_3_against_5": "one positive movement of 3; second after release refuses 409"
},
"history_asserted": {
"server_page_size": 25,
"proposal_fixture_count": 51,
"descending_id_order": true,
"pages_disjoint": true,
"status_filters": [
"all",
"pending",
"confirmed"
],
"confirmed_includes_allocations_and_returns": true,
"unknown_parameters_refused": true,
"tenant_company_unit_isolation": true
},
"package": {
"id": "tempo-inventory-return",
"version": "0.1.0",
"files": {
"bootstrap.php": "f6735623101377038cde58085d5f00e030249066bc6a67f30b718caab73288be",
"src/DeliveryReturnWriter.php": "a7c65169a5c1f3510f9a2762cbf4163ee4cc81b0a23174a7abed96147e16790a"
},
"manifest_sha256": "2850a4f5cb678acfe3a9dbc7a7d62eb233bc72722ad0de374681c2679c90557c",
"canonical_identical": true,
"native_return_command_integrated": false
},
"source_sha256": {
"app/Modules/Workshop/WorkshopStock.php": "840cd559f5189c8c2934d6e0a761cf3ee6b4f8e4e48a3964829ffd02504d7181",
"app/Modules/Workshop/Http/WorkshopStockController.php": "35f090c753b9d9f55ea85b4b566c1f08e34d3e6a5d28bb43768da1bfab90b712",
"resources/js/WorkshopStockWorkspace.jsx": "8adc2fcf8818a6b5b0c51f55520f6e60811c03a46c0b5711bcff880b6df26884",
"tests/Feature/WorkshopStockTest.php": "8a884fa62fcf000530197c61dd641e1ef1751f242f27384057f3cc355ab59b58",
"tests/Support/workshop-stock-worker.php": "538e01a699f0d81c01a4eb4ed0bac9b0d8f7494b2cdda5e00759f3152d4374f1",
"packages/inventory-return/src/DeliveryReturnWriter.php": "a7c65169a5c1f3510f9a2762cbf4163ee4cc81b0a23174a7abed96147e16790a",
"routes/web.php": "9469393870f2123f2a3ecd4b3027309777c7aeb5d20996b937c0dab1878192be"
},
"qa_postcheck": {
"qa_identity": {
"db": "sgf_tempo_test",
"role": "sgf_test_runner",
"port": 55439,
"cluster": "sgf_modular_regression_2576427d1939"
},
"temporary_grants_remaining": 0,
"constraint_sha256": "40046092cba51f1b46d26d5f0da8af47e8336e90a8d50b8de3a8c390758f1783",
"operational_workshop_stock_bindings": 0,
"read_only": true
},
"ui": {
"path": "docs/proofs/workshop-material-cycle-ui-20261102.json",
"sha256": "d143d458bc779260f4b5d3ae2cb618cf789794bb0b0aa9e4724614b05395321a",
"kind": "static_impact_render_and_source_checks",
"allocation_zero_effect": true,
"remaining_quantity_visible": true,
"return_positive_effect_visible": true,
"physical_receiving_checkbox_required_in_source": true,
"explicit_treatment_choice_in_source": true,
"history_controls_and_query_in_source": true,
"source_sha256": "8adc2fcf8818a6b5b0c51f55520f6e60811c03a46c0b5711bcff880b6df26884",
"backend_requests": 0,
"browser_interactions_tested": false,
"visual_review": false
},
"build": {
"passed": true,
"node": "24.22.1",
"vite": "8.3.5",
"manifest_sha256": "aa0c7cad4edc66a14c410667b54345a3c6e6c27c482cf3434a0e162612a62a4f"
},
"reused_proofs": {
"docs/proofs/workshop-delivery-link-20261102.json": "f84d9f219d4b4ef41d92edbbc0ad9f0c433da6ef1fa66b9d22738b615649be1f",
"docs/proofs/workshop-stock-20261102.json": "c13b22eed190e379d8311a8e02586e201f993a89bfc4490be5d9d325d6ca00c3",
"docs/proofs/stock-read-load-20261102.json": "4fc1d7d13d480a30966b259611de1066fc22ef31f7a0e782da4872211801c72e",
"docs/proofs/stock-receipt-link-20261102.json": "b763ab326abf49271d16b32d22f01a8a8d31d1ab015141e42dcf5963ee914143"
},
"preservation": {
"new_qa_schemas_and_actors_only": true,
"regression_not_reset": true,
"six_protected_records_untouched": true,
"blocked_cache_untouched": true,
"demos_untouched": true,
"previous_association_proofs_unchanged": true,
"real_rights_or_data_changed": false,
"indices_in_qa_fixture_only": true,
"purchasing_activation": false,
"publication": false,
"checkpoint": false
},
"limits": [
"One origin may not span multiple deliveries.",
"Consumed-material compensation and amendment/release of confirmed allocations are not implemented.",
"Returns accept quantity only: no lots, reservations, quality/quarantine or spare parts.",
"Native Purchasing return command not integrated; local artifact alone is not runtime integration.",
"Operational installer and one installed procurement-to-workshop composition pending.",
"No write-load benchmark or deployment-capacity evidence; no browser interaction or visual review."
],
"visual_review_pending": true,
"deployment_capacity_validated": false
}
@@ -0,0 +1,13 @@
{
"kind": "static_impact_render_and_source_checks",
"allocation_zero_effect": true,
"remaining_quantity_visible": true,
"return_positive_effect_visible": true,
"physical_receiving_checkbox_required_in_source": true,
"explicit_treatment_choice_in_source": true,
"history_controls_and_query_in_source": true,
"source_sha256": "8adc2fcf8818a6b5b0c51f55520f6e60811c03a46c0b5711bcff880b6df26884",
"backend_requests": 0,
"browser_interactions_tested": false,
"visual_review": false
}
+231
View File
@@ -0,0 +1,231 @@
{
"date": "2026-11-02",
"increment": "WORKSHOP-STOCK-ISSUE-SIM-v1",
"status": "local_synthetic_implementation",
"tests": {
"reused_passing_cases": {
"file": "workshop-stock-1793632450233.xml",
"sha256": "8623c2a85428491d04eb90c0f162a1587226f9ab9c276534463f019472fc0f68",
"tests": 4,
"assertions": 154,
"cases": [
"test_individual_impact_independence_exact_issue_and_replay",
"test_client_unverified_fraction_and_unknown_delivery_do_not_debit",
"test_stale_book_mapping_permission_scope_and_failure_recovery",
"test_concurrent_confirmation_has_one_claim_and_movement"
],
"selection": true,
"whole_run_tests": 5,
"whole_run_failures": 1,
"whole_run_errors": 0
},
"corrected_source": {
"file": "workshop-stock-1793632791460.xml",
"sha256": "9141a3b9cba9255b6ce34abf1167cfc45151546d26ec3253ee240785ad246e1f",
"tests": 1,
"assertions": 39,
"cases": [
"test_corrected_source_requires_review_and_never_consumes_the_same_origin_twice"
],
"selection": false,
"whole_run_tests": 1,
"whole_run_failures": 0,
"whole_run_errors": 0
},
"scope_and_command": {
"file": "workshop-stock-1793633025634.xml",
"sha256": "cf0643f3c5444efc3e65294790fd3e111e3e9a14a30af4a6f9399bbf93c04c4c",
"tests": 1,
"assertions": 29,
"cases": [
"test_other_company_cannot_read_or_confirm_origin_and_changed_command_is_refused"
],
"selection": false,
"whole_run_tests": 1,
"whole_run_failures": 0,
"whole_run_errors": 0
},
"native_issues": {
"file": "private/stock-receipt-54f39ed20d16/issue-affected-junit.xml",
"sha256": "aed6359ba4216e10bb89f34d40e0314fc9efb0f8dedeea40551c3302f31b8525",
"tests": 25,
"assertions": 125,
"cases": [
"issues are exact, idempotent and cannot make stock negative",
"transfer creates exactly two opposite ledger entries and rejects repeated references",
"counts preserve theoretical quantities and adjustments apply a justified difference once",
"intervening receipts and issues invalidate counts and stale count forms",
"operational role cannot be replaced by administration or other profiles with data set &quot;(App\\Enums\\PurchasingRole Enum (Admin, 'admin'))&quot;",
"operational role cannot be replaced by administration or other profiles with data set &quot;(App\\Enums\\PurchasingRole Enum (Finance, 'finance'))&quot;",
"operational role cannot be replaced by administration or other profiles with data set &quot;(App\\Enums\\PurchasingRole Enum (Procurement, 'procurement'))&quot;",
"operational role cannot be replaced by administration or other profiles with data set &quot;(App\\Enums\\PurchasingRole Enum (DepartmentHead, 'department_head'))&quot;",
"operational role cannot be replaced by administration or other profiles with data set &quot;(App\\Enums\\PurchasingRole Enum (Requester, 'requester'))&quot;",
"foreign company resources cannot be used with data set &quot;('warehouse_id')&quot;",
"foreign company resources cannot be used with data set &quot;('destination_warehouse_id')&quot;",
"foreign company resources cannot be used with data set &quot;('stock_item_id')&quot;",
"foreign company resources cannot be used with data set &quot;('responsible_id')&quot;",
"audit failure rolls back both halves of transfer and operation",
"operations are immutable and new public screen contains only demonstration props",
"invalid precision and missing justification or destination do not write with data set &quot;('quantity', '-1')&quot;",
"invalid precision and missing justification or destination do not write with data set &quot;('quantity', '0')&quot;",
"invalid precision and missing justification or destination do not write with data set &quot;('quantity', '0.0001')&quot;",
"invalid precision and missing justification or destination do not write with data set &quot;('reason', ' ')&quot;",
"invalid precision and missing justification or destination do not write with data set &quot;('destination', '')&quot;",
"invalid precision and missing justification or destination do not write with data set &quot;('responsible_id', null)&quot;",
"positive adjustments credit only the difference and matching counts create no movements",
"failure creating transfer credit rolls back its debit",
"stock views isolate operations and counts from other companies",
"form encoded retry identifiers and equivalent quantities retain idempotency"
],
"selection": false,
"whole_run_tests": 25,
"whole_run_failures": 0,
"whole_run_errors": 0
},
"native_lots": {
"file": "private/stock-receipt-0119bb873c56/issue-lots-junit.xml",
"sha256": "4ea8597200ebd761cb9460acf165e1baaa4f7b7b1b84690a0bfe749b73ddf6dc",
"tests": 2,
"assertions": 10,
"cases": [
"FEFO consumes earliest expiry and preserves the single physical ledger with exact partitions",
"expiry and hold remove usable quantity without changing physical stock"
],
"selection": false,
"whole_run_tests": 2,
"whole_run_failures": 0,
"whole_run_errors": 0
},
"navigation": {
"file": "junit-focused.xml",
"sha256": "1452d1702bae6c8c3162750030b76c1167b88250ac03766fb8cba5fc4cae3549",
"tests": 8,
"assertions": 90,
"cases": [
"test_explicit_selection_direct_access_and_old_generation",
"test_company_configuration_and_revocation_are_checked_again",
"test_development_discovery_never_grants_operations_or_applies_in_production",
"test_failed_selection_preserves_context_and_audit_contains_module_without_token",
"test_local_environment_and_copied_profile_cannot_enable_discovery_for_client_database_configuration",
"test_shared_records_require_explicit_association_and_company_scope",
"test_unassociated_legacy_records_remain_in_explicit_administrative_inventory",
"test_draft_creation_preserves_source_history_and_does_not_share_dependencies_implicitly"
],
"selection": false,
"whole_run_tests": 8,
"whole_run_failures": 0,
"whole_run_errors": 0
}
},
"totals": {
"tests": 41,
"assertions": 447
},
"proof_selection": "Four passing cases reused from an intermediate five-case run with one fixture-date failure. Only the corrected case and the additional scope case were rerun; the failed case is excluded from reused results.",
"scenario_asserted": {
"initial_physical_milli": "10000",
"consumption_milli": "2000",
"final_physical_milli": "8000",
"movements_added": 1,
"claims_added": 1,
"same_book_observed_by_stock": true,
"preparer_cannot_confirm": true,
"replay_original_movement": true,
"stale_book_map_rights_context_refused": true,
"unknown_previous_issue_refused": true,
"client_delivered_unverified_fraction_insufficient_refused": true,
"failure_after_claim_insert_atomic_and_recovered": true,
"other_company_sources_and_proposals_not_visible": true,
"other_company_prepare_and_confirm_refused": true,
"wrong_module_context_refused": true,
"changed_idempotency_body_refused": true
},
"concurrency_asserted": {
"processes": 2,
"lock": "company row held by first transaction",
"pg_blocking_pids_observed": true,
"second_after_release": "200 replay same movement",
"one_movement_and_claim": true
},
"correction_asserted": {
"old_proposal_after_source_correction": "409",
"verified_v2_after_new_review_physical_milli": "7000",
"verified_v3_after_consumption": "409 without second effect"
},
"package": {
"id": "tempo-inventory-issue",
"version": "0.1.0",
"files": {
"bootstrap.php": "3e6c7c698279f3ffb865131e79b3f89e5ec3e4aa9114782df62e17712f48df6b",
"src/IssueMovementWriter.php": "36d59bce53b8447516399974fc7d08beaa5d92b7b45a416014bd855e03fdf409"
},
"manifest_sha256": "3c24d9e9fb99bfbb274077495c3a42ddb7eccab06b5c6a956cd739b2bc9b56f0",
"source_and_artifact_equal": true
},
"source_sha256": {
"app/Modules/Workshop/WorkshopStock.php": "bfbcc17b9ff0caa4ed46dad7d1276dd8e508166eecafd2a3c6cbb4c5b54fbab0",
"app/Modules/Workshop/Http/WorkshopStockController.php": "c6116f317a8ef6dd74f66599797b77da990f26aa9b6279142804f4974bf0d00d",
"resources/js/WorkshopStockWorkspace.jsx": "7bbc2c5c8a6360b601b9c00772fcd9bbf16722cd087431ecc4274ef1c5031338",
"resources/js/WorkshopMenuWorkspace.jsx": "098b990adcbafc387bd447e77f3238a8ec984218812d736bcb33e3da22f4937c",
"config/workshop_stock.php": "603c5ea718e59b9e43c6dc01a4238813a56a63755fe60b63354b3957f6a0af49",
"tests/Feature/WorkshopStockTest.php": "450f15558cb2727db8e1f60ab95ffaf12124dacf6c9e561611d82e56bdd17fd4",
"tests/Support/workshop-stock-worker.php": "bdad20fd4f58714c36c20d3c271ac31fdd92a4083cedf31341938b501fd73c2d",
"../compras/app/Services/StockIssueMovement.php": "61a649d26f4bf1e96becc3ff213bab0a029c47040d1368e99cc558bd98649de6",
"../compras/app/Services/StockWorkflow.php": "18ddaa075432b84c0b0ee5241ff56ab9de9aa8e8db4e6132693bc7fd904b3a58"
},
"qa_postcheck": {
"qa_identity": {
"db": "sgf_tempo_test",
"role": "sgf_test_runner",
"port": 55439,
"cluster": "sgf_modular_regression_2576427d1939"
},
"temporary_grants_remaining": 0,
"constraint_sha256": "40046092cba51f1b46d26d5f0da8af47e8336e90a8d50b8de3a8c390758f1783",
"operational_workshop_stock_bindings": 0,
"read_only": true
},
"static_ui": {
"proof": "docs/proofs/workshop-stock-ui-20261102.json",
"sha256": "65aca7809af88f80e50c52e9ab13ee9ba52e047b17b183c048c8e1c0dd03b3fc",
"kind": "static_render",
"permission_separation": true,
"pending_notice_removed_for_authorized_view": true,
"loading_not_zero": true,
"backend_requests": 0,
"visual_review": false
},
"build": {
"tool": "pinned Node 24.22.1 / Vite 8.3.5",
"passed": true,
"manifest_sha256": "205a739db091d58850827051e840cbf367437595c370418b2d6475848497be04",
"visual_review": false
},
"reused_evidence_sha256": {
"docs/proofs/stock-receipt-link-20261102.json": "b763ab326abf49271d16b32d22f01a8a8d31d1ab015141e42dcf5963ee914143",
"docs/proofs/stock-read-load-20261102.json": "4fc1d7d13d480a30966b259611de1066fc22ef31f7a0e782da4872211801c72e",
"docs/proofs/stock-read-composition-20261102.json": "bb129ab22f424a5d3333f9b851062bc6284fd514b9962e0df04b3efd22d951a6"
},
"preservation": {
"writes_confined_to_new_synthetic_fixtures": true,
"regression_not_reset": true,
"six_protected_records_untouched": true,
"blocked_cache_untouched": true,
"demos_untouched": true,
"previous_association_proofs_unchanged": true,
"real_grants_or_data_changed": false,
"purchasing_candidate_activation": false,
"publication": false,
"checkpoint": false
},
"limits": [
"Quantity-only new eligible workshop origins; lots/reservations/spare parts refused.",
"Reconciliation of existing deliveries, partial allocation, returns and compensation not implemented.",
"Initial stock in workshop fixture is synthetic; previous native receipt proof is separate, not an installed single end-to-end ERP scenario.",
"Conference tables are QA fixture only; operational installer and real rights not applied.",
"Source list paginated 25, latest 25 proposals only.",
"PostgreSQL tested; new write-load capacity and other drivers unvalidated."
],
"visual_review_pending": true,
"deployment_capacity_validated": false
}
@@ -0,0 +1,339 @@
{
"date": "2026-11-02",
"increment": "WORKSHOP-STOCK-PROPOSAL-CLOSURE-SIM-v1",
"status": "local_synthetic_implementation",
"proofs": [
{
"file": "workshop-stock-1793641924753.xml",
"sha256": "cc0d1b6a5f55586303a8d6cb740f03b1bdfb72c7da7aee6e99edb890beb2a8c5",
"tests": 10,
"assertions": 319,
"failures": 1,
"errors": 0,
"selected_passing_cases": 9
},
{
"file": "workshop-stock-1793642136561.xml",
"sha256": "0b1e3e4aa6f139cb042b9bd704e374aefd8b08dff8ac46956219cd7d08497056",
"tests": 1,
"assertions": 41,
"failures": 0,
"errors": 0,
"selected_passing_cases": 1
},
{
"file": "workshop-stock-1793642158453.xml",
"sha256": "462f040b1ca17b2a7478d4f1bef68c89523281b208cd98450373df21e3c09705",
"tests": 22,
"assertions": 820,
"failures": 0,
"errors": 0,
"selected_passing_cases": 22
},
{
"file": "workshop-stock-1793642231864.xml",
"sha256": "3182db7e3e3379bc54b4b53aeb939cf9f8f0372bec115c031c1efaa432703894",
"tests": 1,
"assertions": 28,
"failures": 0,
"errors": 0,
"selected_passing_cases": 1
}
],
"selection": "All current WorkshopStockTest cases covered exactly once by name, selecting passing cases only. Initial history assertion omitted the schema-discovery SELECT: its failure is retained, excluded and replaced by the targeted passing rerun distinguishing one catalogue lookup and one batch data lookup. Other passing cases were reused. No native, association or unrelated suites repeated.",
"totals": {
"distinct_tests": 33,
"assertions": 1181
},
"closure_cases": {
"tests": 11,
"assertions": 361
},
"selected_cases": [
{
"name": "test_closure_withdraws_stale_preview_and_replay_does_not_reopen_it",
"assertions": 50,
"proof": "workshop-stock-1793641924753.xml"
},
{
"name": "test_closure_requires_current_right_context_independence_hash_and_version",
"assertions": 35,
"proof": "workshop-stock-1793641924753.xml"
},
{
"name": "test_closure_of_confirmed_proposal_requires_separate_physical_correction",
"assertions": 28,
"proof": "workshop-stock-1793641924753.xml"
},
{
"name": "test_closure_failure_rolls_back_audit_and_recovers_with_one_decision",
"assertions": 27,
"proof": "workshop-stock-1793641924753.xml"
},
{
"name": "test_closure_cannot_cross_company_or_unit_even_with_shared_source_binding",
"assertions": 25,
"proof": "workshop-stock-1793641924753.xml"
},
{
"name": "test_closure_for_delivery_allocation_and_return_never_moves_or_claims_material",
"assertions": 39,
"proof": "workshop-stock-1793641924753.xml"
},
{
"name": "test_closure_withdrawal_wins_over_concurrent_confirmation",
"assertions": 29,
"proof": "workshop-stock-1793641924753.xml"
},
{
"name": "test_closure_confirmation_wins_over_concurrent_withdrawal",
"assertions": 29,
"proof": "workshop-stock-1793641924753.xml"
},
{
"name": "test_closure_concurrent_identical_withdrawals_replay_one_decision",
"assertions": 30,
"proof": "workshop-stock-1793641924753.xml"
},
{
"name": "test_closure_history_filters_and_pages_use_only_the_current_page",
"assertions": 41,
"proof": "workshop-stock-1793642136561.xml"
},
{
"name": "test_stock_return_unconsumed_material_restores_only_remaining_quantity_once",
"assertions": 63,
"proof": "workshop-stock-1793642158453.xml"
},
{
"name": "test_stock_return_refuses_consumed_client_unverified_excess_and_stale_capacity",
"assertions": 52,
"proof": "workshop-stock-1793642158453.xml"
},
{
"name": "test_stock_return_failure_after_decision_rolls_back_movement_and_recovers",
"assertions": 32,
"proof": "workshop-stock-1793642158453.xml"
},
{
"name": "test_stock_return_concurrency_cannot_restore_quantity_twice",
"assertions": 40,
"proof": "workshop-stock-1793642158453.xml"
},
{
"name": "test_stock_return_revoked_right_stale_context_and_foreign_company_do_not_write",
"assertions": 36,
"proof": "workshop-stock-1793642158453.xml"
},
{
"name": "test_partial_delivery_links_multiple_origins_without_debit_and_rechecks_remaining",
"assertions": 60,
"proof": "workshop-stock-1793642158453.xml"
},
{
"name": "test_partial_delivery_requires_enabled_capability_and_rolls_back_allocation_failure",
"assertions": 26,
"proof": "workshop-stock-1793642158453.xml"
},
{
"name": "test_partial_delivery_concurrent_proposals_cannot_overallocate",
"assertions": 41,
"proof": "workshop-stock-1793642158453.xml"
},
{
"name": "test_history_filters_and_pagination_preserve_order_and_scope",
"assertions": 38,
"proof": "workshop-stock-1793642158453.xml"
},
{
"name": "test_delivery_link_has_zero_effect_independent_decision_and_no_duplicate",
"assertions": 44,
"proof": "workshop-stock-1793642158453.xml"
},
{
"name": "test_delivery_link_refuses_mismatch_stale_book_and_recovers_from_failure",
"assertions": 39,
"proof": "workshop-stock-1793642158453.xml"
},
{
"name": "test_delivery_link_can_reconcile_fully_depleted_stock_without_new_issue",
"assertions": 30,
"proof": "workshop-stock-1793642158453.xml"
},
{
"name": "test_delivery_link_rejects_reversal_and_does_not_adopt_history",
"assertions": 20,
"proof": "workshop-stock-1793642158453.xml"
},
{
"name": "test_delivery_link_refuses_missing_original_hash",
"assertions": 21,
"proof": "workshop-stock-1793642158453.xml"
},
{
"name": "test_delivery_link_other_company_cannot_prepare_or_confirm",
"assertions": 26,
"proof": "workshop-stock-1793642158453.xml"
},
{
"name": "test_individual_impact_independence_exact_issue_and_replay",
"assertions": 45,
"proof": "workshop-stock-1793642158453.xml"
},
{
"name": "test_client_unverified_fraction_and_unknown_delivery_do_not_debit",
"assertions": 48,
"proof": "workshop-stock-1793642158453.xml"
},
{
"name": "test_stale_book_mapping_permission_scope_and_failure_recovery",
"assertions": 31,
"proof": "workshop-stock-1793642158453.xml"
},
{
"name": "test_corrected_source_requires_review_and_never_consumes_the_same_origin_twice",
"assertions": 39,
"proof": "workshop-stock-1793642158453.xml"
},
{
"name": "test_other_company_cannot_read_or_confirm_origin_and_changed_command_is_refused",
"assertions": 29,
"proof": "workshop-stock-1793642158453.xml"
},
{
"name": "test_concurrent_confirmation_has_one_claim_and_movement",
"assertions": 30,
"proof": "workshop-stock-1793642158453.xml"
},
{
"name": "test_delivery_link_concurrent_confirmation_has_one_claim_without_movement",
"assertions": 30,
"proof": "workshop-stock-1793642158453.xml"
},
{
"name": "test_closure_absent_in_legacy_synthetic_source_does_not_disable_confirmation",
"assertions": 28,
"proof": "workshop-stock-1793642231864.xml"
}
],
"workflow": {
"withdraw_requires_original_preparer_and_current_prepare_right": true,
"reject_requires_independent_current_confirmer": true,
"explicit_reason": true,
"presented_state_version_and_source_hash_required": true,
"stale_physical_preview_can_be_closed_without_execution": true,
"confirmed_effect_cannot_be_closed_or_reversed_by_this_command": true,
"replay_same_body_actor_and_state_only": true,
"new_review_requires_new_proposal": true,
"zero_stock_effect": true,
"original_immutable": true,
"append_only_decision_with_before_after_actor_time_reason": true,
"audit_in_same_transaction": true
},
"concurrency": {
"separate_processes": 2,
"company_lock_observed_with_pg_blocking_pids": true,
"withdraw_then_confirm": "second refuses 409 after release; no physical movement",
"confirm_then_withdraw": "second refuses 409 after release; original movement retained",
"identical_withdrawals": "second replays original; one decision"
},
"history": {
"fixture_proposals": 51,
"closed": 3,
"pending": 48,
"page_size": 25,
"closure_catalog_discovery_selects": 1,
"closure_batch_data_selects": 1,
"pages_disjoint": true,
"not_a_capacity_benchmark": true,
"filters": [
"all",
"pending",
"confirmed",
"withdrawn",
"rejected"
],
"repeatable_read_read_only": true,
"no_universe_loaded": true
},
"recovery": {
"audit_failure_rolls_back_decision": true,
"retry_creates_one_decision": true,
"database_update_of_closure_refused": true
},
"source_sha256": {
"app/Modules/Workshop/WorkshopStock.php": "6460a4235fe7b0b4602b0aeb63a47f1a97e367e93baba6aa774be5fa0dac4e6e",
"app/Modules/Workshop/Http/WorkshopStockController.php": "06c9f85f926b4268636887f50458cd19fc1a467ae636dea94caba586fb463c0e",
"resources/js/WorkshopStockWorkspace.jsx": "195526f823813a47f797b9f09203d0fecde921a95138fdbda5238b0a7cc5106d",
"routes/web.php": "3c3c3bfcb0d50bbf813e8b049191ce8691f74c1396d5f32bd1d83768a3d2b1e8",
"tests/Feature/WorkshopStockTest.php": "d20cc5f2f07e1e4bef96785913bf77f45e10c107a4e823542b8ed4e90e03d7ab",
"tests/Support/workshop-stock-worker.php": "d216643380bbde379695887ec456987c20babf5f8223cac0de27ebb501f81bf3",
"config/workshop_stock.php": "603c5ea718e59b9e43c6dc01a4238813a56a63755fe60b63354b3957f6a0af49"
},
"ui": {
"proof": "docs/proofs/workshop-stock-closure-ui-20261102.json",
"sha256": "60c4f12e14f91ddfadfa35ff57b6e88f8dc4e24ad6347fbd5b25572eb149c5d4",
"kind": "static_closure_impact_render_and_source_guards",
"closure_zero_effect_visible": true,
"archival_and_new_review_visible": true,
"existing_return_impact_preserved": true,
"version_and_hash_sent": true,
"independent_action_visibility_guards": true,
"context_generation_guards": true,
"source_sha256": "195526f823813a47f797b9f09203d0fecde921a95138fdbda5238b0a7cc5106d",
"backend_requests": 0,
"browser_interactions_tested": false,
"visual_review": false
},
"build": {
"passed": true,
"manifest_sha256": "e8ba7311860444604202cfe6ad420eb35dd11858e9e7fcc815a1f26ab7512c24",
"application_asset": "public/build/assets/app-DuxcWTkD.js",
"application_asset_sha256": "847d900405d5a5a9898f243df5981114841d06f3d99772c52070c822ad7fd931",
"closure_controls_in_built_application": true,
"modules_transformed": 46,
"navigation_source_changed": false,
"extra_navigation_checker": "Existing home checker did not complete; only its verified own processes stopped. Direct Vite build and targeted closure UI proof passed. No new navigation acceptance claimed.",
"browser_interactions_tested": false,
"visual_review": false
},
"postcheck": {
"qa_identity": {
"db": "sgf_tempo_test",
"role": "sgf_test_runner",
"port": 55439,
"cluster": "sgf_modular_regression_2576427d1939"
},
"temporary_grants_remaining": 0,
"constraint_sha256": "40046092cba51f1b46d26d5f0da8af47e8336e90a8d50b8de3a8c390758f1783",
"operational_workshop_stock_bindings": 0,
"read_only": true
},
"reused_proofs": {
"docs/proofs/workshop-material-cycle-20261102.json": "4d79e563401df1e20d793ca8af9a1da228a24c86d6c887323a9e57c3ce65cc9a",
"docs/proofs/native-warehouse-return-20261102.json": "587795ab4d2b2e65d51feaf7ed5e368df715d69cb7a0480f5f2b1d802d019869",
"docs/proofs/stock-read-load-20261102.json": "4fc1d7d13d480a30966b259611de1066fc22ef31f7a0e782da4872211801c72e"
},
"preservation": {
"new_closure_table_and_index_only_in_new_synthetic_fixture_schemas": true,
"no_installed_migration": true,
"no_new_rights": true,
"temporary_qa_rights_restored": true,
"six_pending_associations_untouched": true,
"blocked_cache_untouched": true,
"demos_and_real_data_untouched": true,
"regression_not_reset": true,
"previous_proofs_preserved": true,
"publication": false,
"activation": false,
"checkpoint": false
},
"limits": [
"Closing a proposal does not correct a confirmed physical effect.",
"Legacy synthetic sources without ws_closures retain read/confirm capability; closure command returns 503 and UI does not offer closure. No operational installer created.",
"No change to native forecasting convention, lots, reservations or financial/accounting effects.",
"No browser interaction, visual acceptance or deployment-capacity validation."
],
"visual_review_pending": true,
"deployment_capacity_validated": false
}
@@ -0,0 +1,13 @@
{
"kind": "static_closure_impact_render_and_source_guards",
"closure_zero_effect_visible": true,
"archival_and_new_review_visible": true,
"existing_return_impact_preserved": true,
"version_and_hash_sent": true,
"independent_action_visibility_guards": true,
"context_generation_guards": true,
"source_sha256": "195526f823813a47f797b9f09203d0fecde921a95138fdbda5238b0a7cc5106d",
"backend_requests": 0,
"browser_interactions_tested": false,
"visual_review": false
}
@@ -0,0 +1,8 @@
{
"kind": "static_render",
"permission_separation": true,
"pending_notice_removed_for_authorized_view": true,
"loading_not_zero": true,
"backend_requests": 0,
"visual_review": false
}