Files
SGF/docs/STOCK_READ_DELIVERY.md
T
2026-11-02 20:29:34 +02:00

77 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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.