# 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.