Compare commits

...
30 changed files with 3758 additions and 9 deletions
@@ -1052,6 +1052,110 @@ Entrega agrupada preparada com os sete casos novos compatíveis;incompatibilidad
Conferência de compatibilidade:main `a7434cd2` incorporado na candidata,com apresentação/catálogo e linhas não fiscais da matriz preservados. Recuperada a adenda históricaQA13 que tinha desaparecido do manual no main;isto é perda documental,não perda do cálculo13. Só tipos/build de integração foram conferidos novamente;provas fiscais aceites conservadas. A revisão servida não foi consultada nesta passagemQA.
## 26/10/2026 — Cumulações L7 entregues pelo Git
**Instalado `f8d57bddf96b4610604a013fcc5bdd703c7dc6d5`.** A anteriora7434cd2,que já incluía632dc069,fica preservada. Main/candidata compatíveis;apresentação ecatálogo sectorial entregues entretanto mantidos. A notaQA anterior é histórica:não há pendência de instalação deste incremento.
Medição inicial:5.06GiB,com inodes suficientes,mas sem margem para o backup fresco mais o mínimo5GiB do instalador. Recuperados0.21GiB somente da cache versionada de compilaçãoNode em`/tmp/node-compile-cache`,sem gestores de pacotes ou ficheiros abertos. Fontes,node_modules,releases,backups,logs,originais eSGF mantidos;permissões/proprietário da pasta preservados. Nova capacidade:5.26GiB e21374782inodes. Backup fresco`2026-10-26T14:20:47Z`:174tabelas/369ficheiros econfiguração;restauro isolado sem rede/55441 com174checksums iguais. Após o backup restavam5.10GiB,acima do mínimo5GiB de compilação;a guarda de um segundo backup não é requisito para repetir o backup acabado de executar. Nenhum limiar foi reduzido.
Só depois destas guardas,integraçãoGit sem forçar histórico;release anterior activa até a nova estar pronta. Compilação,tipos econtrolos automáticos do procedimento passaram:1054testesfrontend,API59testes/317asserções,preservação1teste/3106asserções. Reutilizadas as provasQA12testes/API133/UI/relatórios,não repetidas por iniciativa desta entrega. Conferidos4ficheiros fiscais do delta,68protegidos,31originais,369persistentes/configuração e174tabelas;172tabelas de negócio mantidas,cache/sessões reconciliadas com eventos operacionais/acessos públicos. Schema,roles/grants epermissões iguais;sem migrações/importações/escrita privada sintética. Revisão/manifest servidos,15marcadores,4assets eHTTP200 do simulador conferidos.
O recorte mantém a diferençaCBF16 de25MZN aplicada uma vez,com15recuperados já incluídos nos75deduzidos;depois aplica16% à base cooperativa integralmente elegível. No caso combinado,colecta496,80MZN;com despesa autónoma qualificada,512,80+35=547,80MZN. Valores são colecta simulada,não saldo finalL8. IncompatibilidadeCBF4/13,excepções sem correspondência e informação em falta permanecem explícitas;nenhum benefício é escolhido ouapagado automaticamente.
Após a instalação ficaram4.14GiB livres. Antes de outra compilação,voltar a resolver capacidade contra o mínimo existente e o backup dessa execução;esta entrega foi concluída e não autoriza apagar releases,backups ou provas. SaldoL7 e primeiro incrementoL8 são discriminados na secção seguinte. Recibo:`docs/investmoz/simulations/irpc-l7-combinations-delivery-20261026.json`;provas:`outputs/irpc-l7-combinations-delivery-20261026/`. **L7 parcial;L8 conserva saldo final.**
## 26/10/2026 — Saldo consolidado de L7 e primeiro incremento delimitado de L8
**L7 parcial,com a entrega de cumulaçõesf8d57bdd registada acima.** Deixam de estar pendentes de instalação a combinaçãoCIRPC12+CBF16 no recorte qualificado,a separação do imposto autónomo61(4) e os estados de incompatibilidade/falta/excepção não correspondida demonstrados. Isso não implementa todas as cumulações nem os tratamentos abaixo. Fontes oficiais e provas aceites permanecem válidas;documento em falta limita só o caso/campo que dele dependa.
| CódigoL7 ainda por implementar | Exemplo e condição concreta de retoma |
| --- | --- |
| Outras origens/segregações de despesas autónomas | Despesa100 com apenas60 correspondidos em36g ou encargo fora do resultado:ligar origem/parcela e incidência61(4),sem segundo acréscimo. |
| Cooperativas mistas/retidas e demais entidades9–14 | Base agrária com serviços não abrangidos ou rendimentos sujeitos a retenção:segregar proveitos/custos/base e aplicar o artigo específico;não reduzir tudo a16%. |
| ExtensõesCBF16 e outras combinações | Activo anterior a2025,usado/reabilitado/reavaliado,método/período fora da cobertura,ou excepção expressa à não cumulação:ligar regra temporal/base/método e disposição,ordem e limites à parcela;reutilizar activos/quotas,sem reescrever o passado. |
| Mais-valias61-A e operações54–56/41-A | Ganho já incluído no resultado ou transferência de activo/perda:implementar apuramento e reconciliação próprios,sem dupla incidência ou compensação presumida. |
| CBF17–19 e direito potencial15 | Formação/investimento com activos e despesas elegíveis/excluídos:implementar base,limite,janela temporal e compatibilidade. Direito/origem do crédito emL7;utilização anual e saldo emL8. |
| Regimes sectoriais/territoriais e benefícios específicos | EstatutoZEE ou projecto de infra-estruturas:aplicar disposição/período efectivos e excepção quando prevista;endereço/sector não concede benefício. |
| TransporteL7M20/M22 | Efeito calculado sem campo/edição correspondente:identificar exemplar,instrução,campo e representação;conservar o cálculo exacto independente. |
**Documentos por caso,distintos de código:**natureza/parcela/período;estatuto/reconhecimento exigido ou norma de excepção;saldos anteriores e distinção de exclusão temporária/permanente;disposição/ordem/limites da combinação;exemplar/edição/campo/representação. Não pedir nova validação genérica da autenticidade de fontes aceites,nem repetir pesquisas anteriores sem informação nova. Não preencher campo,código,taxa ou saldo por presunção.
### L8 — primeiro percurso a implementar em QA:colecta→pagamentos comprovados→saldo simulado
**Delimitado,não implementado ou instalado nesta passagem.** Recorte inicial:IRPC de residente no regime geral,ano civil2026,MZN,com colecta corrente determinada e suportes que permitem reconciliar o fecho. Parte de uma execuçãoL6 válida ou deL7 válida quando os efeitos aplicáveis estejam qualificados;guarda chave/versão/NUIT/período e valores de origem. Não soma colectaL6 com colectaL7 nem a colecta ordinária com uma colecta combinada que já a inclua. Não usa uma versãoL6 para ignorar um efeitoL7 positivo ou pendente que afecte o mesmo fecho. Um caso ordinário independente não espera pela implementação de outro benefício ou por um campoM20/M22 desconhecido.
**Dados reutilizados e qualificações novas apenas onde necessárias:**
1. **Colecta:**reutilizar a execução e as condições existentes,distinguindo colecta ordinária,imposto autónomo e colecta combinada. O primeiro fecho completo limita-se aos casos com ausência documentada de tributação autónoma/mais-valias que exija liquidação própria. Se existir imposto autónomo positivo,a parcela ordinária pode ser apresentada,mas não como saldo total até corresponder a articulação;não o apagar ou compensar por pressuposto.
2. **Retenções sofridas:**reutilizarL5 apenas quando `direction=received`,natureza `on_account`,origem efectiva,documento/prova e montante sofrido reconciliados,mesmo sujeito/NUIT/período e rendimento incluído na base apropriada. Retenção entregue pela empresa por pagamento a terceiros,retenção definitiva,mera projecção,guia sem pagamento ou montante ainda não comprovado não são crédito próprio. EmL7cooperativa,a declaração de ausência de rendimentos retidos não pode coexistir silenciosamente com retenção recebida positiva;esse caso exige a segregação própria,sem bloquear o regime normal independente.
3. **Pagamentos por conta efectuados:**registar/reutilizar comprovativo,identificador,data,exercício,sujeito e montanteMZN;reconciliar parcelas e pagamentos sem dupla utilização. Neste primeiro incremento,não calcular automaticamente a obrigaçãoPPC a partir do exercício anterior,nem transformar tesouraria prevista em pagamento efectuado.
4. **Outros créditos/PEC:**reutilizar a informação existente e distinguir valor conhecido,ausência declarada e falta de informação. O primeiro percurso completo exige ausência documentada dePEC e créditos por dupla tributação/investimento/outros créditos ainda sem limite/ordem correspondidos. Presença positiva mantém a parcela/fecho dependente indeterminado;não usar zero. CBF15 potencialL7 não é automaticamente crédito anual utilizável. PEC não se transforma em montante reembolsável nem recebe transporte de3/5anos por presunção.
5. **Identidade/duplicação:**contrapartes e documentos existentes são reutilizados;qualificar beneficiário e NUIT do próprio sujeito. Deduplicar por origem/documento/comprovativo e controlar afectações parciais;um comprovativo não pode aparecer integralmente em retenções ePPC,ou em dois exercícios. Preservar valores declarados e histórico,sem consumo de saldo oficial.
**Resultado e sequência a demonstrar:**colecta válida→deduções admissíveis e respectivas ausências→retenções efectivamente sofridas por conta→PPC comprovados→saldo aritmético→aplicação das regras de cobrança/reembolso do recorte→montante simulado a pagar ou recuperar. Mostrar a decomposição e o sinal;zero só com entradas completas ou ausência documentada. Informação em falta não transforma a colecta em saldo final. Como a base nasce do plano,o resultado continua uma simulação identificada,não autoliquidação submetida,pagamento efectuado ou reembolso deferido/recebido.
**Fontes já disponíveis para o cotejo dirigido de implementação:**CIRPC63/67,natureza das retenções com as alteraçõesLei12/2025;RegulamentoDecreto9/2008 art21(2–5),ordem/limites das deduções,eart27(1–2/6),pagamentos e reembolso. O exemplar aceite prevê no27(6) um mínimo de100MZN;esse parâmetro e a fronteira devem ser ligados à versão/período aplicáveis antes de activar o consumidor,não inferidos de um rótulo de formulário. O cotejo de aplicabilidade/alterações desta regra é trabalho de implementação da fonte aceite,não pedido de certificação genérica nem reabertura dos cálculosL6/L7. Arts64–66/PEC e créditos específicos mantêm as suas regras próprias;juros/multas/calendário,geração de guias,submissão e processamento de reembolso seguem incrementos próprios.
| Critério de aceitação a executar,sem prova reivindicada agora | Exemplo sintético proposto |
| --- | --- |
| Saldo positivo com pagamentos/retencões válidos | Colecta1408−retenção sofrida300−PPC500=608MZN de saldo aritmético;qualificar valor a pagar segundo a regra aplicável. |
| Saldo negativo | Colecta1408−retenção1000−PPC600=−192MZN;identificar192 a recuperar no recorte,se a regra permitir,sem afirmar reembolso recebido. |
| Zero e fronteiras do mínimo | Colecta1408−408−1000=0;demonstrar os lados inferior/igual/superior do mínimo do parâmetro versionado,sem arredondamento novo. |
| Ausência vs informação em falta | Ausência documentada de retenções/PPC/outros créditos permite saldo com parcelas zero justificadas;suporte ou natureza por determinar mantém só o fecho dependente indeterminado. |
| Reutilização e dupla dedução | Seleccionar retenção recebida e comprovativo existentes,recusar pagamento a terceiros/retenção definitiva/duplicado e demonstrar conservação dos originais e cenários anteriores. |
| Cálculo→gravação→recuperação→relatório | Novo livro/snapshotL8 ligado à chave da colecta e às provas seleccionadas;resultado13/14 eL5 anteriores imutáveis;mudança da fonte invalida a fotografia corrente sem recalcular históricos. Relatório/exportação apresenta colecta,abatimentos,saldo e lacunas concordantes. |
Só serão demonstradas estas novas regras/efeitos,emQA isolada e com as guardas existentes. Fracções continuam exactas;representação/campos oficiais sem correspondência ficam identificados e não bloqueiam cálculo independente. Pagamentos noutra moeda,períodos especiais,PEC/créditos positivos,liquidação autónoma e demais situações ficam no saldo concreto deL8,com condição de retoma por regra,origem,limite,período e prova. A documentação deste recorte não é novo cálculo executável.
### Esforço global:referência inicial não é previsão actual
As240–416horas deL8–L14 permanecem identificadas como referência inicial de planeamento,não saldo actual nem prazo assumido. Antes de estimar o conjunto:reconciliar por lote o que já está implementado/reutilizável e o que falta em código;descontar provas aceites sem as repetir;separar espera documental;incluir resíduosL1–L7,integrações/entregas eL15–L16,SISA/encargos imobiliários. Campos de entrada,fontes inventariadas ou percentagens isoladas não provam percurso executável completo. Contar apenas o delta necessário e não somar duas vezes componentes partilhados. Esta passagem entregaL7 e delimitaL8;gere uma estimativa reconciliada futura,sem converter os intervalos iniciais numa promessa global. **L7 parcial;saldo finalL8 ainda não implementado nesta entrega.**
## 26/10/2026 — L8: primeiro saldo anual simulado demonstrado em QA
**QA concluído em `11a6cee9`; ainda sem instalação.** `f8d57bdd` permanece a entrega comunicada no portal. Este incremento reutiliza a colecta corrente de L6 ou o total ordinário L7 aplicável, sem somar ambos nem contornar um tratamento pendente. Recorte: sujeito residente no regime geral, ano civil de 2026, MZN, sem PEC/créditos positivos ou imposto autónomo que exijam liquidação própria. L6 operacional no âmbito demonstrado; L7 mantém o saldo parcial já discriminado. Não há nova pesquisa ou reabertura das provas aceites.
**Percurso executável:** «Preparar saldo anual L8» reutiliza NUIT, exercício e chave/versão da colecta sem substituir edições deliberadas. Selecciona os comprovativos L5 recebidos, efectivos, por conta e reconciliados; confirma o próprio beneficiário e a inclusão do rendimento na base do exercício. Retenções entregues pela empresa por pagamentos a terceiros, definitivas ou projectadas não são abatimentos próprios. PPC exige recibo, emitente, data, titular, exercício, moeda, montante comprovado, parcela utilizada e confirmação do pagamento efectivo; não usa previsões do plano nem calcula a obrigação PPC. A reutilização não apaga provas ou consome saldos oficiais.
Conhecido, ausência declarada com suporte e informação em falta são estados distintos. Ausência contraditória, titular/exercício divergente, prova em falta ou origem desactualizada mantêm o saldo dependente indeterminado. A identidade normalizada do emitente/comprovativo detecta repetição mesmo com data alterada; a mesma prova não pode ser retenção e PPC. Controla limites do comprovativo e da afectação L5, incluindo parcelas em outros contextos do mesmo dossier. São simulações alternativas, sem reserva central ou consumo de crédito fiscal entre dossiers independentes.
| Caso demonstrado | Resultado L8 simulado |
| --- | --- |
| Colecta 1 408 − retenção sofrida 300 − PPC 500 | **608 MZN a pagar**. |
| Colecta 1 408 − retenção sofrida 1 000 − PPC 600 | Saldo aritmético −192: **192 MZN a recuperar**, sem afirmar reembolso recebido. |
| Colecta 1 408 − retenção 408 − PPC 1 000 | Saldo zero, com parcelas completas. |
| Ausência declarada de retenções/PPC, PEC ausente e outros créditos conhecidos zero | 1 408 MZN a pagar; estados conhecidos/ausentes conservados. |
| PPC por comprovar, prova repetida ou PEC positivo ainda sem regra própria | Saldo a pagar/recuperar indeterminado; entradas e subtotais conhecidos conservados. |
| Fronteiras do mínimo: saldos ±99,99 e ±100 | Aritmética exacta; abaixo de 100 MZN sem cobrança/reembolso neste recorte; em 100 aplica pagar/recuperar. Sem arredondamento ou transporte de crédito inventado. |
| Colecta anual L7 acelerada aceite de 1 996,80, sem abatimentos declarados | Reutilizada uma vez: saldo simulado 1 996,80, sem somar a referência L6 nem recalcular o benefício. |
**Fontes e limites:** CIRPC arts. 63/67, Lei 34/2007 e natureza da retenção na redacção aplicável da Lei 12/2025; Regulamento Decreto 9/2008 arts. 21(2–5) e 27(1–2/6). O mínimo de 100 MZN do art. 27(6) está ligado ao recorte ordinário de 2026; as alterações IRPC do acervo de 2025 não substituem essa regra. Exemplares, páginas e hashes constam do recibo, com aceitação oficial anterior preservada. Não generalizar este parâmetro a períodos/regimes não correspondidos. PEC positivo, crédito de investimento, dupla tributação e outros créditos não recebem abatimento, limite, transporte ou reembolso presumidos. Um crédito potencial L7 não passa automaticamente a crédito utilizável L8.
**Gravação e recuperação:** livro opcional `irpcAnnual` no snapshot existente, por contexto, sujeito e exercício; ligado à execução da colecta e às provas L5 seleccionadas. Guarda o input e o resultado simulado, acrescenta o resultado anterior ao histórico sem o recalcular, e invalida o resultado corrente quando mudam as fontes/entradas. HTML e dossier financeiro recuperam colecta, provas/parcelas, estados, saldo, lacunas e limites concordantes. Sem preparação L8, os relatórios anteriores não ganham linhas L8. Plano, originais, livros e históricos L5–L7 permanecem imutáveis. O saldo não é declaração submetida, pagamento efectuado ou reembolso recebido.
**Provas novas:** 19 testes frontend dirigidos; API privada QA, 1 teste/170 asserções, sete casos com cálculo → gravação → recuperação → HTML/dossier; base isolada `simulator_fiscal_delta_20261021_test`, loopback 55441, guarda de identidade e transacção com rollback. Interface real: preparar, preencher só dados em falta, seleccionar prova, impedir repetição, pagar/recuperar/zero/ausência/indeterminação, guardar/recarregar/recuperar/exportar, sem erros de página. Wayfinder `--with-form`, TypeScript e build QA passaram. Comparação de 2 832 ficheiros anteriores: só três pontos de integração alterados, mais os cinco ficheiros novos do incremento; motores L5/L6/L7, fontes, fixtures, schema, configuração e permissões preservados; 31 originais iguais. Não se repetiram suites aceites de L3, ISPC, câmbio ou L5–L7. SGF TEMPO separado.
### Saldo concreto L8 após este incremento
| Código ainda por implementar | Condição concreta de retoma |
| --- | --- |
| PEC e créditos positivos: investimento, dupla tributação e outros créditos próprios | Correspondência do crédito, titular/exercício, montante efectivamente disponível, ordem, limite e transporte aplicáveis; prova de cada saldo. Não presumir reembolsabilidade ou prazo de 3/5 anos. |
| Liquidação de imposto autónomo/61-A e articulação com o saldo anual | Segregar a parcela autónoma e corresponder quais abatimentos podem incidir sobre ela; não a ignorar nem compensar automaticamente com prejuízo/PPC. |
| Períodos especiais e comprovativos noutra moeda | Corresponder exercício/data de afectação e regra cambial fiscal do pagamento; reutilizar periodização/câmbio existentes sem confirmar pressupostos por omissão. |
| Cálculo da obrigação PPC/PEC, calendários, juros/multas e guias | Regra, parâmetros, factos e vencimentos próprios por período. O registo de PPC efectuado já demonstrado não calcula a obrigação. |
| Transporte oficial M20/M22, submissão e processamento de reembolso | Edição/campo, representação de fracções e fluxo de recepção correspondidos; sem preencher campos provisórios como oficiais. |
**Esclarecimentos documentais aguardados:** permanecem as dúvidas concretas L5/L6/L7 já registadas, sem nova pesquisa repetida. Exemplo: cooperativa com rendimentos mistos/retidos requer segregação antes de utilizar retenção positiva; excepção de cumulação exige disposição, período e limites correspondidos; campo M20/M22 divergente requer edição/campo exactos. Cada falta só bloqueia o seu caso. Ausência de documento num cenário não bloqueia o saldo normal independente acima.
**Próxima entrega:** compatibilidade conferida com `origin/main` em `f8d57bdd`, sem incorporar runtime do checkout raiz. Nenhum acesso ou operação no servidor nesta passagem. Os 4,14 GiB são o valor comunicado, não medição nova; antes de instalar, medir espaço/inodes, confirmar capacidade para backup/restauro fresco e compilação isolada, mantendo a versão activa até a nova estar pronta. Recibo: `docs/investmoz/simulations/irpc-l8-first-qa-20261026.json`; provas: `outputs/irpc-l8-settlement/`. Reprodução só do delta: `node --test tests/frontend/irpc-annual-settlement.test.mjs`; `php tools/irpc-annual-settlement-qa.php routes`; `php tools/irpc-annual-settlement-qa.php test`; `tsc --noEmit`; build com `INVESTMOZ_QA_BUILD=1`. **L8 parcial, QA pronto, sem instalação.** A referência inicial de 240–416 horas L8–L14 não é previsão actual; permanece necessária a reconciliação do trabalho reutilizado, resíduos e L15–L16 antes de assumir prazo global.
## 27/10/2026 — entrega L8 preparada; instalação adiada por capacidade
**Candidato `14360748` pronto; não instalado.** A conferência SSH autenticada de 27/10, 06:05 UTC (08:05 em Moçambique), confirmou `f8d57bdd` como revisão activa e `main` remoto. Compatibilidade por ancestralidade, pacote QA e 168 ficheiros do destino conferidos: 134 ficheiros protegidos, três integrações anteriores e 31 originais. O delta executável continua limitado a cinco ficheiros L8; os 19 testes, API/170 asserções, interface, recuperação/relatórios, tipos e build aceites foram reutilizados, sem nova ronda.
**Impedimento concreto:** partição `/dev/md2`, montada em `/`, com 4 402 343 936 bytes livres (**4,10 GiB**) e 21 340 182 inodes disponíveis. Inodes suficientes face à referência da release (31 259 entradas). O instalador existente exige **5 GiB livres após o backup**; com a referência observada do backup anterior de 175 917 490 bytes, faltam pelo menos **1,07 GiB adicionais antes do backup**. É uma estimativa mínima de capacidade, a medir novamente; não uma autorização para reduzir o limiar. Caches regeneráveis de Composer/Node somam cerca de 0,12 GiB e não cobrem a diferença. Diagnóstico apenas por leitura, sem limpeza de caches, releases, backups, provas, dependências ou ficheiros SGF TEMPO.
**Decisão expressa do utilizador: «Manter a entrega preparada por agora».** Não foram executados backup/restauro frescos, integração no `main` nem instalação. A versão activa foi preservada e a sessão SSH encerrada. Na retoma, seleccionar o ramo candidato `codex/irpc-l8-settlement-qa-20261026`, voltar a conferir `main` e revisão servida, medir capacidade/espaço/inodes, executar backup/restauro fresco e compilação isolada, mantendo o activo até a nova release estar pronta. Só depois conferir a revisão servida e o delta L8. As notas desta espera ficam no ramo documental `codex/irpc-l8-delivery-capacity-20261027`; não mudam o código candidato. L8 parcial, PEC/créditos próprios separados e saldo L7 preservado. Recibo: `docs/investmoz/simulations/irpc-l8-delivery-capacity-20261027.json`; provas e auxiliares preparados: `outputs/irpc-l8-first-delivery-20261027/` no checkout raiz.
## 27/10/2026 — identidade proactiva: primeiro incremento demonstrado em QA
**QA concluído em `3439f350`; sem instalação, publicação real ou análise económica validada.** Partida no `main` remoto `f8d57bdd`, conferido novamente antes da entrega. Ramo separado `codex/proactive-investment-first-qa-20261027`, worktree `C:/laragon/www/portal-investidor-proactive-qa-20261027`. A referência local `fa02c70` e o ramo `codex/proactive-investment-scope-20261027` não foram encontrados no repositório consultado; o âmbito expresso da Tempo foi suficiente e não se criou dependência desse commit. **L8 `14360748` mantém-se preparado, sem instalação e sem integração nesta candidata.** A capacidade do servidor continua fora deste trabalho local. Sem SSH, instalação, limpeza do servidor ou intervenção no SGF TEMPO nesta passagem.
@@ -1284,3 +1388,82 @@ Runtime desta correcção: `51d536b7`; inclui o percurso técnico `3439f350`/can
**Não instalado.** Antes da entrega activa, medir novamente espaço/inodes na partição do instalador e dos backups, confrontar com a necessidade efectiva de compilação isolada/backup, conferir o main então actual, executar backup/restauro fresco e manter a versão activa até a nova estar pronta. Depois conferir revisão servida e apenas o delta. A preparação dos pilotos QA não integra dados na base activa nem publica oportunidades. L8 `14360748` permanece separado; SGF TEMPO intocado. Não se fizeram SSH, limpeza, backup ou instalação nesta passagem.
Recibo: `docs/investmoz/unification/proactive-team-autonomy-qa-20261027.json`. Provas e pacote local: `outputs/proactive-team-autonomy-20261027/`. A verificação comprova que o percurso está disponível aos perfis autorizados através da interface; não declara formação da equipa, viabilidade dos pilotos ou conclusão integral dos requisitos nacionais.
## 27/10/2026 — duas entregas autorizadas: L8 primeiro, percurso proactivo depois
O responsável autorizou expressamente a execução das duas entregas pelo procedimento existente, sem nova ronda de autorização. A indicação histórica de manter preparado em `c85e772d` foi reconciliada: o commit acrescenta documentação de capacidade, sem mudar o código de L8 `14360748`/runtime `11a6cee9`. A autorização actual permite retomar; não substitui a medição de capacidade nem o backup/restauro frescos.
**Etapa1:** L8 em `c85e772d`, com a colecta válida, retenções efectivamente sofridas e PPC comprovados no recorte aceite; PEC e créditos próprios continuam separados. **Etapa2:** ramo `codex/sequential-delivery-20261027`, merge de L8 e do percurso proactivo `0ff402a1`, runtime reconciliado `74f7f93a`. A etapa2 só segue após confirmar a revisão efectivamente servida na etapa1.
O relatório comum tinha um conflito de imports. Foram conservados ambos e as chamadas de linhas anuais e proactivas. Os restantes ficheiros de runtime de cada candidata ficaram idênticos à origem. Verificação apenas da integração partilhada:6linhas anuais e10linhas proactivas recuperadas, entradas intactas e sem inferência cruzada. TypeScript e compilação QA isolada passaram; suites económicas/fiscais aceites não repetidas. Documentação de ambas as linhas conservada, sem importação de fixtures ou escrita em bases.
**Estado efectivo desta passagem: preparado, sem instalação.** O main remoto permanece `f8d57bdd` e a revisão pública servida foi conferida por HTTP em27/10/2026,10:14UTC, também `f8d57bdd`. A ponte SSH local estava `closed`; a autenticação por chave foi recusada com a chave do servidor registada e conferida. Não havia aqui uma sessão autenticada utilizável. Não foram executados backup/restauro frescos, alteração de main ou instalação. A capacidade antiga de4,10GiB é histórica e não foi apresentada como medição actual.
Retomar na sessão local com SSH autenticado, usando a autorização já registada: medir espaço/inodes na partição efectiva, comparar com compilação e backup, conferir main e revisão activa, criar e ensaiar backup fresco, instalar L8 e conferir apenas o seu delta. Depois repetir as guardas necessárias para a candidata conjunta e conferir o delta proactivo preservando L8. Manter a versão activa até a nova estar pronta. Excluir fixtures QA dos inputs de instalação; não executar seeders/importações de amostras, não publicar pilotos privados nem usar o pacote QA como cópia da base activa. SGF TEMPO separado.
Recibo de preparação: `docs/investmoz/unification/sequential-delivery-preparation-20261027.json`. Provas e instrução de passagem: `outputs/sequential-delivery-20261027/`. Os recibos de execução e as duas revisões servidas serão registados apenas depois de execução real na sessão autenticada; este recibo não os substitui.
## 27/10/2026 — L8 e percurso proactivo instalados pela sequência autorizada
Entrega1: **L8 `c85e772d`**, anterior `f8d57bdd`. Entrega2, apenas após conferir a primeira: **percurso proactivo `9fda6d6e`**, incluindo `56c0c6a7` e preservando L8. As duas revisões foram conferidas no registo do instalador e no recurso público `/build/revision.json`, com hash do manifest e marcadores compilados dos deltas. `c85e772d` conserva o código aceite de `14360748`; o merge proactivo mantém ambos os fornecedores de linhas do relatório. A referência final servida passa a `9fda6d6e`.
A tentativa proactiva em `56c0c6a7` não foi activada: um teste dependia de um ficheiro de outputs existente apenas no QA local. L8 permaneceu em serviço. A correcção `9fda6d6e` torna esse teste portátil com um exemplar mínimo sintético da projecção pública da API, sem perfis, credenciais ou pilotos reais e sem escrita em outputs. O teste dirigido passou; o código da aplicação é byte a byte idêntico a `56c0c6a7`. Não se transportou a base QA nem se saltou a guarda do instalador. A nova tentativa usou o backup/restauro ainda fresco, com capacidade e fonte activa novamente conferidas.
A ligação SSH foi restabelecida pelo responsável na janela local, sem credenciais na conversa ou nos recibos. A medição inicial encontrou91,6GiB livres e inodes suficientes; a capacidade foi novamente conferida depois de cada backup. Instalador existente e suas guardas preservados; a versão anterior permaneceu activa até a nova release estar pronta. Os controlos automáticos do instalador foram mantidos, sem nova ronda manual das provas funcionais/económicas aceites.
**Backup/restauro fresco em cada etapa:** `/var/backups/investmoz-sequential-20261027/l8/backup` e `/var/backups/investmoz-sequential-20261027/proactive/backup`. Em cada uma, dump consistente e369ficheiros persistentes/configuração verificados; restauro das174tabelas num contentor sem rede, porta55441, com contagens/checksums iguais. Recibos `backup-receipt.json`, `restore-receipt.json`, `schema-permissions-before.json`, `schema-permissions-after.json`, `preservation-receipt.json` e `operational-delta-receipt.json` conservados nesses directórios. Hashes exactos no recibo consolidado.
**Preservação demonstrada:**172tabelas de negócio intactas em cada comparação; apenas cache/sessões operacionais reconciliados individualmente por identidade/timeouts e pedidos públicos de entrega. Schema, papéis, grants, permissões e originais persistentes conservados. Fontes instaladas comparadas aos commits:996ficheiros após L8 e1000após o proactivo. Sem migrations na base activa, importação de amostras QA, seeders ou publicação dos pilotos. O instalador manteve base e storage sintéticos isolados; o storage QA fica fora da árvore servida, e a release usa os mesmos `.env` e storage persistentes por ligação.
**Âmbito:** L8 continua parcial, com PEC e créditos de regra própria separados; os resultados continuam simulações. Songo permanece privado e pendente de respostas externas; Gurué continua hipótese agrícola privada. Disponibilização técnica não confirma clientes, procura, sustentabilidade ou publicação comercial. L3, ISPC, câmbio, L6/L7 e SGF TEMPO preservados.
Recibo consolidado: `docs/investmoz/unification/sequential-delivery-installed-20261027.json`. Provas locais: `outputs/l8-proactive-install-20261027/`. Os recibos históricos de preparação/suspensão mantêm-se como histórico e deixam de representar pendência de instalação destas duas candidatas.
Recibo remoto consolidado: `/var/backups/investmoz-sequential-20261027/installed-receipt.json`;SHA256 `62584b5abb50a05303a24379a0563e8dc147e25e682dc3566bb8edf015ba9d0b`. A fixture sintética portátil é apenas input de teste, sem importação na aplicação e sem dados dos pilotos.
## 27/10/2026 — utilização real do percurso proactivo: exercício preparado, execução por observar
Reutilizadas a entrega `9fda6d6e` e as provas técnicas aceites. Roteiro no manual existente, secção «avaliação de utilização pela equipa, sem Codex»: análise privada de trabalho → evidências com proveniência → ideia com hipótese/pendências → guardar/recuperar → mesmo dossier → revisão sem duplicação. A equipa utiliza a própria conta autorizada e devolve referências internas, passo, dificuldade concreta e apoio consultado. Estado desta avaliação: **pendente de execução real**, sem resultados de participantes inventados e sem nova aprovação obrigatória da entrega.
As quatro linhas proactivas existentes (RF-CLU-003, MASTER-471012ab-0010, MASTER-9dee08d0-0067 e MASTER-471012ab-0067) conservam as provas e limitações; esta nota não promove os requisitos globais a concluídos. Não houve testes técnicos, nova instalação, alteração no portal ou contacto externo. Songo/Gurué privados; L8 parcial, PEC/créditos próprios separados. Registo: `docs/investmoz/unification/proactive-team-use-evaluation-20261027.json`. Retoma: tratar apenas os obstáculos observados pela equipa.
## 27/10/2026 — L8: PEC pago no próprio exercício, incremento em QA
**Estado:** implementado e demonstrado em QA, ainda sem instalação. O portal mantém a entrega `9fda6d6e`, segundo o recibo anterior; esta passagem não acedeu ao servidor nem alterou `main`. A avaliação real da equipa sobre o percurso proactivo continua pendente de retorno; Songo e Gurué permanecem privados.
**Recorte:** residente no regime geral, ano civil 2026, MZN; colecta corrente válida L6/L7, créditos anteriores ausentes ou conhecidos zero, sem imposto autónomo positivo. PEC é pagamento efectivamente comprovado do próprio sujeito/exercício, não estimativa de tesouraria. Reutilizados o livro anual, o vínculo à colecta, os PPC, as retenções L5 e o mecanismo de gravação/recuperação/relatório existentes.
**Regra implementada:** CIRPC, art. 66(1–2), exemplar oficial Lei34/2007, PDF18/p768-(72), conferido visualmente. A dedução PEC é a menor entre as parcelas disponíveis comprovadas e a colecta disponível antes de retenções/PPC. A colecta após PEC não fica negativa. O excedente PEC é apresentado como parcela seleccionada não deduzida: **não constitui reembolso nem transporte oficial criado pelo simulador**. Retenções/PPC ainda podem originar saldo simulado a recuperar. Créditos precedentes positivos ou desconhecidos mantêm o caso indeterminado, sem ordem ou limite presumidos.
O detalhe PEC é uma extensão opcional versionada do snapshot anual. A acção explícita «Preparar detalhe PEC» reutiliza estado/suporte anteriores, conservando o resumo e os resultados históricos. Cada prova identifica emitente/documento, pagamento efectivo, NUIT, exercício/data, moeda, montante comprovado, utilizações anteriores documentadas e parcela seleccionada. Zero utilizado exige valor e suporte; vazio não vira zero. Ausência declarada, pagamento conhecido e informação em falta permanecem distintos. Contradições não são apagadas. A identidade física do comprovativo ignora mudanças de data e confere PEC/PPC/retenções neste e noutros contextos do mesmo snapshot; parcelas mais utilização anterior não podem ultrapassar o comprovado. Não há consulta/consumo de conta fiscal oficial nem deduplicação global entre dossiers independentes.
| Caso sintético novo | Efeito demonstrado |
| --- | --- |
| Colecta1 408; PEC200; PPC500; ausência de retenções | Dedução PEC200; colecta após PEC1 208; saldo simulado a pagar708 MZN. |
| Mesmo caso com retenção L5 efectivamente sofrida300 | Saldo simulado408 MZN; prova L5 reutilizada, sem alterar o cálculo L5. |
| Colecta1 408; PEC2 000; sem PPC/retenções | Dedução1 408; saldo zero; PEC592 não deduzido, sem reembolso PEC. |
| Mesmo PEC2 000 e PPC500 | Saldo simulado a recuperar500; PEC592 continua separado. |
| Prova PEC300; já utilizado100; parcela200; sem PPC/retenções | Saldo simulado a pagar1 208; utilizações anteriores não deduzidas outra vez. |
| Utilização anterior desconhecida, prova incompatível/duplicada ou crédito precedente positivo | Saldo indeterminado; subtotal conhecido não substitui os dados em falta. |
**Provas do delta:**12 testes novos PEC;19 testes do módulo anual directamente afectado preservados e aprovados. API privada:1 teste/102 asserções, cinco casos, base isolada `proactive_investment_20261027_test` em loopback55441 e transacção com rollback. Os cinco snapshots recuperados geraram HTML e dossier concordantes; histórico anterior conservado. Hashes dos registos existentes em sete tabelas conservaram55 oportunidades,64 documentos,1 vínculo documental,19 rascunhos,40 utilizadores,3 organizações e409 eventos anteriores. Não houve nova conta/grant, publicação ou importação de pilotos. Wayfinder pelo procedimento existente, TypeScript e build isolado aprovados. Interface PEC implementada; nesta passagem não se declara nova prova manual de utilização por browser/equipa. Não se repetiram suites independentes L3/ISPC/câmbio/L5–L7.30 PDFs do arquivo comparados byte a byte ao baseline `dc14f01e`, sem alterações; schema/configuração e módulos proactivos preservados.
### Saldo concreto do PEC e dependências de L8
| Código ainda por implementar | Exemplo / condição concreta de retoma |
| --- | --- |
| Cálculo da obrigação PEC e prestações | Distinguir volume anterior, PPC do ano anterior e PEC pago. Exemplo de domínio a desenvolver:volume10 000 000 ×0,5%=50 000, antes dos PPC anteriores. Reutilizar vendas/pagamentos só após reconciliação de entidade/exercício; aplicar limites/calendário da edição pertinente e representar dispensas/rectificações próprias. Nenhum vencimento/valor a pagar foi gerado neste incremento. |
| Transporte, ordem de utilização e caducidade de PEC de exercícios anteriores | Exemplo:PEC2025 ainda não deduzido no fecho2026. Implementar proveniência por ano, utilizações, remanescente e prazo; não aceitar esse saldo como PEC2026 nem criar crédito oficial a partir dos592 do exemplo. |
| Outros créditos, imposto autónomo, períodos especiais, outras moedas e transporte/submissão M20/M22 | Mantêm os grupos L8 anteriores, com condições e regras próprias; o PEC corrente independente não espera por esses casos. O mecanismo cambial existente será reutilizado quando corresponder a regra do pagamento. |
| Esclarecimento documental aguardado | Exemplo / condição concreta de retoma |
| --- | --- |
| Edição regulamentar após o anúncio governamental de alterações IRPC em2026 | Recuperar diploma publicado, artigos alterados e entrada em vigor para os calendários/obrigações afectados. O anúncio não substitui norma nem activa parâmetros novos. Não se reabrem as fontes aceites ou cálculos independentes do art66 já demonstrados. |
| Aplicação do prazo do art66 aos saldos anteriores e eventuais regras transitórias | Fixar para um PEC2025 as datas/último exercício elegível e documentação das utilizações; manter a regra PEC distinta do transporte de cinco exercícios do crédito por dupla tributação internacional do art65. Não presumir reembolso, expiração ou saldo oficial. |
| Crédito próprio específico positivo | Exemplo:imposto estrangeiro10 MZN exige rendimento/base/titular, imposto efectivamente pago, limite, convenção e período próprios antes de concorrer com PEC. Segue a dependência existente do crédito, não uma pesquisa geral de L5. |
Registo do incremento: `docs/investmoz/simulations/irpc-l8-pec-qa-20261027.json`; provas sintéticas locais em `outputs/irpc-l8-pec-20261027/`. **L8 permanece parcial.** Não há nova estimativa global de prazo nem declaração de IRPC integralmente concluído. Dificuldades da equipa serão tratadas como correcções concretas do percurso proactivo quando forem comunicadas.
@@ -0,0 +1,789 @@
{
"status": "L7_combinations_installed",
"installed": {
"status": "installed",
"commit": "f8d57bddf96b4610604a013fcc5bdd703c7dc6d5",
"release": "/var/www/investmoz-homologacao/releases/f8d57bddf96b4610604a013fcc5bdd703c7dc6d5-7a31e8ac",
"previous_release": "/var/www/investmoz-homologacao/releases/a7434cd27c09df3d8e6c586f9676b67abcde798e-60070b10",
"database_migrations": 0,
"content_imports": 0
},
"previous_installed": "a7434cd27c09df3d8e6c586f9676b67abcde798e",
"preserved_fiscal_delivery": "632dc069",
"backup": {
"stage": "/var/backups/investmoz-irpc-l7-combinations-delivery-20261026/backup",
"created_at": "2026-10-26T14:20:47Z",
"target": {
"database": "teste_investidor",
"port": 5432
},
"tables": 174,
"files_verified": 369,
"dump_sha256": "2a069fcda7a89368323cda9d5339e76e545b85088de594c1e5a585891dd7b3c3",
"files_sha256": "289ebdcb8cf1983f8fcdb237d3fb947d43fbe71a575064cede233368d43b4584",
"restore_verified": false
},
"restore": {
"restore_verified": true,
"tables_verified": 174,
"container_network": "none",
"database": "irpc_l7_combinations_restore_20261026",
"port": 55441,
"source_dump_sha256": "2a069fcda7a89368323cda9d5339e76e545b85088de594c1e5a585891dd7b3c3",
"active_database_writes": 0
},
"backup_restore_verified": true,
"capacity_before_recovery": {
"checked_at_UTC": "2026-10-26T14:16:50.285126+00:00",
"installed": {
"status": "installed",
"commit": "a7434cd27c09df3d8e6c586f9676b67abcde798e",
"release": "/var/www/investmoz-homologacao/releases/a7434cd27c09df3d8e6c586f9676b67abcde798e-60070b10",
"previous_release": "/var/www/investmoz-homologacao/releases/632dc06930d6b4f1b012feb3b4daa3b1cfc53f39-4c020686",
"database_migrations": 0,
"content_imports": 0
},
"current_link": "/var/www/investmoz-homologacao/releases/a7434cd27c09df3d8e6c586f9676b67abcde798e-60070b10",
"release_revision": {
"commit": "a7434cd27c09df3d8e6c586f9676b67abcde798e",
"branch": "main",
"built_at": "2026-10-26T14:07:54.031522+00:00",
"manifest_sha256": "06af8bbd9ffabeac215cbb0357531f4e4169955461d8cfac380f3776e923e64e"
},
"service": "MainPID=0\nExecMainStatus=0\nActiveState=inactive\nSubState=dead\n",
"volumes": [
{
"path": "/var/www/investmoz-homologacao/releases",
"mount": "/dev/md2 / ext4",
"device": 2306,
"available_bytes": 5430136832,
"available_inodes": 21367883,
"total_inodes": 29089792
},
{
"path": "/var/lib/investmoz-deploy",
"mount": "/dev/md2 / ext4",
"device": 2306,
"available_bytes": 5430136832,
"available_inodes": 21367883,
"total_inodes": 29089792
},
{
"path": "/var/backups",
"mount": "/dev/md2 / ext4",
"device": 2306,
"available_bytes": 5430136832,
"available_inodes": 21367883,
"total_inodes": 29089792
},
{
"path": "/tmp",
"mount": "/dev/md2 / ext4",
"device": 2306,
"available_bytes": 5430136832,
"available_inodes": 21367883,
"total_inodes": 29089792
},
{
"path": "/var/lib/docker",
"mount": "/dev/md2 / ext4",
"device": 2306,
"available_bytes": 5430136832,
"available_inodes": 21367883,
"total_inodes": 29089792
}
],
"free_bytes": 5430136832,
"existing_pipeline_minimum_bytes": 5368709120,
"observed_previous_backup_bytes": 175918494,
"same_partition_release_and_backup": true,
"space_guard_satisfied": false,
"current_release_entry_reference": 31237,
"inodes_available_vs_reference": true,
"inode_note": "Observed current release footprint for scale;no new arbitrary inode threshold. Capacity rechecked after fresh backup.",
"pipeline_sha256": "adec1c17654f3a8658b83b134f1e75f95391b235738552721906c3236e388604",
"active_writes": 0
},
"regenerable_Node_cache_recovery": {
"at_UTC": "2026-10-26T14:18:26.184720+00:00",
"target": "/tmp/node-compile-cache",
"kind": "Node versioned compilation cache;source and node_modules retained;regenerable by Node",
"files_removed": 6893,
"logical_bytes": 206715844,
"free_before": 5429366784,
"free_after": 5652504576,
"recovered_bytes": 223137792,
"installed_record_unchanged": true,
"directory_owner_permissions_preserved": true,
"projects_releases_backups_originals_logs_untouched": true,
"active_business_writes": 0
},
"capacity_before": {
"checked_at_UTC": "2026-10-26T14:19:01.971003+00:00",
"installed": {
"status": "installed",
"commit": "a7434cd27c09df3d8e6c586f9676b67abcde798e",
"release": "/var/www/investmoz-homologacao/releases/a7434cd27c09df3d8e6c586f9676b67abcde798e-60070b10",
"previous_release": "/var/www/investmoz-homologacao/releases/632dc06930d6b4f1b012feb3b4daa3b1cfc53f39-4c020686",
"database_migrations": 0,
"content_imports": 0
},
"current_link": "/var/www/investmoz-homologacao/releases/a7434cd27c09df3d8e6c586f9676b67abcde798e-60070b10",
"release_revision": {
"commit": "a7434cd27c09df3d8e6c586f9676b67abcde798e",
"branch": "main",
"built_at": "2026-10-26T14:07:54.031522+00:00",
"manifest_sha256": "06af8bbd9ffabeac215cbb0357531f4e4169955461d8cfac380f3776e923e64e"
},
"service": "MainPID=0\nExecMainStatus=0\nActiveState=inactive\nSubState=dead\n",
"volumes": [
{
"path": "/var/www/investmoz-homologacao/releases",
"mount": "/dev/md2 / ext4",
"device": 2306,
"available_bytes": 5652262912,
"available_inodes": 21374782,
"total_inodes": 29089792
},
{
"path": "/var/lib/investmoz-deploy",
"mount": "/dev/md2 / ext4",
"device": 2306,
"available_bytes": 5652262912,
"available_inodes": 21374782,
"total_inodes": 29089792
},
{
"path": "/var/backups",
"mount": "/dev/md2 / ext4",
"device": 2306,
"available_bytes": 5652262912,
"available_inodes": 21374782,
"total_inodes": 29089792
},
{
"path": "/tmp",
"mount": "/dev/md2 / ext4",
"device": 2306,
"available_bytes": 5652262912,
"available_inodes": 21374782,
"total_inodes": 29089792
},
{
"path": "/var/lib/docker",
"mount": "/dev/md2 / ext4",
"device": 2306,
"available_bytes": 5652242432,
"available_inodes": 21374780,
"total_inodes": 29089792
}
],
"free_bytes": 5652262912,
"existing_pipeline_minimum_bytes": 5368709120,
"observed_previous_backup_bytes": 175918494,
"same_partition_release_and_backup": true,
"space_guard_satisfied": true,
"current_release_entry_reference": 31237,
"inodes_available_vs_reference": true,
"inode_note": "Observed current release footprint for scale;no new arbitrary inode threshold. Capacity rechecked after fresh backup.",
"pipeline_sha256": "adec1c17654f3a8658b83b134f1e75f95391b235738552721906c3236e388604",
"active_writes": 0
},
"capacity_after_backup": {
"checked_at_UTC": "2026-10-26T14:22:54.407089+00:00",
"installed": {
"status": "installed",
"commit": "a7434cd27c09df3d8e6c586f9676b67abcde798e",
"release": "/var/www/investmoz-homologacao/releases/a7434cd27c09df3d8e6c586f9676b67abcde798e-60070b10",
"previous_release": "/var/www/investmoz-homologacao/releases/632dc06930d6b4f1b012feb3b4daa3b1cfc53f39-4c020686",
"database_migrations": 0,
"content_imports": 0
},
"current_link": "/var/www/investmoz-homologacao/releases/a7434cd27c09df3d8e6c586f9676b67abcde798e-60070b10",
"release_revision": {
"commit": "a7434cd27c09df3d8e6c586f9676b67abcde798e",
"branch": "main",
"built_at": "2026-10-26T14:07:54.031522+00:00",
"manifest_sha256": "06af8bbd9ffabeac215cbb0357531f4e4169955461d8cfac380f3776e923e64e"
},
"service": "MainPID=0\nExecMainStatus=0\nActiveState=inactive\nSubState=dead\n",
"volumes": [
{
"path": "/var/www/investmoz-homologacao/releases",
"mount": "/dev/md2 / ext4",
"device": 2306,
"available_bytes": 5472501760,
"available_inodes": 21374766,
"total_inodes": 29089792
},
{
"path": "/var/lib/investmoz-deploy",
"mount": "/dev/md2 / ext4",
"device": 2306,
"available_bytes": 5472501760,
"available_inodes": 21374766,
"total_inodes": 29089792
},
{
"path": "/var/backups",
"mount": "/dev/md2 / ext4",
"device": 2306,
"available_bytes": 5472501760,
"available_inodes": 21374766,
"total_inodes": 29089792
},
{
"path": "/tmp",
"mount": "/dev/md2 / ext4",
"device": 2306,
"available_bytes": 5472501760,
"available_inodes": 21374766,
"total_inodes": 29089792
},
{
"path": "/var/lib/docker",
"mount": "/dev/md2 / ext4",
"device": 2306,
"available_bytes": 5472501760,
"available_inodes": 21374766,
"total_inodes": 29089792
}
],
"free_bytes": 5472501760,
"existing_pipeline_minimum_bytes": 5368709120,
"observed_previous_backup_bytes": 175918494,
"same_partition_release_and_backup": true,
"space_guard_satisfied": false,
"current_release_entry_reference": 31237,
"inodes_available_vs_reference": true,
"inode_note": "Observed current release footprint for scale;no new arbitrary inode threshold. Capacity rechecked after fresh backup.",
"pipeline_sha256": "adec1c17654f3a8658b83b134f1e75f95391b235738552721906c3236e388604",
"active_writes": 0
},
"post_backup_existing_build_minimum_satisfied": true,
"post_backup_next_fresh_backup_guard_not_required_for_already_completed_backup": true,
"capacity_after_installation": {
"checked_at_UTC": "2026-10-26T14:29:30.537317+00:00",
"installed": {
"status": "installed",
"commit": "f8d57bddf96b4610604a013fcc5bdd703c7dc6d5",
"release": "/var/www/investmoz-homologacao/releases/f8d57bddf96b4610604a013fcc5bdd703c7dc6d5-7a31e8ac",
"previous_release": "/var/www/investmoz-homologacao/releases/a7434cd27c09df3d8e6c586f9676b67abcde798e-60070b10",
"database_migrations": 0,
"content_imports": 0
},
"current_link": "/var/www/investmoz-homologacao/releases/f8d57bddf96b4610604a013fcc5bdd703c7dc6d5-7a31e8ac",
"release_revision": {
"commit": "f8d57bddf96b4610604a013fcc5bdd703c7dc6d5",
"branch": "main",
"built_at": "2026-10-26T14:26:51.629481+00:00",
"manifest_sha256": "367be71b25b56a83571d610e211ea11beae2af87989d62ef6cc7b9c54eabf580"
},
"service": "MainPID=0\nExecMainStatus=0\nActiveState=inactive\nSubState=dead\n",
"volumes": [
{
"path": "/var/www/investmoz-homologacao/releases",
"mount": "/dev/md2 / ext4",
"device": 2306,
"available_bytes": 4441751552,
"available_inodes": 21342698,
"total_inodes": 29089792
},
{
"path": "/var/lib/investmoz-deploy",
"mount": "/dev/md2 / ext4",
"device": 2306,
"available_bytes": 4441751552,
"available_inodes": 21342698,
"total_inodes": 29089792
},
{
"path": "/var/backups",
"mount": "/dev/md2 / ext4",
"device": 2306,
"available_bytes": 4441751552,
"available_inodes": 21342698,
"total_inodes": 29089792
},
{
"path": "/tmp",
"mount": "/dev/md2 / ext4",
"device": 2306,
"available_bytes": 4441747456,
"available_inodes": 21342697,
"total_inodes": 29089792
},
{
"path": "/var/lib/docker",
"mount": "/dev/md2 / ext4",
"device": 2306,
"available_bytes": 4441747456,
"available_inodes": 21342696,
"total_inodes": 29089792
}
],
"free_bytes": 4441751552,
"existing_pipeline_minimum_bytes": 5368709120,
"observed_previous_backup_bytes": 175918494,
"same_partition_release_and_backup": true,
"space_guard_satisfied": false,
"current_release_entry_reference": 31259,
"inodes_available_vs_reference": true,
"inode_note": "Observed current release footprint for scale;no new arbitrary inode threshold. Capacity rechecked after fresh backup.",
"pipeline_sha256": "adec1c17654f3a8658b83b134f1e75f95391b235738552721906c3236e388604",
"active_writes": 0
},
"next_delivery_capacity_adjustment_required": true,
"delta": [
{
"path": "resources/js/lib/irpc-special.ts",
"sha256_LF": "aea0e55b9317ca8ebb313a02e5e92c5b0bac805157d67d54f7c30c71068f46e6"
},
{
"path": "resources/js/lib/irpc-normal.ts",
"sha256_LF": "bce82366ab4ae41fc5f889d9a68d041604e1c032823e4a9384a1227e170c649b"
},
{
"path": "resources/js/components/simulation-irpc-special.tsx",
"sha256_LF": "de77c20af4f07cb2fda31b94cb2c163b627b987d816b43e196590afe59d22fb8"
},
{
"path": "resources/js/lib/irpc-special-combinations.ts",
"sha256_LF": "0c80d39930e2a3f598ba2fed6d7e31252bc24211b5a908778367e2451fcbc90c"
}
],
"preservation": {
"previous_release_preserved": "/var/www/investmoz-homologacao/releases/a7434cd27c09df3d8e6c586f9676b67abcde798e-60070b10",
"installed": {
"status": "installed",
"commit": "f8d57bddf96b4610604a013fcc5bdd703c7dc6d5",
"release": "/var/www/investmoz-homologacao/releases/f8d57bddf96b4610604a013fcc5bdd703c7dc6d5-7a31e8ac",
"previous_release": "/var/www/investmoz-homologacao/releases/a7434cd27c09df3d8e6c586f9676b67abcde798e-60070b10",
"database_migrations": 0,
"content_imports": 0
},
"runtime_files_verified": 4,
"preserved_L3_ISPC_FX_runtime_files_verified": 68,
"documentary_files_verified": 31,
"persistent_files_and_env_verified": 369,
"tables_compared": 174,
"changed_tables": {
"cache": {
"before": {
"rows": 106,
"checksum": "0d909f267cc44165e41d5ac5e966448f"
},
"after": {
"rows": 106,
"checksum": "8381b51b093febcc81854e20cb22bec8"
}
},
"sessions": {
"before": {
"rows": 12,
"checksum": "aa6448d95c23f325f4e2004fb48315ce"
},
"after": {
"rows": 13,
"checksum": "e64cf16446c054a7e852f4944574dabf"
}
}
},
"preserved_counts": {
"published_fiches": 29,
"relations": 28,
"geometries": 408
},
"migration_count": 0,
"content_imports": 0,
"comparison_role": "postgres_before_and_after;sameexportedsnapshotbaseline;noapplicationRLSvisibilityinference",
"writes_by_verification": 0
},
"schema_permissions_after": {
"schema_sha256": "5045b3e51d2185377aa3d9ac7fa07a44fad3ec620cdfa83ffe31c8884ee1601d",
"roles_grants_sha256": "1530c33cb016e67bfdc64891ddfce7f185b13b56b2cd87c012871a685e118109",
"filesystem_permissions": {
".env": {
"mode": 416,
"uid": 1001,
"gid": 33
},
"storage": {
"mode": 1533,
"uid": 1001,
"gid": 33
},
"storage/app": {
"mode": 1533,
"uid": 1001,
"gid": 33
},
"bootstrap/cache": {
"mode": 1528,
"uid": 1001,
"gid": 33
}
},
"comparison_identity": "postgres;catalogue read only;no passwords collected",
"unchanged": true
},
"operational_delta": {
"status": "operational_delta_reconciled",
"comparison_identity": "postgres before/after;isolated restored baseline;no RLS visibility inference",
"cache": "queue:restart;requestthrottle;identical home-sector cached value with refreshed expiry(HomeController remember10min);no deletedcache",
"sessions": "anonymous sessions from delivery user-agent or exactUA/time correlated with nginx public request;deleted sessions individually expired beyond configured lifetime,normal database session garbage collection(config/session lottery2/100)",
"delta": {
"cache": {
"before_rows": 106,
"after_rows": 106,
"changes": [
{
"key_sha256": "7f7dd83f47f5bf404d55e6e9f1367948721579970b195680645e356031a070ff",
"kind": "updated",
"fields": [
"value",
"expiration"
],
"key_pattern": "investemoz-cache-illuminate:queue:restart",
"is_queue_restart_key": true,
"expiration_unchanged": false,
"throttle_timer_pair": false,
"same_value_home_cache_expiry_refresh": false
}
]
},
"sessions": {
"before_rows": 12,
"after_rows": 14,
"changes": [
{
"key_sha256": "d8e8fff391c7cb6369d141adae95227c9616f39055ffd58b5fda3f0cc6eda2a4",
"kind": "added",
"fields": [
"id",
"ip_address",
"user_agent",
"payload",
"last_activity"
],
"anonymous_user": true,
"delivery_user_agent": true,
"expired_before_comparison": false,
"session_lifetime_minutes": 120,
"anonymous_public_request_logged": true
},
{
"key_sha256": "1618c52511f4c5d1fba6bbf74167ce464d7fbe7a121a937cab645415fa7f0878",
"kind": "added",
"fields": [
"id",
"ip_address",
"user_agent",
"payload",
"last_activity"
],
"anonymous_user": true,
"delivery_user_agent": true,
"expired_before_comparison": false,
"session_lifetime_minutes": 120,
"anonymous_public_request_logged": true
}
]
}
},
"business_tables_to_confirm_separately": 172,
"active_data_writes_by_comparison": 0,
"restore_network": "none"
},
"public": {
"status": "installed_delta_verified",
"served_revision": {
"commit": "f8d57bddf96b4610604a013fcc5bdd703c7dc6d5",
"branch": "main",
"built_at": "2026-10-26T14:26:51.629481+00:00",
"manifest_sha256": "367be71b25b56a83571d610e211ea11beae2af87989d62ef6cc7b9c54eabf580"
},
"manifest_hash_matches": true,
"compiled_delta_markers": {
"IRPC-normal-adjustments/14": [
"assets/project-dossier-JLJx7klI.js"
],
"Preparar cumulações dos tratamentos L7 registados": [
"assets/services-BKUDFoA6.js"
],
"Combinação incompatível": [
"assets/project-dossier-JLJx7klI.js"
],
"única diferença adicional:": [
"assets/project-dossier-JLJx7klI.js"
],
"IRPC-normal-adjustments/13": [
"assets/project-dossier-JLJx7klI.js"
],
"Preparar CBF16 para início de actividade": [
"assets/services-BKUDFoA6.js"
],
"Preparar CBF16 para cessação e quotas anteriores": [
"assets/services-BKUDFoA6.js"
],
"sem consumo de saldos oficiais": [
"assets/project-dossier-JLJx7klI.js"
],
"Preparar CBF16 com duodécimos": [
"assets/services-BKUDFoA6.js"
],
"CBF16 — duodécimos reutilizados de L6": [
"assets/project-dossier-JLJx7klI.js"
],
"Suporte dos duodécimos CBF16": [
"assets/services-BKUDFoA6.js"
],
"Manter preparação anual CBF16": [
"assets/services-BKUDFoA6.js"
],
"CBF16 por duodécimos — ": [
"assets/project-dossier-JLJx7klI.js"
],
"diferença adicional:": [
"assets/project-dossier-JLJx7klI.js"
],
"IRPC-normal-adjustments/10": [
"assets/project-dossier-JLJx7klI.js"
]
},
"assets": [
{
"file": "assets/project-dossier-document-W46BRNSe.js",
"status": 200,
"sha256": "80e14fba26e9e81f840ba09eb3f9e24a70404bbe7e6933b490b3085299a6186f"
},
{
"file": "assets/services-BKUDFoA6.js",
"status": 200,
"sha256": "0ac8c266fcecec0e564619948f4cec28cd2572975aff70acc6997971a67fcfd9"
},
{
"file": "assets/project-dossier-JLJx7klI.js",
"status": 200,
"sha256": "1016cb33e4476a95e1a06ce17fad4312efc93aef01994a2674e251d00c884f0b"
},
{
"file": "assets/simulation-form-zFZ4YNrB.js",
"status": 200,
"sha256": "338068b86cce1c3215ee71b1328a6cb2f754b903ed78ff1886f8554df506d2d6"
}
],
"simulator_status": 200,
"simulator_entry": "assets/app-BPLj40Iz.js",
"synthetic_private_writes": 0,
"method": "Read-only installedrevision/manifest/newcompiledcatalogueandreaders/simulatorentry;acceptedQAproofsreused"
},
"pipeline": {
"service": "ExecMainStatus=0\nActiveState=inactive\nSubState=dead\n",
"installed": {
"status": "installed",
"commit": "f8d57bddf96b4610604a013fcc5bdd703c7dc6d5",
"release": "/var/www/investmoz-homologacao/releases/f8d57bddf96b4610604a013fcc5bdd703c7dc6d5-7a31e8ac",
"previous_release": "/var/www/investmoz-homologacao/releases/a7434cd27c09df3d8e6c586f9676b67abcde798e-60070b10",
"database_migrations": 0,
"content_imports": 0
},
"latest_report": {
"status": "installed",
"commit": "f8d57bddf96b4610604a013fcc5bdd703c7dc6d5",
"release": "/var/www/investmoz-homologacao/releases/f8d57bddf96b4610604a013fcc5bdd703c7dc6d5-7a31e8ac",
"previous_release": "/var/www/investmoz-homologacao/releases/a7434cd27c09df3d8e6c586f9676b67abcde798e-60070b10",
"database_migrations": 0,
"content_imports": 0,
"requested_commits": [
"f8d57bddf96b4610604a013fcc5bdd703c7dc6d5"
],
"finished_at": "2026-10-26T14:26:54.452008+00:00"
},
"log_file": "1793024604346159017.log",
"summaries": [
"OK (1 test, 3106 assertions)",
"built in 32.14s",
"OK (59 tests, 317 assertions)",
"# tests 1054",
"# pass 1054",
"# fail 0"
],
"log_bytes": 299642
},
"accepted_QA_proofs_reused": {
"new_frontend_tests": 12,
"API_tests": 1,
"API_assertions": 133,
"QA_database": "simulator_fiscal_delta_20261021_test",
"QA_host": "127.0.0.1",
"QA_port": 55441,
"QA_transaction_rollback": true,
"wayfinder_with_form": true,
"typescript": true,
"build": true,
"recovered_HTML_and_financial_dossier": 7,
"UI": {
"actualComponent": true,
"explicitPrepareCancel": true,
"assetsPeriodsBenefitsNotEdited": true,
"missingOnlyDependentL7": true,
"CBF16Additional25ThenCooperative16": true,
"prior15AlreadyIncluded": true,
"specificGenericIncompatibilityNoAutomaticChoice": true,
"unmappedExceptionIndeterminate": true,
"autonomous35NotHalved": true,
"saveRecoverDownload": true,
"accepted13InputPreserved": true,
"L8FinalUnknown": true,
"errors": []
},
"accepted13_exact_model_key_history_comparison": true,
"accepted_suites_not_rerun": true,
"typescript_build_after_main": true
},
"no_custom_QA_suite_repeated": true,
"L7_remaining_code": [
"other combinations and express exceptions",
"CBF17-19 and potential15 entitlement",
"specific sector/territorial regimes",
"mixed/withheld cooperativeincome and otherentities",
"other autonome expense origins",
"furtherCBF16 scopes",
"capitalgains/specialoperations",
"officialL7M20M22transport"
],
"L7_resume_conditions": [
"disposition/article/scope/period/order/limit and segregatedparcel for combination",
"implement not-yet-supported treatment before adding its effect",
"specific document only for dependentcase/field"
],
"L8_first_increment": {
"status": "L8_first_increment_delimited_not_implemented",
"date": "2026-10-26",
"installed_L7": "f8d57bddf96b4610604a013fcc5bdd703c7dc6d5",
"no_new_L8_calculator_installed": true,
"initial_scope": "resident general IRPC,annualcivil2026,MZN,currentdetermined assessment,documented absence of positive PEC/unmappedcredits and autonomoustax needing ownsettlement",
"inputs_reused": [
"current L6 or applicable qualifiedL7 assessment key/version/subjectNUIT/period;never add both",
"L5 received/effective/on_account qualified and reconciled withholding proofs",
"actual documented PPC payments by subject/period/receipt",
"known/declaredabsence/missing states for every credit/paymentfamily"
],
"wrong_credits_excluded": [
"withholding remitted by enterprise on payments to others",
"definitive withholding",
"projected amount without effective proof",
"duplicate receipt/allocation/year",
"unmapped positive PEC/investment/doubletax credit"
],
"sequence": [
"validassessment",
"admissibledeductions and explicitabsence",
"effective onaccount withholdings",
"actual PPC",
"signed arithmeticbalance",
"applicable collection/refund minimum rules",
"simulatedpayable orrecoverable;not submittedor receivedrefund"
],
"proposed_acceptance_cases": [
{
"colecta": "1408",
"withholdings": "300",
"PPC": "500",
"arithmetic_balance": "608"
},
{
"colecta": "1408",
"withholdings": "1000",
"PPC": "600",
"arithmetic_balance": "-192"
},
{
"colecta": "1408",
"withholdings": "408",
"PPC": "1000",
"arithmetic_balance": "0"
},
"minimumrule boundaries afterperiod/version mapping",
"knownzero vs declaredabsence vs missing",
"wrongbeneficiary/definitive/duplicates",
"calculation-save-recover-report with oldhistories unchanged"
],
"cases_tested_now": false,
"rule_work_before_implementation": [
"CIRPC63/67 with Lei12/2025 nature applicable",
"Decreto9/2008 art21(2-5) deductionorder/limits and27(1-2/6) settlement",
"100MZN minimum in accepted2008 exemplar:link to applicable version/period before enabling parameter;no generic credibility revalidation",
"retain PEC/credits distinct and nonrefundable limits;no3/5year automaticcarry"
],
"boundaries": [
"qualified cooperative withoutwithheldincome cannot silently acceptpositivereceivedwithholdings without L7segregation",
"no L6fallback toignore applicablependingL7effect",
"autonomoustax/61Apositive needs own settlement articulation",
"fraction exact;unmapped formrepresentation onlyblocks affectedtransport"
],
"deferred": [
"automatic PPC/PEC obligationcalculation",
"positivePEC/creditorderlimitscarry",
"autonomoustaxsettlement",
"specialperiods/foreigncurrencypayments",
"interest/penalties/calendar/guideremittance",
"AT submission/refundprocessing",
"unmappedM20M22fields"
],
"sources_reused": [
{
"file": "C:\\laragon\\www\\portal-investidor-irpc-l7-common-qa-20261026\\docs\\investmoz\\simulations\\source-archive\\Lei-34-2007-BR52.pdf",
"sha256": "cdbef875ad7ccc1517b12faf5de0e893a70ed2ed81e33913cd6dc4a674474e6e",
"articles": "CIRPC63/67",
"PDF_pages": [
18,
19
],
"official_source_acceptance_preserved": true
},
{
"file": "C:\\laragon\\www\\portal-investidor-irpc-l7-common-qa-20261026\\docs\\investmoz\\simulations\\source-archive\\Decreto-9-2008-BR16.pdf",
"sha256": "96fccdecbfdc11c9eafb90fbc6c7bc259f88bbd4c7507d1ac3af1fa03f960697",
"articles": "RIRPC21/27",
"PDF_pages": [
6,
7
],
"official_source_acceptance_preserved": true
},
{
"file": "C:\\laragon\\www\\portal-investidor-irpc-l7-common-qa-20261026\\docs\\investmoz\\simulations\\source-archive\\BR-248-I-Suplemento-1-2025.pdf",
"sha256": "ccf2a8deeca820f2dd076b4b2141b1efe3f6a806568c3a587ca59a8e92f4c251",
"articles": "Lei12/2025 IRPC67/version2026",
"PDF_pages": [
18,
19,
20
],
"official_source_acceptance_preserved": true
}
],
"global_effort": {
"initial_L8_L14_reference_hours": [
240,
416
],
"is_current_remainingforecast": false,
"reconciliation_before_globalforecast": [
"implemented/reusable vs remainingcode perlot",
"reuseacceptedproofs;no duplicate sharedcomponentestimate",
"documentarywait separately",
"L1-L7residuals,integration/delivery,L15-L16 included"
]
},
"L7_partial": true,
"L8_final_still_not_implemented": true
},
"global_effort_forecast_not_assumed": true,
"L6_operational_delimited": true,
"L7_partial": true,
"L8_final_separate": true,
"SGF_TEMPO_untouched": true
}
@@ -0,0 +1,95 @@
{
"status": "prepared_delivery_deferred_by_user_capacity_not_satisfied",
"date": "2026-10-27",
"candidate": "14360748194f3658d91a7d7ae5615efd0fcbfbb7",
"QA_runtime_commit": "11a6cee981f0a425b0fceefb6ed85485bb298245",
"candidate_branch": "codex/irpc-l8-settlement-qa-20261026",
"remote_main_verified": "f8d57bddf96b4610604a013fcc5bdd703c7dc6d5",
"installed_remote_verified": "f8d57bddf96b4610604a013fcc5bdd703c7dc6d5",
"capacity": {
"checked_at_UTC": "2026-10-27T06:05:28.744338+00:00",
"partition": "/dev/md2 / ext4",
"free_bytes": 4402343936,
"free_GiB": 4.100002288818359,
"required_after_backup_bytes": 5368709120,
"previous_backup_reference_bytes": 175917490,
"estimated_required_before_backup_bytes": 5544626610,
"additional_free_bytes_needed": 1142282674,
"additional_GiB_needed_rounded_up": 1.07,
"inodes_available": 21340182,
"release_entries_reference": 31259,
"inodes_sufficient_against_reference": true,
"fresh_measurement_required_on_resume": true,
"installer_threshold_not_changed": true
},
"baseline": {
"baseline": "f8d57bddf96b4610604a013fcc5bdd703c7dc6d5",
"files_verified": 168,
"active_writes": 0
},
"prepared_runtime_delta_files": 5,
"preserved_runtime_files": 134,
"originals_preserved": 31,
"caches_read_only": {
"caches": [
{
"path": "/root/.cache/composer/files",
"resolved": "/root/.cache/composer/files",
"symlink": false,
"bytes": 127242240,
"first_entries": [
"carbonphp",
"maatwebsite",
"iamcal",
"bordoni",
"fidry",
"mockery",
"symfony",
"mtdowling",
"inertiajs",
"tcg",
"nyholm",
"dflydev"
]
},
{
"path": "/tmp/node-compile-cache",
"resolved": "/tmp/node-compile-cache",
"symlink": false,
"bytes": 4009984,
"first_entries": [
"v22.23.4-x64-d04b8edd-1001"
]
}
],
"package_manager_processes": [],
"open_cache_handles": [],
"service": "ActiveState=inactive\nSubState=dead\n",
"active_writes": 0
},
"caches_insufficient_to_resolve_gap": true,
"cleanup_performed": false,
"fresh_backup_executed": false,
"fresh_restore_executed": false,
"main_push_executed": false,
"installation_executed": false,
"server_persistent_writes": 0,
"business_database_writes": 0,
"user_decision": "Manter a entrega preparada por agora",
"next_action": "New space/inode and main/servedrevision checks;confirm capacity for freshbackup/restore and isolatedbuild;then authorized Git delivery and onlydelta verification. Keep active release until new is ready.",
"QA_proofs_reused": {
"frontend": 19,
"API_assertions": 170,
"UI_round_trip": true,
"typescript": true,
"isolatedbuild": true,
"not_repeated": true
},
"L8_partial": true,
"PEC_and_own_credits_separate": true,
"L7_residuals_unchanged": true,
"SGF_TEMPO_untouched": true,
"preflight_pipeline_sha256": "adec1c17654f3a8658b83b134f1e75f95391b235738552721906c3236e388604",
"resume_candidate_branch": "codex/irpc-l8-settlement-qa-20261026",
"notes_branch": "codex/irpc-l8-delivery-capacity-20261027"
}
@@ -0,0 +1,382 @@
{
"status": "QA_complete_ready_for_grouped_delivery_not_installed",
"date": "2026-10-26",
"branch": "codex/irpc-l8-settlement-qa-20261026",
"runtime_revision": "11a6cee981f0a425b0fceefb6ed85485bb298245",
"installed_revision_per_user": "f8d57bddf96b4610604a013fcc5bdd703c7dc6d5",
"remote_main_checked": "f8d57bddf96b4610604a013fcc5bdd703c7dc6d5",
"version": "IRPC-annual-settlement/1",
"scope": "resident general IRPC,annualcivil2026,MZN,currentdetermined assessment,documented absence of positive PEC/unmappedcredits and autonomoustax needing ownsettlement",
"inputs_reused": [
"current L6 or applicable qualifiedL7 assessment key/version/subjectNUIT/period;never add both",
"L5 received/effective/on_account qualified and reconciled withholding proofs",
"actual documented PPC payments by subject/period/receipt",
"known/declaredabsence/missing states for every credit/paymentfamily"
],
"PEC_and_special_credits_separate": true,
"official_credit_consumption_or_central_reservation": false,
"duplicate_guards": [
"same L5 allocation/pair",
"normalised issuer/document even if date changed",
"same receipt as withholding and PPC",
"receipt total including partial allocations in other contexts in same dossier",
"same sourceKey L5 allocation cannot consume larger receipt twice",
"different entity/year or inconsistent proven amount"
],
"cases": {
"payable": {
"status": "payable",
"knownWithholdings": {
"numerator": "300",
"denominator": "1"
},
"knownPpc": {
"numerator": "500",
"denominator": "1"
},
"arithmeticBalance": {
"numerator": "608",
"denominator": "1"
},
"payable": {
"numerator": "608",
"denominator": "1"
},
"recoverable": {
"numerator": "0",
"denominator": "1"
},
"pending": []
},
"recoverable": {
"status": "recoverable",
"knownWithholdings": {
"numerator": "1000",
"denominator": "1"
},
"knownPpc": {
"numerator": "600",
"denominator": "1"
},
"arithmeticBalance": {
"numerator": "-192",
"denominator": "1"
},
"payable": {
"numerator": "0",
"denominator": "1"
},
"recoverable": {
"numerator": "192",
"denominator": "1"
},
"pending": []
},
"balanced": {
"status": "balanced",
"knownWithholdings": {
"numerator": "408",
"denominator": "1"
},
"knownPpc": {
"numerator": "1000",
"denominator": "1"
},
"arithmeticBalance": {
"numerator": "0",
"denominator": "1"
},
"payable": {
"numerator": "0",
"denominator": "1"
},
"recoverable": {
"numerator": "0",
"denominator": "1"
},
"pending": []
},
"absent": {
"status": "payable",
"knownWithholdings": {
"numerator": "0",
"denominator": "1"
},
"knownPpc": {
"numerator": "0",
"denominator": "1"
},
"arithmeticBalance": {
"numerator": "1408",
"denominator": "1"
},
"payable": {
"numerator": "1408",
"denominator": "1"
},
"recoverable": {
"numerator": "0",
"denominator": "1"
},
"pending": []
},
"missing": {
"status": "indeterminate",
"knownWithholdings": {
"numerator": "300",
"denominator": "1"
},
"knownPpc": {
"numerator": "0",
"denominator": "1"
},
"arithmeticBalance": null,
"payable": null,
"recoverable": null,
"pending": [
"QA-PPC-2026-1: Error: PPC exige comprovativo efectivo,MZN,data,entidade e exercício correspondentes;projecção/tesouraria não é pagamento"
]
},
"duplicate": {
"status": "indeterminate",
"knownWithholdings": {
"numerator": "300",
"denominator": "1"
},
"knownPpc": {
"numerator": "0",
"denominator": "1"
},
"arithmeticBalance": null,
"payable": null,
"recoverable": null,
"pending": [
"QA-PPC-2026-1: Comprovativo utilizado além do montante disponível ou com montantes divergentes neste/outro mapa."
]
},
"pec": {
"status": "indeterminate",
"knownWithholdings": {
"numerator": "300",
"denominator": "1"
},
"knownPpc": {
"numerator": "500",
"denominator": "1"
},
"arithmeticBalance": null,
"payable": null,
"recoverable": null,
"pending": [
"PEC: Error: montante positivo fora deste recorte:corresponder ordem,limite e transporte próprios;sem abatimento ou reembolso automático"
]
}
},
"checks": {
"frontend_tests": 19,
"frontend_pass": 19,
"API_tests": 1,
"API_assertions": 170,
"API_cases": 7,
"database": "simulator_fiscal_delta_20261021_test",
"host": "127.0.0.1",
"port": 55441,
"transaction_rollback": true,
"actual_components_UI": {
"actualComponents": true,
"explicitPreparation": true,
"onlyActualOnAccountProofSelectable": true,
"duplicateSelectionDisabled": true,
"missingNotZero": true,
"ownBeneficiaryAndIncludedIncomeConfirmed": true,
"actualPPCConfirmed": true,
"PECAndCreditsSeparate": true,
"payable608": true,
"recoverable192": true,
"balanced": true,
"duplicateIndeterminate": true,
"positivePECIndeterminate": true,
"oldBooksAndPlanUnchanged": true,
"saveReloadRecoverReportDownload": true,
"errors": []
},
"wayfinder_with_form": "passed",
"typescript": "passed",
"isolated_QA_build": "passed",
"build_existing_warnings": [
"chunk size over500kB;plugin timing diagnostic"
],
"prior_accepted_suites_not_repeated": true
},
"runtime_delta": [
"resources/js/components/simulation-form.tsx",
"resources/js/components/simulation-irpc-annual.tsx",
"resources/js/lib/irpc-annual-settlement.ts",
"resources/js/lib/project-dossier-report.ts",
"resources/js/lib/project-dossier.ts",
"tests/Feature/IrpcAnnualSettlementDraftTest.php",
"tests/frontend/irpc-annual-settlement.test.mjs",
"tools/irpc-annual-settlement-qa.php"
],
"preservation": {
"baseline": "f8d57bddf96b4610604a013fcc5bdd703c7dc6d5",
"documentation_base": "d5f11462",
"existing_tracked_files": 2832,
"changed_existing_files": [
"docs/investmoz/consolidated-review-matrix-2026-10-03.md",
"docs/investmoz/unification/traceability-and-manual.md",
"docs/investmoz/v2/auditoria-portal/matriz-requisitos.csv",
"resources/js/components/simulation-form.tsx",
"resources/js/lib/project-dossier-report.ts",
"resources/js/lib/project-dossier.ts"
],
"all_other_existing_files_byte_identical": true,
"schema_configuration_permissions_unchanged": true,
"L5_L6_L7_engines_and_fixtures_byte_identical": true,
"originals_count": 31,
"originals": {
"docs/investmoz/simulations/source-archive/AT-Comunicado-9-2026-ISPC.pdf": "106f8a9ce9255c03549c70bf07fe999d32e6e55302d009b509862aa74ccb4973",
"docs/investmoz/simulations/source-archive/AT-MRFTA-19-39.pdf": "8ea62c53066b482f87078a7a7b1ecf15ca98a12a122e8d7abca63acfc993186b",
"docs/investmoz/simulations/source-archive/AT-Modelo-30-ISPC.pdf": "6802edd06b6ff638a0b851a3ec7ecf69af8f07840faa47446becad67d35d445c",
"docs/investmoz/simulations/source-archive/AT-Modelo-B-Geral.pdf": "bd977c7c59d4d98befd92e2c566b1bf168cb1343bb519f51b41a3807f431fc57",
"docs/investmoz/simulations/source-archive/BM-Mercado-Monetario-MAIBOR-20261025.html": "00e8a7e0d3a1db4ca3beb56d5361b2084a0f1684f3d40fc1c203702a2190e063",
"docs/investmoz/simulations/source-archive/BR-16-I-Serie-2008-04-16.pdf": "fc373ff5637edf75ec6a9595dec8763a8503d4ee786e3b7d8f1c742eae9d80ee",
"docs/investmoz/simulations/source-archive/BR-248-I-Suplemento-1-2025.pdf": "ccf2a8deeca820f2dd076b4b2141b1efe3f6a806568c3a587ca59a8e92f4c251",
"docs/investmoz/simulations/source-archive/BR-89-I-Serie-2017-06-08.pdf": "11f0cab15eb6e51010952203ffa24fdc533a24fd642e19525fe4f46b17a1f5e5",
"docs/investmoz/simulations/source-archive/BR-95-I-Suplemento-2025-05-21.pdf": "e0e682e2c027c3cd9c1d46a73a3f48bc5f6bdbf05667fd97314d7a3f6a456358",
"docs/investmoz/simulations/source-archive/BR252-I-Serie-2022-Lei20-PESOE.pdf": "1159fd3ce1ba5581671796d083534da48bd3c5578298819e896f1c2a8026318d",
"docs/investmoz/simulations/source-archive/Decreto-22-2021-BR70.pdf": "a8fac38dcfe08f9c7a8e46254cff10e1ec82fc4f7a8d88ad6e4fe7d91ffc21a5",
"docs/investmoz/simulations/source-archive/Decreto-27-2026-BR123.pdf": "26249c3fa58f149c81de36e99d1aac2819a4771379d9e8833159660dabf539bb",
"docs/investmoz/simulations/source-archive/Decreto-29-1998-BR22-5-suplemento.pdf": "6242cbe675faadf085f43f95ec8c7e8868aafe67c3b2ab2bb010992288f954f8",
"docs/investmoz/simulations/source-archive/Decreto-3-2011-BR-11-I-mineiros.pdf": "5bca1133666ba9c69870b89823420175b7b5b8d0eccb667ecdf5c29716f3b6be",
"docs/investmoz/simulations/source-archive/Decreto-37-2023-BR124.pdf": "7e680b191481faa0e2e9057fa5053587eb2a29d1d8c819e0eb9f02814255a04c",
"docs/investmoz/simulations/source-archive/Decreto-9-2008-BR16.pdf": "96fccdecbfdc11c9eafb90fbc6c7bc259f88bbd4c7507d1ac3af1fa03f960697",
"docs/investmoz/simulations/source-archive/Lei-13-2016-CIVA-BR-156-10-suplemento.pdf": "b90dc7c14ecea2e378c4a62e8e5a47d54a5644c457baeb8b8053b92fd2a5710b",
"docs/investmoz/simulations/source-archive/Lei-14-1992-BR42.pdf": "089fff7423e99a70a230a73ca379e4ea3a91d124703f91016e57ff82794b9e56",
"docs/investmoz/simulations/source-archive/Lei-17-2022-BR251-exemplar-MCNet5.pdf": "14eb34f0af91a8f5cb1770c7b52d6ff839c6818302d1ed96d79afbfb9fe999d4",
"docs/investmoz/simulations/source-archive/Lei-17-2022-IPP-BR250-Parlamento.pdf": "978cd22403ffd336a631704ecd7a5bbd814a427c815b9acdaca5515591dd9e2a",
"docs/investmoz/simulations/source-archive/Lei-19-2013-BR76.pdf": "bba96d645cc935ffc3d1a79b9f0f73ac1c693d6459c2ad41f56cd2841accae76",
"docs/investmoz/simulations/source-archive/Lei-19-2017-IRPS-BR-OCAM.pdf": "c3a0186cb9ad090d7a9533006295dc9bb6a62ad0d6150173cbd49dba4ee4b52d",
"docs/investmoz/simulations/source-archive/Lei-2-2011-BR-1-4-suplemento-MCNet.pdf": "a7543a68cc3287a46a83c39a04821b40f649dd06c4e9b5dc51ff0b47fba08899",
"docs/investmoz/simulations/source-archive/Lei-20-2009-BR36-AT-exemplar19.pdf": "fc1c8144db42960cbf73e717e095896f511ece0f907f58f78819b27d6917a7ee",
"docs/investmoz/simulations/source-archive/Lei-22-2022-IVA-republicada-BR-250-2-suplemento.pdf": "ea1b0dc6f5cf6e595f6d9a19e7042f398999e0087caef1785f6e8fac571b5f53",
"docs/investmoz/simulations/source-archive/Lei-34-2007-BR52.pdf": "cdbef875ad7ccc1517b12faf5de0e893a70ed2ed81e33913cd6dc4a674474e6e",
"docs/investmoz/simulations/source-archive/Lei-4-1994-BR37-3-suplemento.pdf": "210df9db8980d0a5690cd187a6eeec7e37a900d743e39062c16f4e0d12215c7e",
"docs/investmoz/simulations/source-archive/Lei-4-2012-BR3.pdf": "b8845cef41dcbd9ba50c43dbfa743a56030dd3d348242a107e1ae30279eec121",
"docs/investmoz/simulations/source-archive/Lei-7-1991-Partidos-IFES.pdf": "6b783a0bb3330688ef10660a58060d9724aa2da6a873d234fe902f0eaaeda42d",
"docs/investmoz/simulations/source-archive/PT-MZ-CDT-1992.pdf": "d504e1024b28aee5c6acf4592acb96ec9c915a8414f67a61ab6984d6acf9df9d",
"docs/investmoz/simulations/source-archive/PT-MZ-Protocolo-2009.pdf": "f353773dcf41f09f4daa6cf5ba5a5f7994f3e02615867c2dcffc61c3d901bf9b"
},
"all_seven_recovered_cases_match_final_inputs": true,
"no_active_database_or_server_operations": true,
"no_SGF_TEMPO_operations": true,
"runtime_changed_existing_files": [
"resources/js/components/simulation-form.tsx",
"resources/js/lib/project-dossier-report.ts",
"resources/js/lib/project-dossier.ts"
],
"documentation_changed_existing_files": [
"docs/investmoz/consolidated-review-matrix-2026-10-03.md",
"docs/investmoz/unification/traceability-and-manual.md",
"docs/investmoz/v2/auditoria-portal/matriz-requisitos.csv"
],
"documentation_only_appends_and_target_AUD_record": true
},
"sources_reused": [
{
"file": "docs/investmoz/simulations/source-archive/Lei-34-2007-BR52.pdf",
"sha256": "cdbef875ad7ccc1517b12faf5de0e893a70ed2ed81e33913cd6dc4a674474e6e",
"articles": "CIRPC63/67",
"PDF_pages": [
18,
19
],
"official_source_acceptance_preserved": true
},
{
"file": "docs/investmoz/simulations/source-archive/Decreto-9-2008-BR16.pdf",
"sha256": "96fccdecbfdc11c9eafb90fbc6c7bc259f88bbd4c7507d1ac3af1fa03f960697",
"articles": "RIRPC21/27",
"PDF_pages": [
6,
7
],
"official_source_acceptance_preserved": true
},
{
"file": "docs/investmoz/simulations/source-archive/BR-248-I-Suplemento-1-2025.pdf",
"sha256": "ccf2a8deeca820f2dd076b4b2141b1efe3f6a806568c3a587ca59a8e92f4c251",
"articles": "Lei12/2025 IRPC67/version2026",
"PDF_pages": [
18,
19,
20
],
"official_source_acceptance_preserved": true
}
],
"minimum": {
"rule": "Decreto9/2008 art27(6)",
"scope": "2026 resident_general/calendar/MZN",
"less_than": "100 MZN",
"strict_boundary_tests": [
"+99.99",
"+100",
"-99.99",
"-100"
],
"arithmetic_exact": true,
"new_rounding": false,
"automatic_carry": false
},
"remaining_code": [
"automatic PPC/PEC obligationcalculation",
"positivePEC/creditorderlimitscarry",
"autonomoustaxsettlement",
"specialperiods/foreigncurrencypayments",
"interest/penalties/calendar/guideremittance",
"AT submission/refundprocessing",
"unmappedM20M22fields"
],
"documentary_dependencies": {
"previous_L5_L6_L7_matrix_items_preserved": true,
"examples": [
"mixed/withheld cooperativeincome needs L7 segregation",
"express cumulation exception requires disposition/period/limits",
"divergent M20M22 field needs exactedition and representation"
],
"only_dependent_case_blocked": true
},
"L6_operational_delimited": true,
"L7_partial": true,
"L8_partial": true,
"submitted_or_payment_or_refund_received": false,
"server_operations_this_turn": false,
"reported_server_free_GiB": 4.14,
"reported_capacity_not_measured_this_turn": true,
"capacity_blocks_future_install_not_QA": true,
"future_delivery": {
"fresh_main_compatibility": true,
"measure_space_and_inodes": true,
"confirm_backup_and_isolated_build_capacity": true,
"fresh_backup_restore": true,
"keep_active_until_new_ready": true,
"verify_served_revision_and_only_delta": true
},
"evidence_directory": "outputs/irpc-l8-settlement/",
"global_effort": {
"initial_L8_L14_reference_hours": [
240,
416
],
"is_current_remainingforecast": false,
"reconciliation_before_globalforecast": [
"implemented/reusable vs remainingcode perlot",
"reuseacceptedproofs;no duplicate sharedcomponentestimate",
"documentarywait separately",
"L1-L7residuals,integration/delivery,L15-L16 included"
]
},
"root_checkout_runtime_not_merged": true,
"SGF_TEMPO_untouched": true
}
@@ -0,0 +1,123 @@
{
"status": "L8_first_increment_delimited_not_implemented",
"date": "2026-10-26",
"installed_L7": "f8d57bddf96b4610604a013fcc5bdd703c7dc6d5",
"no_new_L8_calculator_installed": true,
"initial_scope": "resident general IRPC,annualcivil2026,MZN,currentdetermined assessment,documented absence of positive PEC/unmappedcredits and autonomoustax needing ownsettlement",
"inputs_reused": [
"current L6 or applicable qualifiedL7 assessment key/version/subjectNUIT/period;never add both",
"L5 received/effective/on_account qualified and reconciled withholding proofs",
"actual documented PPC payments by subject/period/receipt",
"known/declaredabsence/missing states for every credit/paymentfamily"
],
"wrong_credits_excluded": [
"withholding remitted by enterprise on payments to others",
"definitive withholding",
"projected amount without effective proof",
"duplicate receipt/allocation/year",
"unmapped positive PEC/investment/doubletax credit"
],
"sequence": [
"validassessment",
"admissibledeductions and explicitabsence",
"effective onaccount withholdings",
"actual PPC",
"signed arithmeticbalance",
"applicable collection/refund minimum rules",
"simulatedpayable orrecoverable;not submittedor receivedrefund"
],
"proposed_acceptance_cases": [
{
"colecta": "1408",
"withholdings": "300",
"PPC": "500",
"arithmetic_balance": "608"
},
{
"colecta": "1408",
"withholdings": "1000",
"PPC": "600",
"arithmetic_balance": "-192"
},
{
"colecta": "1408",
"withholdings": "408",
"PPC": "1000",
"arithmetic_balance": "0"
},
"minimumrule boundaries afterperiod/version mapping",
"knownzero vs declaredabsence vs missing",
"wrongbeneficiary/definitive/duplicates",
"calculation-save-recover-report with oldhistories unchanged"
],
"cases_tested_now": false,
"rule_work_before_implementation": [
"CIRPC63/67 with Lei12/2025 nature applicable",
"Decreto9/2008 art21(2-5) deductionorder/limits and27(1-2/6) settlement",
"100MZN minimum in accepted2008 exemplar:link to applicable version/period before enabling parameter;no generic credibility revalidation",
"retain PEC/credits distinct and nonrefundable limits;no3/5year automaticcarry"
],
"boundaries": [
"qualified cooperative withoutwithheldincome cannot silently acceptpositivereceivedwithholdings without L7segregation",
"no L6fallback toignore applicablependingL7effect",
"autonomoustax/61Apositive needs own settlement articulation",
"fraction exact;unmapped formrepresentation onlyblocks affectedtransport"
],
"deferred": [
"automatic PPC/PEC obligationcalculation",
"positivePEC/creditorderlimitscarry",
"autonomoustaxsettlement",
"specialperiods/foreigncurrencypayments",
"interest/penalties/calendar/guideremittance",
"AT submission/refundprocessing",
"unmappedM20M22fields"
],
"sources_reused": [
{
"file": "C:\\laragon\\www\\portal-investidor-irpc-l7-common-qa-20261026\\docs\\investmoz\\simulations\\source-archive\\Lei-34-2007-BR52.pdf",
"sha256": "cdbef875ad7ccc1517b12faf5de0e893a70ed2ed81e33913cd6dc4a674474e6e",
"articles": "CIRPC63/67",
"PDF_pages": [
18,
19
],
"official_source_acceptance_preserved": true
},
{
"file": "C:\\laragon\\www\\portal-investidor-irpc-l7-common-qa-20261026\\docs\\investmoz\\simulations\\source-archive\\Decreto-9-2008-BR16.pdf",
"sha256": "96fccdecbfdc11c9eafb90fbc6c7bc259f88bbd4c7507d1ac3af1fa03f960697",
"articles": "RIRPC21/27",
"PDF_pages": [
6,
7
],
"official_source_acceptance_preserved": true
},
{
"file": "C:\\laragon\\www\\portal-investidor-irpc-l7-common-qa-20261026\\docs\\investmoz\\simulations\\source-archive\\BR-248-I-Suplemento-1-2025.pdf",
"sha256": "ccf2a8deeca820f2dd076b4b2141b1efe3f6a806568c3a587ca59a8e92f4c251",
"articles": "Lei12/2025 IRPC67/version2026",
"PDF_pages": [
18,
19,
20
],
"official_source_acceptance_preserved": true
}
],
"global_effort": {
"initial_L8_L14_reference_hours": [
240,
416
],
"is_current_remainingforecast": false,
"reconciliation_before_globalforecast": [
"implemented/reusable vs remainingcode perlot",
"reuseacceptedproofs;no duplicate sharedcomponentestimate",
"documentarywait separately",
"L1-L7residuals,integration/delivery,L15-L16 included"
]
},
"L7_partial": true,
"L8_final_still_not_implemented": true
}
@@ -0,0 +1,505 @@
{
"date": "2026-10-27",
"status": "QA implemented, not installed",
"branch": "codex/irpc-l8-pec-qa-20261027",
"baseline": "dc14f01e1479f6bef48be60d2fbe961d9d445e0e",
"portal_reference_from_previous_receipt": "9fda6d6e12832a3cf25e7314f1f895dd430238c5",
"active_changed": false,
"main_changed": false,
"scope": {
"year": "2026",
"regime": "resident_general",
"currency": "MZN",
"period": "calendar",
"payment": "documented current-year PEC, available amount after prior use",
"deduction": "min(available selected PEC, valid collecta after preceding credits), before RF/PPC",
"special_credits": "only documented absent or known zero; positive/missing stays indeterminate",
"excess": "selected amount not deducted, no PEC refund or official carry created"
},
"examples": [
{
"case": "payable",
"status": "payable",
"balance": {
"numerator": "708",
"denominator": "1"
},
"pec": {
"version": "IRPC-PEC/1",
"available": {
"numerator": "200",
"denominator": "1"
},
"deducted": {
"numerator": "200",
"denominator": "1"
},
"remaining": {
"numerator": "0",
"denominator": "1"
},
"afterPec": {
"numerator": "1208",
"denominator": "1"
},
"source": "CIRPC, art. 66(1–2), Lei 34/2007, exemplar BR52, p. 768-(72): dedução após créditos anteriores, até à colecta, sem reembolso do PEC. Recorte demonstrado: pagamento efectivo do próprio exercício 2026, residente geral, ano civil, MZN. Não calcula a obrigação PEC, transporte, caducidade ou consumo de saldos oficiais.",
"officialBalancesConsumed": false,
"carryCreated": false
},
"rows": 7,
"history": 0,
"apiRoundTrip": true,
"current": true,
"dossier": true
},
{
"case": "capped",
"status": "balanced",
"balance": {
"numerator": "0",
"denominator": "1"
},
"pec": {
"version": "IRPC-PEC/1",
"available": {
"numerator": "2000",
"denominator": "1"
},
"deducted": {
"numerator": "1408",
"denominator": "1"
},
"remaining": {
"numerator": "592",
"denominator": "1"
},
"afterPec": {
"numerator": "0",
"denominator": "1"
},
"source": "CIRPC, art. 66(1–2), Lei 34/2007, exemplar BR52, p. 768-(72): dedução após créditos anteriores, até à colecta, sem reembolso do PEC. Recorte demonstrado: pagamento efectivo do próprio exercício 2026, residente geral, ano civil, MZN. Não calcula a obrigação PEC, transporte, caducidade ou consumo de saldos oficiais.",
"officialBalancesConsumed": false,
"carryCreated": false
},
"rows": 6,
"history": 1,
"apiRoundTrip": true,
"current": true,
"dossier": true
},
{
"case": "recoverable",
"status": "recoverable",
"balance": {
"numerator": "-500",
"denominator": "1"
},
"pec": {
"version": "IRPC-PEC/1",
"available": {
"numerator": "2000",
"denominator": "1"
},
"deducted": {
"numerator": "1408",
"denominator": "1"
},
"remaining": {
"numerator": "592",
"denominator": "1"
},
"afterPec": {
"numerator": "0",
"denominator": "1"
},
"source": "CIRPC, art. 66(1–2), Lei 34/2007, exemplar BR52, p. 768-(72): dedução após créditos anteriores, até à colecta, sem reembolso do PEC. Recorte demonstrado: pagamento efectivo do próprio exercício 2026, residente geral, ano civil, MZN. Não calcula a obrigação PEC, transporte, caducidade ou consumo de saldos oficiais.",
"officialBalancesConsumed": false,
"carryCreated": false
},
"rows": 7,
"history": 1,
"apiRoundTrip": true,
"current": true,
"dossier": true
},
{
"case": "missing",
"status": "indeterminate",
"balance": null,
"pec": {
"version": "IRPC-PEC/1",
"available": {
"numerator": "0",
"denominator": "1"
},
"deducted": null,
"remaining": null,
"afterPec": null,
"source": "CIRPC, art. 66(1–2), Lei 34/2007, exemplar BR52, p. 768-(72): dedução após créditos anteriores, até à colecta, sem reembolso do PEC. Recorte demonstrado: pagamento efectivo do próprio exercício 2026, residente geral, ano civil, MZN. Não calcula a obrigação PEC, transporte, caducidade ou consumo de saldos oficiais.",
"officialBalancesConsumed": false,
"carryCreated": false
},
"rows": 7,
"history": 1,
"apiRoundTrip": true,
"current": true,
"dossier": true
},
{
"case": "prior-use",
"status": "payable",
"balance": {
"numerator": "1208",
"denominator": "1"
},
"pec": {
"version": "IRPC-PEC/1",
"available": {
"numerator": "200",
"denominator": "1"
},
"deducted": {
"numerator": "200",
"denominator": "1"
},
"remaining": {
"numerator": "0",
"denominator": "1"
},
"afterPec": {
"numerator": "1208",
"denominator": "1"
},
"source": "CIRPC, art. 66(1–2), Lei 34/2007, exemplar BR52, p. 768-(72): dedução após créditos anteriores, até à colecta, sem reembolso do PEC. Recorte demonstrado: pagamento efectivo do próprio exercício 2026, residente geral, ano civil, MZN. Não calcula a obrigação PEC, transporte, caducidade ou consumo de saldos oficiais.",
"officialBalancesConsumed": false,
"carryCreated": false
},
"rows": 6,
"history": 1,
"apiRoundTrip": true,
"current": true,
"dossier": true
}
],
"proofs": {
"new_frontend_tests": 12,
"affected_annual_tests": 19,
"api_tests": 1,
"api_assertions": 102,
"api_cases": 5,
"api_round_trip_reports": 5,
"routes": "wayfinder --with-form passed",
"typescript": "passed",
"isolated_build": "passed; optional fontaine/chunk-size notices only",
"manual_browser_test": false,
"real_team_evaluation": "pending external feedback"
},
"preservation": {
"database": "proactive_investment_20261027_test",
"tables": {
"opportunities": {
"existing_rows": 55,
"unchanged": true
},
"documents": {
"existing_rows": 64,
"unchanged": true
},
"opportunity_documents": {
"existing_rows": 1,
"unchanged": true
},
"simulation_form_drafts": {
"existing_rows": 19,
"unchanged": true
},
"users": {
"existing_rows": 40,
"unchanged": true
},
"organizations": {
"existing_rows": 3,
"unchanged": true
},
"audit_events": {
"existing_rows": 409,
"unchanged": true
}
},
"transaction_rollback": true
},
"source_preservation": {
"baseline": "dc14f01e",
"count": 30,
"all_equal": true,
"files": [
{
"file": "AT-Comunicado-9-2026-ISPC.pdf",
"sha256": "106f8a9ce9255c03549c70bf07fe999d32e6e55302d009b509862aa74ccb4973"
},
{
"file": "AT-Modelo-30-ISPC.pdf",
"sha256": "6802edd06b6ff638a0b851a3ec7ecf69af8f07840faa47446becad67d35d445c"
},
{
"file": "AT-Modelo-B-Geral.pdf",
"sha256": "bd977c7c59d4d98befd92e2c566b1bf168cb1343bb519f51b41a3807f431fc57"
},
{
"file": "AT-MRFTA-19-39.pdf",
"sha256": "8ea62c53066b482f87078a7a7b1ecf15ca98a12a122e8d7abca63acfc993186b"
},
{
"file": "BR-16-I-Serie-2008-04-16.pdf",
"sha256": "fc373ff5637edf75ec6a9595dec8763a8503d4ee786e3b7d8f1c742eae9d80ee"
},
{
"file": "BR-248-I-Suplemento-1-2025.pdf",
"sha256": "ccf2a8deeca820f2dd076b4b2141b1efe3f6a806568c3a587ca59a8e92f4c251"
},
{
"file": "BR-89-I-Serie-2017-06-08.pdf",
"sha256": "11f0cab15eb6e51010952203ffa24fdc533a24fd642e19525fe4f46b17a1f5e5"
},
{
"file": "BR-95-I-Suplemento-2025-05-21.pdf",
"sha256": "e0e682e2c027c3cd9c1d46a73a3f48bc5f6bdbf05667fd97314d7a3f6a456358"
},
{
"file": "BR252-I-Serie-2022-Lei20-PESOE.pdf",
"sha256": "1159fd3ce1ba5581671796d083534da48bd3c5578298819e896f1c2a8026318d"
},
{
"file": "Decreto-22-2021-BR70.pdf",
"sha256": "a8fac38dcfe08f9c7a8e46254cff10e1ec82fc4f7a8d88ad6e4fe7d91ffc21a5"
},
{
"file": "Decreto-27-2026-BR123.pdf",
"sha256": "26249c3fa58f149c81de36e99d1aac2819a4771379d9e8833159660dabf539bb"
},
{
"file": "Decreto-29-1998-BR22-5-suplemento.pdf",
"sha256": "6242cbe675faadf085f43f95ec8c7e8868aafe67c3b2ab2bb010992288f954f8"
},
{
"file": "Decreto-3-2011-BR-11-I-mineiros.pdf",
"sha256": "5bca1133666ba9c69870b89823420175b7b5b8d0eccb667ecdf5c29716f3b6be"
},
{
"file": "Decreto-37-2023-BR124.pdf",
"sha256": "7e680b191481faa0e2e9057fa5053587eb2a29d1d8c819e0eb9f02814255a04c"
},
{
"file": "Decreto-9-2008-BR16.pdf",
"sha256": "96fccdecbfdc11c9eafb90fbc6c7bc259f88bbd4c7507d1ac3af1fa03f960697"
},
{
"file": "Lei-13-2016-CIVA-BR-156-10-suplemento.pdf",
"sha256": "b90dc7c14ecea2e378c4a62e8e5a47d54a5644c457baeb8b8053b92fd2a5710b"
},
{
"file": "Lei-14-1992-BR42.pdf",
"sha256": "089fff7423e99a70a230a73ca379e4ea3a91d124703f91016e57ff82794b9e56"
},
{
"file": "Lei-17-2022-BR251-exemplar-MCNet5.pdf",
"sha256": "14eb34f0af91a8f5cb1770c7b52d6ff839c6818302d1ed96d79afbfb9fe999d4"
},
{
"file": "Lei-17-2022-IPP-BR250-Parlamento.pdf",
"sha256": "978cd22403ffd336a631704ecd7a5bbd814a427c815b9acdaca5515591dd9e2a"
},
{
"file": "Lei-19-2013-BR76.pdf",
"sha256": "bba96d645cc935ffc3d1a79b9f0f73ac1c693d6459c2ad41f56cd2841accae76"
},
{
"file": "Lei-19-2017-IRPS-BR-OCAM.pdf",
"sha256": "c3a0186cb9ad090d7a9533006295dc9bb6a62ad0d6150173cbd49dba4ee4b52d"
},
{
"file": "Lei-2-2011-BR-1-4-suplemento-MCNet.pdf",
"sha256": "a7543a68cc3287a46a83c39a04821b40f649dd06c4e9b5dc51ff0b47fba08899"
},
{
"file": "Lei-20-2009-BR36-AT-exemplar19.pdf",
"sha256": "fc1c8144db42960cbf73e717e095896f511ece0f907f58f78819b27d6917a7ee"
},
{
"file": "Lei-22-2022-IVA-republicada-BR-250-2-suplemento.pdf",
"sha256": "ea1b0dc6f5cf6e595f6d9a19e7042f398999e0087caef1785f6e8fac571b5f53"
},
{
"file": "Lei-34-2007-BR52.pdf",
"sha256": "cdbef875ad7ccc1517b12faf5de0e893a70ed2ed81e33913cd6dc4a674474e6e"
},
{
"file": "Lei-4-1994-BR37-3-suplemento.pdf",
"sha256": "210df9db8980d0a5690cd187a6eeec7e37a900d743e39062c16f4e0d12215c7e"
},
{
"file": "Lei-4-2012-BR3.pdf",
"sha256": "b8845cef41dcbd9ba50c43dbfa743a56030dd3d348242a107e1ae30279eec121"
},
{
"file": "Lei-7-1991-Partidos-IFES.pdf",
"sha256": "6b783a0bb3330688ef10660a58060d9724aa2da6a873d234fe902f0eaaeda42d"
},
{
"file": "PT-MZ-CDT-1992.pdf",
"sha256": "d504e1024b28aee5c6acf4592acb96ec9c915a8414f67a61ab6984d6acf9df9d"
},
{
"file": "PT-MZ-Protocolo-2009.pdf",
"sha256": "f353773dcf41f09f4daa6cf5ba5a5f7994f3e02615867c2dcffc61c3d901bf9b"
}
]
},
"rule_sources": [
{
"file": "Lei-34-2007-BR52.pdf",
"pdf_page": 18,
"printed_page": "768-(72)",
"article": "66(1–2)",
"sha256": "cdbef875ad7ccc1517b12faf5de0e893a70ed2ed81e33913cd6dc4a674474e6e"
},
{
"file": "Decreto-9-2008-BR16.pdf",
"pdf_pages": [
6,
7
],
"articles": "21(2/5),27;29 for deferred obligation context",
"sha256": "96fccdecbfdc11c9eafb90fbc6c7bc259f88bbd4c7507d1ac3af1fa03f960697"
}
],
"remaining_code": [
"PEC obligation and instalments, separate from actual payment",
"Prior-year carry, expiry and usage ledger",
"Special credits/autonomous tax/special periods/non-MZN/M20-M22 remain own groups"
],
"documentary_resume_conditions": [
"Published 2026 regulatory amendment: exact articles and effective date for affected obligation/calendar",
"Prior-year PEC: exact last eligible exercise, transition and documented usage",
"Specific positive credit: own legal limit, order, period, evidence and convention if relevant"
],
"private_pilots": "Songo/Gurue unchanged and private; no publication",
"proactive_team_use": "await actual team feedback; implement concrete observed corrections only",
"artifacts": [
{
"file": "Decreto-9-2008-BR16.pdf-6.png",
"sha256": "109f862c8b94e15f55270ec41f90a66ed9cb3b5cf1f772615a8808a9a6034964",
"bytes": 476800
},
{
"file": "Decreto-9-2008-BR16.pdf-7.png",
"sha256": "943f945fae0a5086fad53cc468f1105257c9b4d762220b823816874bd1878884",
"bytes": 504338
},
{
"file": "dossier-capped.json",
"sha256": "a93f9dc6b0b2c21526dfaff9a415bbc2b6a53124dbd860ea5d1809c8868dd2d3",
"bytes": 31771
},
{
"file": "dossier-missing.json",
"sha256": "563e015d9a9069b09dd16548efa21fa37399b24fc6634d136100080706aa6d9a",
"bytes": 32184
},
{
"file": "dossier-payable.json",
"sha256": "b4cde0e17a9306bf08b7f54103eb499d11e4fd14d70fd38e4858013074d08a3a",
"bytes": 32130
},
{
"file": "dossier-prior-use.json",
"sha256": "5b2f95e06711099051fc463509854b439a48f7134c6da45210ce0ca529f77622",
"bytes": 31776
},
{
"file": "dossier-recoverable.json",
"sha256": "27d954e4e6a48980cbbd391a9352ea83456b1e61b42663389f6ada47b55d7c77",
"bytes": 32142
},
{
"file": "existing-records-preservation.json",
"sha256": "b45b3306d3c9dee63fbbaf9a04bba31008019e65892bd16322460b5ef53eda7d",
"bytes": 822
},
{
"file": "Lei-34-2007-BR52.pdf-18.png",
"sha256": "25a5493d2d63d492ca849b5b798b87ad792fa4f6a95493ec96fa5c974c8c4c62",
"bytes": 467400
},
{
"file": "Lei-34-2007-BR52.pdf-19.png",
"sha256": "160f635ce804f400e73d878dff19dc0cae360a195a06952294766f00c74f78d0",
"bytes": 483003
},
{
"file": "PEC-excerpts.json",
"sha256": "3d8795a9bde96195a59dfef0387c1294a14bd6f671d3df76ac8f7e95ebd7a1ad",
"bytes": 19256
},
{
"file": "recovered-capped.json",
"sha256": "e9465e01490fc6f3d52ebdf74d12842d60d5bde155e863a14ec8224592dd5ab4",
"bytes": 349126
},
{
"file": "recovered-missing.json",
"sha256": "32b4183191ed48954f6d13b8b0a2c127a1edfd7a2308370396bf1cce26f7504b",
"bytes": 349856
},
{
"file": "recovered-payable.json",
"sha256": "8b039e9127e57a2b104f7b37dbedb60e857b82e271bee7c784cf9be06fef2731",
"bytes": 344415
},
{
"file": "recovered-prior-use.json",
"sha256": "ae5099bc2dd54755f232567a6cf7c87080ca8fc1dfde09db6ed4426d4189d800",
"bytes": 348899
},
{
"file": "recovered-recoverable.json",
"sha256": "cae038d1abe19bfc3101216d3e0b79a4cc3ef360f3ca4f8fa3e298a7c187d843",
"bytes": 349415
},
{
"file": "recovered-report-receipt.json",
"sha256": "e70e0777dd92cf8ef17d199238cef3fcef8223a4dfba3b56c420ba4aca42a6f7",
"bytes": 5362
},
{
"file": "report-capped.html",
"sha256": "ddf9e4fa8508daa86c2f5a337f57fe6d8c443018c8706d79f34c8151a6bd9465",
"bytes": 5214
},
{
"file": "report-missing.html",
"sha256": "7313eaa4f984ae2976d7a66b81242899bb5a9cc5c55e62f85a0d4813b7710c91",
"bytes": 5594
},
{
"file": "report-payable.html",
"sha256": "d654183e1d293f7fd025918ddaca6da0d30915e4fd6cc4b34e899b210ed6eb52",
"bytes": 5540
},
{
"file": "report-prior-use.html",
"sha256": "113bdc44ad910a8679ec99949726d637297180f078c2b6ba4760076e8dd0da85",
"bytes": 5219
},
{
"file": "report-recoverable.html",
"sha256": "c91511cd25706322ddfc9f081e1058325a8af617a97580c97388304f6481194a",
"bytes": 5552
},
{
"file": "source-preservation.json",
"sha256": "621864a86ef46931a949d039d3de854c339e205310955fa886d9f879404834e2",
"bytes": 4483
}
]
}
@@ -192,3 +192,10 @@ Reutilizados31originais sem alteração por hash. Lei34/2007PDF5/p768(59),15(1)a
## 25/10/2026 — L6:taxa geral para a colecta normal2026
Sem novos originais:31exemplares preservados por hash. Conferidos visualmenteCIRPC Lei34/2007PDF17/p768(71),61(1),taxa geral32%;Lei20/2022PDF1/p2731,61(1)mantido e61(2)temporário;Lei12/2025PDF18/p2180(18),lista de alterações,ePDF20/p2180(20),61-A/vigência. A alteração61(2)daLei4/2012 já aceite é reutilizada. Índice primárioINM confirmaLei20/2022,artigos61/62,p2731. Não se transportam medidas expiradas,casos autónomos ou taxas de retenção para a colecta normal. Enquadramento do caso/ano é expresso;nenhum aprovador ou revalidação genérica criado. Sem pesquisa das pendênciasL5. Retenções/pagamentos/créditos anuais permanecemL8.
## 27/10/2026 — L8: dedução PEC do próprio exercício
Sem novo original legal importado. Conferidos visualmente Lei34/2007PDF18/p768-(72),art66(1–2),eDecreto9/2008PDF6/p121,21(2/5),PDF7/p122,27/29;Lei34PDF19/art71 lido para delimitar obrigação separada. Lei4/2012,Lei19/2013 e acervo de alteraçõesLei12/2025 reutilizados;nenhuma alteração doart66 identificada nesses exemplares. Dedução corrente limitada à colecta,sem reembolso PEC;transporte/caducidade e obrigação separados.30PDFs presentes no arquivo source-archive iguais byte a byte a dc14f01e;recibo source-preservation.json.
Consulta primária dirigida identificou anúncio do Governo de alterações regulamentares2026: https://portaldogoverno.gov.mz/governo-introduz-alteracoes-nos-regulamentos-fiscais-para-reforcar-eficiencia-tributaria/ . O anúncio não fornece o articulado promulgado e contém referência editorial divergente à lei; não é tratado como nova regra. Retoma específica para obrigação/calendário: diploma publicado,artigos e vigência. Sem nova pesquisa genérica ou substituição das fontes aceites;art66 e cálculo simulado corrente permanecem no recorte explícito. Model39 oficialAT identificaPEC,mas não foi inferido transporte automáticoM20/M22: https://edeclaracao.at.gov.mz/formularios/irpc/view/formulario_irpc_m39.aspx .
@@ -0,0 +1,40 @@
{
"date": "2026-10-27",
"status": "exercise_prepared_awaiting_real_team_use",
"installed_reference_from_accepted_receipt": "9fda6d6e12832a3cf25e7314f1f895dd430238c5",
"installation_receipt": "docs/investmoz/unification/sequential-delivery-installed-20261027.json",
"guide": "docs/investmoz/unification/traceability-and-manual.md#27102026--avaliação-de-utilização-pela-equipa-sem-codex",
"evaluation_scope": [
"prepare a private work analysis using an existing authorised source",
"record evidence with source,period,coverage and distinction between fact and hypothesis",
"structure a complementary idea with clients/payer,conditions and unknowns",
"save and recover through the interface",
"preview/confirm and recover in the same dossier",
"revise a pending point and recover the new version without duplication"
],
"existing_guide_reused": true,
"technical_proofs_reused": true,
"new_technical_tests": 0,
"new_installations": 0,
"active_application_writes": 0,
"private_pilots_modified": false,
"team_messages_sent": 0,
"team_execution_observed": false,
"participants": [],
"observed_results": [],
"Codex_executes_team_exercise": false,
"existing_authorised_accounts_only": true,
"new_permissions_or_roles": false,
"not_a_new_approval_gate": true,
"results_to_return": [
"date and operational profile",
"internal analysis/dossier references in authorised channel",
"steps achieved and guide/human help used",
"step/field and concrete difficulty",
"exact message or behaviour and expected result"
],
"resume_when": "Real team observations arrive;address only reported usability/access/save-recovery obstacles",
"commercial_validation_separate": true,
"Songo_and_Gurue": "private;external commercial evidence pending",
"L8": "partial;PEC and own credits separate"
}
@@ -0,0 +1,719 @@
{
"date": "2026-10-27T10:51:18.002627+00:00",
"status": "both_deliveries_installed_in_requested_order",
"order": [
"l8",
"proactive"
],
"stages": {
"l8": {
"candidate": "c85e772d2fd2be5182eb4d768ddd34d43962bf59",
"previous": "f8d57bddf96b4610604a013fcc5bdd703c7dc6d5",
"installed": {
"status": "installed",
"commit": "c85e772d2fd2be5182eb4d768ddd34d43962bf59",
"release": "/var/www/investmoz-homologacao/releases/c85e772d2fd2be5182eb4d768ddd34d43962bf59-ae7401aa",
"previous_release": "/var/www/investmoz-homologacao/releases/f8d57bddf96b4610604a013fcc5bdd703c7dc6d5-7a31e8ac",
"database_migrations": 0,
"content_imports": 0
},
"served": {
"commit": "c85e772d2fd2be5182eb4d768ddd34d43962bf59",
"branch": "main",
"built_at": "2026-10-27T10:32:26.854949+00:00",
"manifest_sha256": "f27852b26d53b46f6927ee46c13370db17a4bec1623655552fd8fdca3589005a"
},
"backup": {
"stage": "/var/backups/investmoz-sequential-20261027/l8/backup",
"created_at": "2026-10-27T10:25:59Z",
"target": {
"database": "teste_investidor",
"port": 5432
},
"tables": 174,
"files_verified": 369,
"dump_sha256": "11bc7c8f25edc861b18785a9714845384cf29a5da92f58f55ff53f6913e69d42",
"files_sha256": "52ffe40bcf943ce580047b55c34b60d3ba876d81dd4bc3ff4fbe1ec97a9c6f56",
"restore_verified": false
},
"restore": {
"restore_verified": true,
"tables_verified": 174,
"container_network": "none",
"database": "irpc_l8_first_restore_20261027",
"port": 55441,
"source_dump_sha256": "11bc7c8f25edc861b18785a9714845384cf29a5da92f58f55ff53f6913e69d42",
"active_database_writes": 0
},
"capacity_after_backup": {
"at": "2026-10-27T10:28:35.403687+00:00",
"baseline": "f8d57bddf96b4610604a013fcc5bdd703c7dc6d5",
"capacity_after_backup_satisfied": true,
"volumes": [
{
"path": "/var/www/investmoz-homologacao/releases",
"free_bytes": 98153496576,
"free_inodes": 23860325
},
{
"path": "/var/lib/investmoz-deploy",
"free_bytes": 98153496576,
"free_inodes": 23860325
},
{
"path": "/var/backups",
"free_bytes": 98153496576,
"free_inodes": 23860325
},
{
"path": "/tmp",
"free_bytes": 98153496576,
"free_inodes": 23860325
},
{
"path": "/var/lib/docker",
"free_bytes": 98153496576,
"free_inodes": 23860325
}
],
"backup_age_seconds": 156.403651,
"backup_dump_sha256": "11bc7c8f25edc861b18785a9714845384cf29a5da92f58f55ff53f6913e69d42",
"restore_verified": true,
"tables_verified": 174,
"files_verified": 369,
"backup_paths": {
"dump": "/var/backups/investmoz-sequential-20261027/l8/backup/database.dump",
"files": "/var/backups/investmoz-sequential-20261027/l8/backup/files-before.tar.gz"
},
"active_writes": 0
},
"source": {
"phase": "after",
"installed": "c85e772d2fd2be5182eb4d768ddd34d43962bf59",
"files_verified": 996,
"source_matches_Git": true,
"active_writes": 0
},
"schema_permissions": {
"schema_sha256": "5045b3e51d2185377aa3d9ac7fa07a44fad3ec620cdfa83ffe31c8884ee1601d",
"roles_grants_sha256": "1530c33cb016e67bfdc64891ddfce7f185b13b56b2cd87c012871a685e118109",
"filesystem_permissions": {
".env": {
"mode": 416,
"uid": 1001,
"gid": 33
},
"storage": {
"mode": 1533,
"uid": 1001,
"gid": 33
},
"storage/app": {
"mode": 1533,
"uid": 1001,
"gid": 33
},
"bootstrap/cache": {
"mode": 1528,
"uid": 1001,
"gid": 33
}
},
"comparison_identity": "postgres;catalogue read only;no passwords collected",
"unchanged": true
},
"preservation": {
"checked_at": "2026-10-27T10:34:53.148104+00:00",
"installed": "c85e772d2fd2be5182eb4d768ddd34d43962bf59",
"business_tables_unchanged": 172,
"total_tables": 174,
"operational_tables_to_reconcile": {
"cache": {
"before": {
"rows": 106,
"checksum": "6c05e12d73079effd52f3add83104de2"
},
"after": {
"rows": 106,
"checksum": "a9c2d7df6ecc8cabba35d5c6f1d019c5"
}
},
"sessions": {
"before": {
"rows": 11,
"checksum": "b83d84b3894b8fc6ef42b0b8fd937304"
},
"after": {
"rows": 12,
"checksum": "fea9aecf735aa394f40e9a4b6a55e27f"
}
}
},
"persistent_files_unchanged": 369,
"original_configuration_preserved": true,
"synthetic_QA_storage_not_served": true,
"QA_storage_saved_outside_active": "/var/lib/investmoz-deploy/qa-runtime/c85e772d2fd2be5182eb4d768ddd34d43962bf59-ae7401aa",
"fixture_or_content_imports": 0,
"migrations": 0,
"comparison_identity": "postgres;UTC;consistent before snapshot and after read-only transaction",
"active_database_writes": 0
},
"operational_delta": {
"status": "operational_delta_reconciled",
"comparison_identity": "postgres before/after;isolated restored baseline;no RLS visibility inference",
"cache": "queue:restart;requestthrottle;identical home-sector cached value with refreshed expiry(HomeController remember10min);no deletedcache",
"sessions": "anonymous sessions from delivery user-agent or exactUA/time correlated with nginx public request;deleted sessions individually expired beyond configured lifetime,normal database session garbage collection(config/session lottery2/100)",
"delta": {
"cache": {
"before_rows": 106,
"after_rows": 106,
"changes": [
{
"key_sha256": "7f7dd83f47f5bf404d55e6e9f1367948721579970b195680645e356031a070ff",
"kind": "updated",
"fields": [
"value",
"expiration"
],
"key_pattern": "investemoz-cache-illuminate:queue:restart",
"is_queue_restart_key": true,
"expiration_unchanged": false,
"throttle_timer_pair": false,
"same_value_home_cache_expiry_refresh": false
}
]
},
"sessions": {
"before_rows": 11,
"after_rows": 15,
"changes": [
{
"key_sha256": "7a0b0d7c40ef99d4c033c9df695a5cd69d6433f068463fdf9f8baff6835453f6",
"kind": "added",
"fields": [
"id",
"ip_address",
"user_agent",
"payload",
"last_activity"
],
"anonymous_user": true,
"delivery_user_agent": true,
"expired_before_comparison": false,
"session_lifetime_minutes": 120,
"anonymous_public_request_logged": true
},
{
"key_sha256": "9f06bc9fb6ef8d45fe1c1093b4e54b59ee080463861b8051271597b0ec5e45a4",
"kind": "added",
"fields": [
"id",
"ip_address",
"user_agent",
"payload",
"last_activity"
],
"anonymous_user": true,
"delivery_user_agent": true,
"expired_before_comparison": false,
"session_lifetime_minutes": 120,
"anonymous_public_request_logged": true
},
{
"key_sha256": "e66f917f9d71192fe17cf2c7c26046afa6bff0db292d0c232a5b59629be030a3",
"kind": "added",
"fields": [
"id",
"ip_address",
"user_agent",
"payload",
"last_activity"
],
"anonymous_user": true,
"delivery_user_agent": true,
"expired_before_comparison": false,
"session_lifetime_minutes": 120,
"anonymous_public_request_logged": true
},
{
"key_sha256": "a84b009ac5f5358a0452f4a40968a4826e34ced257930b6ecf08a0289aa6684f",
"kind": "added",
"fields": [
"id",
"ip_address",
"user_agent",
"payload",
"last_activity"
],
"anonymous_user": true,
"delivery_user_agent": true,
"expired_before_comparison": false,
"session_lifetime_minutes": 120,
"anonymous_public_request_logged": true
}
]
}
},
"business_tables_to_confirm_separately": 172,
"active_data_writes_by_comparison": 0,
"restore_network": "none"
},
"public_delta": {
"stage": "l8",
"served_revision": {
"commit": "c85e772d2fd2be5182eb4d768ddd34d43962bf59",
"branch": "main",
"built_at": "2026-10-27T10:32:26.854949+00:00",
"manifest_sha256": "f27852b26d53b46f6927ee46c13370db17a4bec1623655552fd8fdca3589005a"
},
"manifest_hash_matches": true,
"compiled_delta_markers": {
"IRPC-annual-settlement/1": [
"assets/project-dossier-BNt4O6Rz.js"
],
"Preparar saldo anual L8": [
"assets/services-BvFvahdE.js"
],
"Calcular e guardar saldo anual L8": [
"assets/services-BvFvahdE.js"
],
"Saldo anual simulado": [
"assets/project-dossier-BNt4O6Rz.js"
],
"PEC e créditos separados": [
"assets/project-dossier-BNt4O6Rz.js"
]
},
"assets": [
{
"file": "assets/simulation-form-zFZ4YNrB.js",
"status": 200,
"sha256": "338068b86cce1c3215ee71b1328a6cb2f754b903ed78ff1886f8554df506d2d6"
},
{
"file": "assets/services-BvFvahdE.js",
"status": 200,
"sha256": "97615f0d113746ee5ac1550a1e59c567dd152ef5ddac68f133bd2cee9e9c16d1"
},
{
"file": "assets/project-dossier-BNt4O6Rz.js",
"status": 200,
"sha256": "8cf6a6678c5c9aed0d7b996147bc2fde35d20f86c73ec7bd894df2ae11aae75c"
},
{
"file": "assets/project-dossier-document-Cj4QX7oF.js",
"status": 200,
"sha256": "302ec6831893f2ef4c09a90273b458c49a6ff281adb01c4594a166a90efe53e2"
}
],
"simulator_status": 200,
"served_component": "portal/services",
"private_operations": 0,
"QA_fixture_imports": 0,
"accepted_QA_proofs_reused": true,
"method": "Read-only served revision/manifest/compiled delta;no synthetic active records or publication"
},
"backup_restore_verified": true
},
"proactive": {
"candidate": "9fda6d6e12832a3cf25e7314f1f895dd430238c5",
"previous": "c85e772d2fd2be5182eb4d768ddd34d43962bf59",
"installed": {
"status": "installed",
"commit": "9fda6d6e12832a3cf25e7314f1f895dd430238c5",
"release": "/var/www/investmoz-homologacao/releases/9fda6d6e12832a3cf25e7314f1f895dd430238c5-88fc859c",
"previous_release": "/var/www/investmoz-homologacao/releases/c85e772d2fd2be5182eb4d768ddd34d43962bf59-ae7401aa",
"database_migrations": 0,
"content_imports": 0
},
"served": {
"commit": "9fda6d6e12832a3cf25e7314f1f895dd430238c5",
"branch": "main",
"built_at": "2026-10-27T10:50:00.471464+00:00",
"manifest_sha256": "40de38cbf74b475f73de825bfd16af6fabe339faad4817e2857fd9ae36ec7cc0"
},
"backup": {
"stage": "/var/backups/investmoz-sequential-20261027/proactive/backup",
"created_at": "2026-10-27T10:36:28Z",
"target": {
"database": "teste_investidor",
"port": 5432
},
"tables": 174,
"files_verified": 369,
"dump_sha256": "45107e48e18ab2b9a78af08374fe3bfa0af216f34433c10fc81f264400e331ce",
"files_sha256": "f7196314f915e75975a9e580a69ddc4dffae64597ae05e9ae59cfbcbb0b47731",
"restore_verified": false
},
"restore": {
"restore_verified": true,
"tables_verified": 174,
"container_network": "none",
"database": "irpc_l8_first_restore_20261027",
"port": 55441,
"source_dump_sha256": "45107e48e18ab2b9a78af08374fe3bfa0af216f34433c10fc81f264400e331ce",
"active_database_writes": 0
},
"capacity_after_backup": {
"at": "2026-10-27T10:46:06.120042+00:00",
"baseline": "c85e772d2fd2be5182eb4d768ddd34d43962bf59",
"capacity_after_backup_satisfied": true,
"volumes": [
{
"path": "/var/www/investmoz-homologacao/releases",
"free_bytes": 95851429888,
"free_inodes": 23794207
},
{
"path": "/var/lib/investmoz-deploy",
"free_bytes": 95851429888,
"free_inodes": 23794207
},
{
"path": "/var/backups",
"free_bytes": 95851429888,
"free_inodes": 23794207
},
{
"path": "/tmp",
"free_bytes": 95851429888,
"free_inodes": 23794207
},
{
"path": "/var/lib/docker",
"free_bytes": 95851429888,
"free_inodes": 23794207
}
],
"backup_age_seconds": 578.120001,
"backup_dump_sha256": "45107e48e18ab2b9a78af08374fe3bfa0af216f34433c10fc81f264400e331ce",
"restore_verified": true,
"tables_verified": 174,
"files_verified": 369,
"backup_paths": {
"dump": "/var/backups/investmoz-sequential-20261027/proactive/backup/database.dump",
"files": "/var/backups/investmoz-sequential-20261027/proactive/backup/files-before.tar.gz"
},
"active_writes": 0
},
"source": {
"phase": "after",
"installed": "9fda6d6e12832a3cf25e7314f1f895dd430238c5",
"files_verified": 1000,
"source_matches_Git": true,
"active_writes": 0
},
"schema_permissions": {
"schema_sha256": "5045b3e51d2185377aa3d9ac7fa07a44fad3ec620cdfa83ffe31c8884ee1601d",
"roles_grants_sha256": "1530c33cb016e67bfdc64891ddfce7f185b13b56b2cd87c012871a685e118109",
"filesystem_permissions": {
".env": {
"mode": 416,
"uid": 1001,
"gid": 33
},
"storage": {
"mode": 1533,
"uid": 1001,
"gid": 33
},
"storage/app": {
"mode": 1533,
"uid": 1001,
"gid": 33
},
"bootstrap/cache": {
"mode": 1528,
"uid": 1001,
"gid": 33
}
},
"comparison_identity": "postgres;catalogue read only;no passwords collected",
"unchanged": true
},
"preservation": {
"checked_at": "2026-10-27T10:50:49.400700+00:00",
"installed": "9fda6d6e12832a3cf25e7314f1f895dd430238c5",
"business_tables_unchanged": 172,
"total_tables": 174,
"operational_tables_to_reconcile": {
"cache": {
"before": {
"rows": 106,
"checksum": "a9c2d7df6ecc8cabba35d5c6f1d019c5"
},
"after": {
"rows": 106,
"checksum": "db78f82003db53db664667b8e6f46088"
}
},
"sessions": {
"before": {
"rows": 15,
"checksum": "4df23659bf65acacc88e1d84d095a243"
},
"after": {
"rows": 20,
"checksum": "64d48443c5027a2fc08615f7528126b5"
}
}
},
"persistent_files_unchanged": 369,
"original_configuration_preserved": true,
"synthetic_QA_storage_not_served": true,
"QA_storage_saved_outside_active": "/var/lib/investmoz-deploy/qa-runtime/9fda6d6e12832a3cf25e7314f1f895dd430238c5-88fc859c",
"fixture_or_content_imports": 0,
"migrations": 0,
"comparison_identity": "postgres;UTC;consistent before snapshot and after read-only transaction",
"active_database_writes": 0
},
"operational_delta": {
"status": "operational_delta_reconciled",
"comparison_identity": "postgres before/after;isolated restored baseline;no RLS visibility inference",
"cache": "queue:restart;requestthrottle;identical home-sector cached value with refreshed expiry(HomeController remember10min);no deletedcache",
"sessions": "anonymous sessions from delivery user-agent or exactUA/time correlated with nginx public request;deleted sessions individually expired beyond configured lifetime,normal database session garbage collection(config/session lottery2/100)",
"delta": {
"cache": {
"before_rows": 106,
"after_rows": 106,
"changes": [
{
"key_sha256": "7f7dd83f47f5bf404d55e6e9f1367948721579970b195680645e356031a070ff",
"kind": "updated",
"fields": [
"value",
"expiration"
],
"key_pattern": "investemoz-cache-illuminate:queue:restart",
"is_queue_restart_key": true,
"expiration_unchanged": false,
"throttle_timer_pair": false,
"same_value_home_cache_expiry_refresh": false
}
]
},
"sessions": {
"before_rows": 15,
"after_rows": 20,
"changes": [
{
"key_sha256": "f78ee9e6f589e1bbda4730d4e71a90c9ad082cc25776c415b6cc815ce4b4d491",
"kind": "added",
"fields": [
"id",
"ip_address",
"user_agent",
"payload",
"last_activity"
],
"anonymous_user": true,
"delivery_user_agent": true,
"expired_before_comparison": false,
"session_lifetime_minutes": 120,
"anonymous_public_request_logged": true
},
{
"key_sha256": "7eb58435f5d60610be81945c0da4331a1dbfda680f7da3f107dbbeb6b60c39df",
"kind": "added",
"fields": [
"id",
"ip_address",
"user_agent",
"payload",
"last_activity"
],
"anonymous_user": true,
"delivery_user_agent": true,
"expired_before_comparison": false,
"session_lifetime_minutes": 120,
"anonymous_public_request_logged": true
},
{
"key_sha256": "1d5026f13ace3894011db54d801f72cd76f9b138d54fe2f7b89f579743282db6",
"kind": "added",
"fields": [
"id",
"ip_address",
"user_agent",
"payload",
"last_activity"
],
"anonymous_user": true,
"delivery_user_agent": true,
"expired_before_comparison": false,
"session_lifetime_minutes": 120,
"anonymous_public_request_logged": true
},
{
"key_sha256": "56820cc8560f13a2c0962a973bd05624712648c2beffd2058dfbae6c9103c7fa",
"kind": "added",
"fields": [
"id",
"ip_address",
"user_agent",
"payload",
"last_activity"
],
"anonymous_user": true,
"delivery_user_agent": true,
"expired_before_comparison": false,
"session_lifetime_minutes": 120,
"anonymous_public_request_logged": true
},
{
"key_sha256": "a91337e37e71b520dd6d621b0ef7bbf68a9a20d099198ecd8edfdc365a9f52f1",
"kind": "added",
"fields": [
"id",
"ip_address",
"user_agent",
"payload",
"last_activity"
],
"anonymous_user": true,
"delivery_user_agent": true,
"expired_before_comparison": false,
"session_lifetime_minutes": 120,
"anonymous_public_request_logged": true
}
]
}
},
"business_tables_to_confirm_separately": 172,
"active_data_writes_by_comparison": 0,
"restore_network": "none"
},
"public_delta": {
"stage": "proactive",
"served_revision": {
"commit": "9fda6d6e12832a3cf25e7314f1f895dd430238c5",
"branch": "main",
"built_at": "2026-10-27T10:50:00.471464+00:00",
"manifest_sha256": "40de38cbf74b475f73de825bfd16af6fabe339faad4817e2857fd9ae36ec7cc0"
},
"manifest_hash_matches": true,
"compiled_delta_markers": {
"IRPC-annual-settlement/1": [
"assets/project-dossier-DFH3NDYe.js"
],
"Preparar saldo anual L8": [
"assets/services-CV6TWKfT.js"
],
"Calcular e guardar saldo anual L8": [
"assets/services-CV6TWKfT.js"
],
"Saldo anual simulado": [
"assets/project-dossier-DFH3NDYe.js"
],
"PEC e créditos separados": [
"assets/project-dossier-DFH3NDYe.js"
],
"Território e sector": [
"assets/proactive-investment-CPkgrUFY.js"
],
"Preparar análise e ideia": [
"assets/proactive-investment-CPkgrUFY.js"
],
"Hipótese analítica": [
"assets/project-dossier-DFH3NDYe.js",
"assets/proactive-investment-CPkgrUFY.js"
],
"Documento existente associado": [
"assets/proactive-investment-CPkgrUFY.js"
],
"Origem privada autorizada deste dossier": [
"assets/proactive-investment-CPkgrUFY.js"
]
},
"assets": [
{
"file": "assets/project-dossier-DFH3NDYe.js",
"status": 200,
"sha256": "62f4e47f6efbb7916663604450ee427401080fad6f9332be2cd0dc017866b85a"
},
{
"file": "assets/project-dossier-document-CgBtS4qw.js",
"status": 200,
"sha256": "fb9aa7e305891719ae49cf8bbcee05b3114c05c8ee1df20238964fddb56721dd"
},
{
"file": "assets/catalogue-DRXXB4Y7.js",
"status": 200,
"sha256": "66a2ae7c819f1ac36ffd37e8456c3cfd2537c820845b20eddb4dd7bfaf4a32a2"
},
{
"file": "assets/services-CV6TWKfT.js",
"status": 200,
"sha256": "656da0adacd9141fcd9b1e82ab9959a62ea381a3815e183c5535801c95d92dff"
},
{
"file": "assets/simulation-form-zFZ4YNrB.js",
"status": 200,
"sha256": "338068b86cce1c3215ee71b1328a6cb2f754b903ed78ff1886f8554df506d2d6"
},
{
"file": "assets/proactive-investment-CPkgrUFY.js",
"status": 200,
"sha256": "288cd1005a05c82241a1ddd8c5bb446e297ead7b7605060cec80d268726522ac"
},
{
"file": "assets/opportunity-draft-Da2FBHoN.js",
"status": 200,
"sha256": "ba50f61a39693ebebbe30ba1937d45c92b80f81ab9a98418ef75662f893cdfb2"
},
{
"file": "assets/detail-BfSgTC5d.js",
"status": 200,
"sha256": "234657a2e5ebad7985d78ea49c5536c31e4aac9a143a02e7682d898e47cee530"
},
{
"file": "assets/show-CJYhqIE4.js",
"status": 200,
"sha256": "6579df14a154c98235330f550e13bee20e74f19517cc1d166ae26322f56c74f9"
}
],
"simulator_status": 200,
"served_component": "portal/services",
"public_catalogue_delta": {
"ideas": {
"status": 200,
"component": "investment/catalogue"
},
"needs": {
"status": 200,
"component": "investment/catalogue"
},
"exists": {
"status": 200,
"component": "investment/catalogue"
}
},
"private_operations": 0,
"QA_fixture_imports": 0,
"accepted_QA_proofs_reused": true,
"method": "Read-only served revision/manifest/compiled delta;no synthetic active records or publication"
},
"backup_restore_verified": true
}
},
"main": "9fda6d6e12832a3cf25e7314f1f895dd430238c5",
"final_served_revision": "9fda6d6e12832a3cf25e7314f1f895dd430238c5",
"private_pilots_preserved_no_publication": true,
"fixtures_not_imported_into_active_database": true,
"QA_runtime_storage_outside_active_release": true,
"active_schema_migrations": 0,
"new_grants": false,
"SGF_TEMPO": "untouched",
"accepted_business_proofs": "reused;post-install checks limited to deltas;existing installer automated checks retained",
"prior_capacity_GiB": 91.60694122314453,
"second_delivery_retry": {
"initial_candidate": "56c0c6a7caa65a4cac54e17f9d455739f8eb6198",
"initial_candidate_activated": false,
"active_L8_preserved": true,
"reason": "One frontend test depended on ignored local outputs/proactive-investment-20261027/recovered-context.json",
"correction": "9fda6d6e12832a3cf25e7314f1f895dd430238c5 changes only the test and a minimal synthetic public API projection;no profile,pilot,credentials or live records",
"application_runtime_identical_to_56c0c6a7": true,
"directed_portability_test": "passed;one test;no skipped test",
"existing_installer_guards_retained": true
}
}
@@ -0,0 +1,79 @@
{
"date": "2026-10-27",
"status": "authorised_prepared_not_installed_SSH_session_unavailable",
"authorization": "User explicitly authorised both deliveries,first L8 then proactive,no new authorisation required",
"stage1": {
"candidate": "c85e772d2fd2be5182eb4d768ddd34d43962bf59",
"includes": "14360748194f3658d91a7d7ae5615efd0fcbfbb7",
"runtime": "11a6cee981f0a425b0fceefb6ed85485bb298245",
"capacity_notes_reconciled": "c85e772d changes documentation only;historical suspension superseded by current explicit authorisation;capacity must be freshly measured",
"runtime_delta_files": [
"resources/js/components/simulation-form.tsx",
"resources/js/components/simulation-irpc-annual.tsx",
"resources/js/lib/irpc-annual-settlement.ts",
"resources/js/lib/project-dossier-report.ts",
"resources/js/lib/project-dossier.ts"
]
},
"stage2": {
"runtime_merge_commit": "74f7f93a750cfb88f9816512ee7add6473a3e34f",
"branch": "codex/sequential-delivery-20261027",
"includes_proactive_candidate": "0ff402a11dbf8d41c499dccd39184fdc20c833f4",
"L8_is_ancestor": true,
"shared_report_conflict": "Both imports and both row providers retained",
"L8_other_runtime_files_byte_identical": [
"resources/js/components/simulation-form.tsx",
"resources/js/components/simulation-irpc-annual.tsx",
"resources/js/lib/irpc-annual-settlement.ts",
"resources/js/lib/project-dossier-report.ts"
],
"proactive_other_runtime_files_byte_identical": true
},
"local_verification": {
"TypeScript": "passed",
"isolated_build": "passed",
"shared_report_delta": {
"scope": "Only shared dossier report merge integration;accepted business-rule suites reused",
"annual_rows": 6,
"proactive_rows": 10,
"annual_report_preserved": true,
"private_idea_report_preserved": true,
"inputs_unchanged": true,
"no_cross_inference": true,
"no_QA_data_written_or_published": true
},
"accepted_suites": "reused,not repeated",
"no_database_or_fixture_operations": true
},
"server": {
"SSH_bridge_state": "closed",
"key_authentication": "denied with registered host key verified",
"fresh_capacity": "not measured in this passage",
"fresh_backup": false,
"fresh_restore": false,
"installation": false,
"public_served_revision_read": {
"checked_at_UTC": "2026-10-27T10:14:16.489135+00:00",
"http_status": 200,
"revision": {
"commit": "f8d57bddf96b4610604a013fcc5bdd703c7dc6d5",
"branch": "main",
"built_at": "2026-10-26T14:26:51.629481+00:00",
"manifest_sha256": "367be71b25b56a83571d610e211ea11beae2af87989d62ef6cc7b9c54eabf580"
},
"method": "Public revision read only;no SSH,backup or installation executed"
}
},
"main_at_preparation": "f8d57bddf96b4610604a013fcc5bdd703c7dc6d5",
"main_push_executed": false,
"required_execution_controls": [
"Use existing authenticated local SSH session;do not request authorisation again",
"Fresh capacity/inodes,backup and restore per existing procedure;keep active release until candidate ready",
"Refresh preparation candidate/base/hashes per stage;do not reuse old dated receipts",
"Stage1 only,L8;verify actual served revision and onlyL8 delta",
"Only after stage1 confirmed,stage2;fresh guards and verify proactive delta and L8 preservation",
"Exclude QA fixtures/outputs/test data from deployment inputs;no seed/import;preserve private pilots",
"Return actual installed/served hashes and fresh receipt paths;do not label this local preparation as installation"
],
"actual_remote_changes": 0
}
@@ -2523,8 +2523,8 @@ As estimativas são **horas de trabalho técnico**, não calendário nem mediç
| L4 — ISPC: elegibilidade e apuramento | Campos de enquadramento e motor genérico | Regime/actividade/volume elegível, opções/exclusões, escalões/taxas aplicáveis, mínimo, trimestre e retenções específicas; comparação só entre regimes admissíveis | Vendas por actividade, custos, NUIT, natureza jurídica e residência confirmada | Lei9/2025 e regulamentação/período; distinguir receita anual, trimestre e excesso | 40–64 h |
| L5 — retenções IRPC e guias | Documentos de compras/vendas e guia M/39 como exemplar | Rendimento pago/recebido, entidade que retém, residente/não residente/EP, evento temporal, excepções e casos digitais/e-money; guia e comprovativo ligados à operação | Contrapartes, facturas, pagamentos, período, moeda, oportunidade | Artigos aplicáveis por rendimento, taxa/convenção se invocada; corrigir remissões do exemplar. Sem submissão electrónica AT presumida | 32–56 h |
| L6 — IRPC anual: regime normal | Disponível5aaf1a56:percurso normal demonstrado atécolecta,períodos/moedas e preparação parcialM20/M22 | Operacional no âmbito demonstrado por decisãoTempo26/10;limitações explícitas;5grupos código+5documentais preservados;sem conclusão integral | Plano financeiro,dados comuns,activos/livros e histórico;retenções/pagamentos/créditos anuaisL8 | Pendências bloqueiam só os casos dependentes;L7/L8 próprios | Estimativa inicial48–80h;saldo não reestimado |
| L7 — IRPC: tratamentos específicos | 632dc069 instalado;cumulações14 prontas emQA,sem instalação | CIRPC12+CBF16 qualificados e61(4) separado;incompatibilidadeCBF4/13 e lacunas explícitas;L7parcial | Activos/períodos/saldos/benefícios reutilizados;diferença25 uma vez e15 já nos75;taxa16% só sobre base elegível | Outras combinações/excepções e restantes tratamentos dependem de regra/parcela/ordem/limites;L8 conserva saldo final | Estimativa inicial48–80h;saldo integral não reestimado |
| L8 — IRPC: liquidação e pagamentos | Parcelas L5–L7 e formulários originais | PPC/PEC, deduções/créditos, dupla tributação quando aplicável, saldo anual a pagar/recuperar; calendário e reconciliação com pagamentos | Retenções, colecta, saldos anteriores, pagamentos/comprovativos | Base anterior para PPC/PEC, regras de limitação/transporte; não usar cinco anos ou compensação automática sem cotejo específico | 32–56 h |
| L7 — IRPC: tratamentos específicos | f8d57bdd instalado;632dc069 e a7434cd2 preservados no percurso | Cumulações demonstradas disponíveis;7famílias de saldo e documentos por caso discriminados;L7parcial | Activos/períodos/saldos/benefícios reutilizados;ordem,limites e incompatibilidades explícitos | Outras combinações/específicos/mistos/transporte próprios;L8delimitado separadamente | Inicial48–80h;saldo não reestimado |
| L8 — IRPC: liquidação e pagamentos | Primeiro saldo com retenções/PPC entregue em9fda6d6e;dedução de PEC corrente comprovado emQA,sem instalação | Residente geral2026/MZN;PEC limitado à colecta,sem reembolso do excedente;ausência/zero/falta explícitos | ColectaL6/L7,L5received/effective/on_account,comprovativos e histórico anual reutilizados | Transporte/obrigaçãoPEC,créditos próprios,autónomos,períodos/moedas eM20M22 específicos;pendências só dependentes | Inicial32–56h;não é previsão actual do saldo |
| L9 — INSS: contribuição social | Massa salarial agregada e referência TCO3%+4% | Trabalhadores, remuneração/base contributiva, exclusões, empregador/trabalhador, TCO/TCP, declaração e encargos por período | Equipa/custos, entidade e calendário; cadastro de pessoa partilhado com L10 | Regulamento e alterações aplicáveis, natureza do vínculo; confirmar base antes da taxa. Contribuição social, distinta dos impostos | 24–40 h |
| L10 — IRPS: retenção mensal e líquido | Entrada IRPS, custos salariais e escalões anuais documentais | Tabela mensal própria, remunerações/benefícios, situação pessoal relevante, retenção, salário líquido e contribuição ligada a L9 | Mesmo trabalhador/folha salarial, pagamentos e retenções | Tabela mensal do período, residência e condições familiares necessárias; não dividir escalões anuais por12 | 40–64 h |
| L11 — IRPS: apuramento anual e outras categorias | Escalões anuais e exemplares M/19/M/20/anexos | Categorias aplicáveis aos rendimentos documentados, actividade independente, capitais/prediais/mais-valias, englobamento/tratamento autónomo, deduções, retenções e saldo | Dados pessoais autorizados, rendimentos/despesas, activos e L10 | Código IRPS/Lei11/2025, âmbito/categoria/período e deduções pessoais; diferenças de edição dos anexos. Não copiar regras IRPC | 48–80 h |
@@ -6573,6 +6573,110 @@ Entrega agrupada preparada com os sete casos novos compatíveis;incompatibilidad
Conferência de compatibilidade:main `a7434cd2` incorporado na candidata,com apresentação/catálogo e linhas não fiscais da matriz preservados. Recuperada a adenda históricaQA13 que tinha desaparecido do manual no main;isto é perda documental,não perda do cálculo13. Só tipos/build de integração foram conferidos novamente;provas fiscais aceites conservadas. A revisão servida não foi consultada nesta passagemQA.
## 26/10/2026 — Cumulações L7 entregues pelo Git
**Instalado `f8d57bddf96b4610604a013fcc5bdd703c7dc6d5`.** A anteriora7434cd2,que já incluía632dc069,fica preservada. Main/candidata compatíveis;apresentação ecatálogo sectorial entregues entretanto mantidos. A notaQA anterior é histórica:não há pendência de instalação deste incremento.
Medição inicial:5.06GiB,com inodes suficientes,mas sem margem para o backup fresco mais o mínimo5GiB do instalador. Recuperados0.21GiB somente da cache versionada de compilaçãoNode em`/tmp/node-compile-cache`,sem gestores de pacotes ou ficheiros abertos. Fontes,node_modules,releases,backups,logs,originais eSGF mantidos;permissões/proprietário da pasta preservados. Nova capacidade:5.26GiB e21374782inodes. Backup fresco`2026-10-26T14:20:47Z`:174tabelas/369ficheiros econfiguração;restauro isolado sem rede/55441 com174checksums iguais. Após o backup restavam5.10GiB,acima do mínimo5GiB de compilação;a guarda de um segundo backup não é requisito para repetir o backup acabado de executar. Nenhum limiar foi reduzido.
Só depois destas guardas,integraçãoGit sem forçar histórico;release anterior activa até a nova estar pronta. Compilação,tipos econtrolos automáticos do procedimento passaram:1054testesfrontend,API59testes/317asserções,preservação1teste/3106asserções. Reutilizadas as provasQA12testes/API133/UI/relatórios,não repetidas por iniciativa desta entrega. Conferidos4ficheiros fiscais do delta,68protegidos,31originais,369persistentes/configuração e174tabelas;172tabelas de negócio mantidas,cache/sessões reconciliadas com eventos operacionais/acessos públicos. Schema,roles/grants epermissões iguais;sem migrações/importações/escrita privada sintética. Revisão/manifest servidos,15marcadores,4assets eHTTP200 do simulador conferidos.
O recorte mantém a diferençaCBF16 de25MZN aplicada uma vez,com15recuperados já incluídos nos75deduzidos;depois aplica16% à base cooperativa integralmente elegível. No caso combinado,colecta496,80MZN;com despesa autónoma qualificada,512,80+35=547,80MZN. Valores são colecta simulada,não saldo finalL8. IncompatibilidadeCBF4/13,excepções sem correspondência e informação em falta permanecem explícitas;nenhum benefício é escolhido ouapagado automaticamente.
Após a instalação ficaram4.14GiB livres. Antes de outra compilação,voltar a resolver capacidade contra o mínimo existente e o backup dessa execução;esta entrega foi concluída e não autoriza apagar releases,backups ou provas. SaldoL7 e primeiro incrementoL8 são discriminados na secção seguinte. Recibo:`docs/investmoz/simulations/irpc-l7-combinations-delivery-20261026.json`;provas:`outputs/irpc-l7-combinations-delivery-20261026/`. **L7 parcial;L8 conserva saldo final.**
## 26/10/2026 — Saldo consolidado de L7 e primeiro incremento delimitado de L8
**L7 parcial,com a entrega de cumulaçõesf8d57bdd registada acima.** Deixam de estar pendentes de instalação a combinaçãoCIRPC12+CBF16 no recorte qualificado,a separação do imposto autónomo61(4) e os estados de incompatibilidade/falta/excepção não correspondida demonstrados. Isso não implementa todas as cumulações nem os tratamentos abaixo. Fontes oficiais e provas aceites permanecem válidas;documento em falta limita só o caso/campo que dele dependa.
| CódigoL7 ainda por implementar | Exemplo e condição concreta de retoma |
| --- | --- |
| Outras origens/segregações de despesas autónomas | Despesa100 com apenas60 correspondidos em36g ou encargo fora do resultado:ligar origem/parcela e incidência61(4),sem segundo acréscimo. |
| Cooperativas mistas/retidas e demais entidades9–14 | Base agrária com serviços não abrangidos ou rendimentos sujeitos a retenção:segregar proveitos/custos/base e aplicar o artigo específico;não reduzir tudo a16%. |
| ExtensõesCBF16 e outras combinações | Activo anterior a2025,usado/reabilitado/reavaliado,método/período fora da cobertura,ou excepção expressa à não cumulação:ligar regra temporal/base/método e disposição,ordem e limites à parcela;reutilizar activos/quotas,sem reescrever o passado. |
| Mais-valias61-A e operações54–56/41-A | Ganho já incluído no resultado ou transferência de activo/perda:implementar apuramento e reconciliação próprios,sem dupla incidência ou compensação presumida. |
| CBF17–19 e direito potencial15 | Formação/investimento com activos e despesas elegíveis/excluídos:implementar base,limite,janela temporal e compatibilidade. Direito/origem do crédito emL7;utilização anual e saldo emL8. |
| Regimes sectoriais/territoriais e benefícios específicos | EstatutoZEE ou projecto de infra-estruturas:aplicar disposição/período efectivos e excepção quando prevista;endereço/sector não concede benefício. |
| TransporteL7M20/M22 | Efeito calculado sem campo/edição correspondente:identificar exemplar,instrução,campo e representação;conservar o cálculo exacto independente. |
**Documentos por caso,distintos de código:**natureza/parcela/período;estatuto/reconhecimento exigido ou norma de excepção;saldos anteriores e distinção de exclusão temporária/permanente;disposição/ordem/limites da combinação;exemplar/edição/campo/representação. Não pedir nova validação genérica da autenticidade de fontes aceites,nem repetir pesquisas anteriores sem informação nova. Não preencher campo,código,taxa ou saldo por presunção.
### L8 — primeiro percurso a implementar em QA:colecta→pagamentos comprovados→saldo simulado
**Delimitado,não implementado ou instalado nesta passagem.** Recorte inicial:IRPC de residente no regime geral,ano civil2026,MZN,com colecta corrente determinada e suportes que permitem reconciliar o fecho. Parte de uma execuçãoL6 válida ou deL7 válida quando os efeitos aplicáveis estejam qualificados;guarda chave/versão/NUIT/período e valores de origem. Não soma colectaL6 com colectaL7 nem a colecta ordinária com uma colecta combinada que já a inclua. Não usa uma versãoL6 para ignorar um efeitoL7 positivo ou pendente que afecte o mesmo fecho. Um caso ordinário independente não espera pela implementação de outro benefício ou por um campoM20/M22 desconhecido.
**Dados reutilizados e qualificações novas apenas onde necessárias:**
1. **Colecta:**reutilizar a execução e as condições existentes,distinguindo colecta ordinária,imposto autónomo e colecta combinada. O primeiro fecho completo limita-se aos casos com ausência documentada de tributação autónoma/mais-valias que exija liquidação própria. Se existir imposto autónomo positivo,a parcela ordinária pode ser apresentada,mas não como saldo total até corresponder a articulação;não o apagar ou compensar por pressuposto.
2. **Retenções sofridas:**reutilizarL5 apenas quando `direction=received`,natureza `on_account`,origem efectiva,documento/prova e montante sofrido reconciliados,mesmo sujeito/NUIT/período e rendimento incluído na base apropriada. Retenção entregue pela empresa por pagamento a terceiros,retenção definitiva,mera projecção,guia sem pagamento ou montante ainda não comprovado não são crédito próprio. EmL7cooperativa,a declaração de ausência de rendimentos retidos não pode coexistir silenciosamente com retenção recebida positiva;esse caso exige a segregação própria,sem bloquear o regime normal independente.
3. **Pagamentos por conta efectuados:**registar/reutilizar comprovativo,identificador,data,exercício,sujeito e montanteMZN;reconciliar parcelas e pagamentos sem dupla utilização. Neste primeiro incremento,não calcular automaticamente a obrigaçãoPPC a partir do exercício anterior,nem transformar tesouraria prevista em pagamento efectuado.
4. **Outros créditos/PEC:**reutilizar a informação existente e distinguir valor conhecido,ausência declarada e falta de informação. O primeiro percurso completo exige ausência documentada dePEC e créditos por dupla tributação/investimento/outros créditos ainda sem limite/ordem correspondidos. Presença positiva mantém a parcela/fecho dependente indeterminado;não usar zero. CBF15 potencialL7 não é automaticamente crédito anual utilizável. PEC não se transforma em montante reembolsável nem recebe transporte de3/5anos por presunção.
5. **Identidade/duplicação:**contrapartes e documentos existentes são reutilizados;qualificar beneficiário e NUIT do próprio sujeito. Deduplicar por origem/documento/comprovativo e controlar afectações parciais;um comprovativo não pode aparecer integralmente em retenções ePPC,ou em dois exercícios. Preservar valores declarados e histórico,sem consumo de saldo oficial.
**Resultado e sequência a demonstrar:**colecta válida→deduções admissíveis e respectivas ausências→retenções efectivamente sofridas por conta→PPC comprovados→saldo aritmético→aplicação das regras de cobrança/reembolso do recorte→montante simulado a pagar ou recuperar. Mostrar a decomposição e o sinal;zero só com entradas completas ou ausência documentada. Informação em falta não transforma a colecta em saldo final. Como a base nasce do plano,o resultado continua uma simulação identificada,não autoliquidação submetida,pagamento efectuado ou reembolso deferido/recebido.
**Fontes já disponíveis para o cotejo dirigido de implementação:**CIRPC63/67,natureza das retenções com as alteraçõesLei12/2025;RegulamentoDecreto9/2008 art21(2–5),ordem/limites das deduções,eart27(1–2/6),pagamentos e reembolso. O exemplar aceite prevê no27(6) um mínimo de100MZN;esse parâmetro e a fronteira devem ser ligados à versão/período aplicáveis antes de activar o consumidor,não inferidos de um rótulo de formulário. O cotejo de aplicabilidade/alterações desta regra é trabalho de implementação da fonte aceite,não pedido de certificação genérica nem reabertura dos cálculosL6/L7. Arts64–66/PEC e créditos específicos mantêm as suas regras próprias;juros/multas/calendário,geração de guias,submissão e processamento de reembolso seguem incrementos próprios.
| Critério de aceitação a executar,sem prova reivindicada agora | Exemplo sintético proposto |
| --- | --- |
| Saldo positivo com pagamentos/retencões válidos | Colecta1408−retenção sofrida300−PPC500=608MZN de saldo aritmético;qualificar valor a pagar segundo a regra aplicável. |
| Saldo negativo | Colecta1408−retenção1000−PPC600=−192MZN;identificar192 a recuperar no recorte,se a regra permitir,sem afirmar reembolso recebido. |
| Zero e fronteiras do mínimo | Colecta1408−408−1000=0;demonstrar os lados inferior/igual/superior do mínimo do parâmetro versionado,sem arredondamento novo. |
| Ausência vs informação em falta | Ausência documentada de retenções/PPC/outros créditos permite saldo com parcelas zero justificadas;suporte ou natureza por determinar mantém só o fecho dependente indeterminado. |
| Reutilização e dupla dedução | Seleccionar retenção recebida e comprovativo existentes,recusar pagamento a terceiros/retenção definitiva/duplicado e demonstrar conservação dos originais e cenários anteriores. |
| Cálculo→gravação→recuperação→relatório | Novo livro/snapshotL8 ligado à chave da colecta e às provas seleccionadas;resultado13/14 eL5 anteriores imutáveis;mudança da fonte invalida a fotografia corrente sem recalcular históricos. Relatório/exportação apresenta colecta,abatimentos,saldo e lacunas concordantes. |
Só serão demonstradas estas novas regras/efeitos,emQA isolada e com as guardas existentes. Fracções continuam exactas;representação/campos oficiais sem correspondência ficam identificados e não bloqueiam cálculo independente. Pagamentos noutra moeda,períodos especiais,PEC/créditos positivos,liquidação autónoma e demais situações ficam no saldo concreto deL8,com condição de retoma por regra,origem,limite,período e prova. A documentação deste recorte não é novo cálculo executável.
### Esforço global:referência inicial não é previsão actual
As240–416horas deL8–L14 permanecem identificadas como referência inicial de planeamento,não saldo actual nem prazo assumido. Antes de estimar o conjunto:reconciliar por lote o que já está implementado/reutilizável e o que falta em código;descontar provas aceites sem as repetir;separar espera documental;incluir resíduosL1–L7,integrações/entregas eL15–L16,SISA/encargos imobiliários. Campos de entrada,fontes inventariadas ou percentagens isoladas não provam percurso executável completo. Contar apenas o delta necessário e não somar duas vezes componentes partilhados. Esta passagem entregaL7 e delimitaL8;gere uma estimativa reconciliada futura,sem converter os intervalos iniciais numa promessa global. **L7 parcial;saldo finalL8 ainda não implementado nesta entrega.**
## 26/10/2026 — L8: primeiro saldo anual simulado demonstrado em QA
**QA concluído em `11a6cee9`; ainda sem instalação.** `f8d57bdd` permanece a entrega comunicada no portal. Este incremento reutiliza a colecta corrente de L6 ou o total ordinário L7 aplicável, sem somar ambos nem contornar um tratamento pendente. Recorte: sujeito residente no regime geral, ano civil de 2026, MZN, sem PEC/créditos positivos ou imposto autónomo que exijam liquidação própria. L6 operacional no âmbito demonstrado; L7 mantém o saldo parcial já discriminado. Não há nova pesquisa ou reabertura das provas aceites.
**Percurso executável:** «Preparar saldo anual L8» reutiliza NUIT, exercício e chave/versão da colecta sem substituir edições deliberadas. Selecciona os comprovativos L5 recebidos, efectivos, por conta e reconciliados; confirma o próprio beneficiário e a inclusão do rendimento na base do exercício. Retenções entregues pela empresa por pagamentos a terceiros, definitivas ou projectadas não são abatimentos próprios. PPC exige recibo, emitente, data, titular, exercício, moeda, montante comprovado, parcela utilizada e confirmação do pagamento efectivo; não usa previsões do plano nem calcula a obrigação PPC. A reutilização não apaga provas ou consome saldos oficiais.
Conhecido, ausência declarada com suporte e informação em falta são estados distintos. Ausência contraditória, titular/exercício divergente, prova em falta ou origem desactualizada mantêm o saldo dependente indeterminado. A identidade normalizada do emitente/comprovativo detecta repetição mesmo com data alterada; a mesma prova não pode ser retenção e PPC. Controla limites do comprovativo e da afectação L5, incluindo parcelas em outros contextos do mesmo dossier. São simulações alternativas, sem reserva central ou consumo de crédito fiscal entre dossiers independentes.
| Caso demonstrado | Resultado L8 simulado |
| --- | --- |
| Colecta 1 408 − retenção sofrida 300 − PPC 500 | **608 MZN a pagar**. |
| Colecta 1 408 − retenção sofrida 1 000 − PPC 600 | Saldo aritmético −192: **192 MZN a recuperar**, sem afirmar reembolso recebido. |
| Colecta 1 408 − retenção 408 − PPC 1 000 | Saldo zero, com parcelas completas. |
| Ausência declarada de retenções/PPC, PEC ausente e outros créditos conhecidos zero | 1 408 MZN a pagar; estados conhecidos/ausentes conservados. |
| PPC por comprovar, prova repetida ou PEC positivo ainda sem regra própria | Saldo a pagar/recuperar indeterminado; entradas e subtotais conhecidos conservados. |
| Fronteiras do mínimo: saldos ±99,99 e ±100 | Aritmética exacta; abaixo de 100 MZN sem cobrança/reembolso neste recorte; em 100 aplica pagar/recuperar. Sem arredondamento ou transporte de crédito inventado. |
| Colecta anual L7 acelerada aceite de 1 996,80, sem abatimentos declarados | Reutilizada uma vez: saldo simulado 1 996,80, sem somar a referência L6 nem recalcular o benefício. |
**Fontes e limites:** CIRPC arts. 63/67, Lei 34/2007 e natureza da retenção na redacção aplicável da Lei 12/2025; Regulamento Decreto 9/2008 arts. 21(2–5) e 27(1–2/6). O mínimo de 100 MZN do art. 27(6) está ligado ao recorte ordinário de 2026; as alterações IRPC do acervo de 2025 não substituem essa regra. Exemplares, páginas e hashes constam do recibo, com aceitação oficial anterior preservada. Não generalizar este parâmetro a períodos/regimes não correspondidos. PEC positivo, crédito de investimento, dupla tributação e outros créditos não recebem abatimento, limite, transporte ou reembolso presumidos. Um crédito potencial L7 não passa automaticamente a crédito utilizável L8.
**Gravação e recuperação:** livro opcional `irpcAnnual` no snapshot existente, por contexto, sujeito e exercício; ligado à execução da colecta e às provas L5 seleccionadas. Guarda o input e o resultado simulado, acrescenta o resultado anterior ao histórico sem o recalcular, e invalida o resultado corrente quando mudam as fontes/entradas. HTML e dossier financeiro recuperam colecta, provas/parcelas, estados, saldo, lacunas e limites concordantes. Sem preparação L8, os relatórios anteriores não ganham linhas L8. Plano, originais, livros e históricos L5–L7 permanecem imutáveis. O saldo não é declaração submetida, pagamento efectuado ou reembolso recebido.
**Provas novas:** 19 testes frontend dirigidos; API privada QA, 1 teste/170 asserções, sete casos com cálculo → gravação → recuperação → HTML/dossier; base isolada `simulator_fiscal_delta_20261021_test`, loopback 55441, guarda de identidade e transacção com rollback. Interface real: preparar, preencher só dados em falta, seleccionar prova, impedir repetição, pagar/recuperar/zero/ausência/indeterminação, guardar/recarregar/recuperar/exportar, sem erros de página. Wayfinder `--with-form`, TypeScript e build QA passaram. Comparação de 2 832 ficheiros anteriores: só três pontos de integração alterados, mais os cinco ficheiros novos do incremento; motores L5/L6/L7, fontes, fixtures, schema, configuração e permissões preservados; 31 originais iguais. Não se repetiram suites aceites de L3, ISPC, câmbio ou L5–L7. SGF TEMPO separado.
### Saldo concreto L8 após este incremento
| Código ainda por implementar | Condição concreta de retoma |
| --- | --- |
| PEC e créditos positivos: investimento, dupla tributação e outros créditos próprios | Correspondência do crédito, titular/exercício, montante efectivamente disponível, ordem, limite e transporte aplicáveis; prova de cada saldo. Não presumir reembolsabilidade ou prazo de 3/5 anos. |
| Liquidação de imposto autónomo/61-A e articulação com o saldo anual | Segregar a parcela autónoma e corresponder quais abatimentos podem incidir sobre ela; não a ignorar nem compensar automaticamente com prejuízo/PPC. |
| Períodos especiais e comprovativos noutra moeda | Corresponder exercício/data de afectação e regra cambial fiscal do pagamento; reutilizar periodização/câmbio existentes sem confirmar pressupostos por omissão. |
| Cálculo da obrigação PPC/PEC, calendários, juros/multas e guias | Regra, parâmetros, factos e vencimentos próprios por período. O registo de PPC efectuado já demonstrado não calcula a obrigação. |
| Transporte oficial M20/M22, submissão e processamento de reembolso | Edição/campo, representação de fracções e fluxo de recepção correspondidos; sem preencher campos provisórios como oficiais. |
**Esclarecimentos documentais aguardados:** permanecem as dúvidas concretas L5/L6/L7 já registadas, sem nova pesquisa repetida. Exemplo: cooperativa com rendimentos mistos/retidos requer segregação antes de utilizar retenção positiva; excepção de cumulação exige disposição, período e limites correspondidos; campo M20/M22 divergente requer edição/campo exactos. Cada falta só bloqueia o seu caso. Ausência de documento num cenário não bloqueia o saldo normal independente acima.
**Próxima entrega:** compatibilidade conferida com `origin/main` em `f8d57bdd`, sem incorporar runtime do checkout raiz. Nenhum acesso ou operação no servidor nesta passagem. Os 4,14 GiB são o valor comunicado, não medição nova; antes de instalar, medir espaço/inodes, confirmar capacidade para backup/restauro fresco e compilação isolada, mantendo a versão activa até a nova estar pronta. Recibo: `docs/investmoz/simulations/irpc-l8-first-qa-20261026.json`; provas: `outputs/irpc-l8-settlement/`. Reprodução só do delta: `node --test tests/frontend/irpc-annual-settlement.test.mjs`; `php tools/irpc-annual-settlement-qa.php routes`; `php tools/irpc-annual-settlement-qa.php test`; `tsc --noEmit`; build com `INVESTMOZ_QA_BUILD=1`. **L8 parcial, QA pronto, sem instalação.** A referência inicial de 240–416 horas L8–L14 não é previsão actual; permanece necessária a reconciliação do trabalho reutilizado, resíduos e L15–L16 antes de assumir prazo global.
## 27/10/2026 — entrega L8 preparada; instalação adiada por capacidade
**Candidato `14360748` pronto; não instalado.** A conferência SSH autenticada de 27/10, 06:05 UTC (08:05 em Moçambique), confirmou `f8d57bdd` como revisão activa e `main` remoto. Compatibilidade por ancestralidade, pacote QA e 168 ficheiros do destino conferidos: 134 ficheiros protegidos, três integrações anteriores e 31 originais. O delta executável continua limitado a cinco ficheiros L8; os 19 testes, API/170 asserções, interface, recuperação/relatórios, tipos e build aceites foram reutilizados, sem nova ronda.
**Impedimento concreto:** partição `/dev/md2`, montada em `/`, com 4 402 343 936 bytes livres (**4,10 GiB**) e 21 340 182 inodes disponíveis. Inodes suficientes face à referência da release (31 259 entradas). O instalador existente exige **5 GiB livres após o backup**; com a referência observada do backup anterior de 175 917 490 bytes, faltam pelo menos **1,07 GiB adicionais antes do backup**. É uma estimativa mínima de capacidade, a medir novamente; não uma autorização para reduzir o limiar. Caches regeneráveis de Composer/Node somam cerca de 0,12 GiB e não cobrem a diferença. Diagnóstico apenas por leitura, sem limpeza de caches, releases, backups, provas, dependências ou ficheiros SGF TEMPO.
**Decisão expressa do utilizador: «Manter a entrega preparada por agora».** Não foram executados backup/restauro frescos, integração no `main` nem instalação. A versão activa foi preservada e a sessão SSH encerrada. Na retoma, seleccionar o ramo candidato `codex/irpc-l8-settlement-qa-20261026`, voltar a conferir `main` e revisão servida, medir capacidade/espaço/inodes, executar backup/restauro fresco e compilação isolada, mantendo o activo até a nova release estar pronta. Só depois conferir a revisão servida e o delta L8. As notas desta espera ficam no ramo documental `codex/irpc-l8-delivery-capacity-20261027`; não mudam o código candidato. L8 parcial, PEC/créditos próprios separados e saldo L7 preservado. Recibo: `docs/investmoz/simulations/irpc-l8-delivery-capacity-20261027.json`; provas e auxiliares preparados: `outputs/irpc-l8-first-delivery-20261027/` no checkout raiz.
## 27/10/2026 — identidade proactiva: primeiro incremento demonstrado em QA
**QA concluído em `3439f350`; sem instalação, publicação real ou análise económica validada.** Partida no `main` remoto `f8d57bdd`, conferido novamente antes da entrega. Ramo separado `codex/proactive-investment-first-qa-20261027`, worktree `C:/laragon/www/portal-investidor-proactive-qa-20261027`. A referência local `fa02c70` e o ramo `codex/proactive-investment-scope-20261027` não foram encontrados no repositório consultado; o âmbito expresso da Tempo foi suficiente e não se criou dependência desse commit. **L8 `14360748` mantém-se preparado, sem instalação e sem integração nesta candidata.** A capacidade do servidor continua fora deste trabalho local. Sem SSH, instalação, limpeza do servidor ou intervenção no SGF TEMPO nesta passagem.
@@ -6805,3 +6909,103 @@ Runtime desta correcção: `51d536b7`; inclui o percurso técnico `3439f350`/can
**Não instalado.** Antes da entrega activa, medir novamente espaço/inodes na partição do instalador e dos backups, confrontar com a necessidade efectiva de compilação isolada/backup, conferir o main então actual, executar backup/restauro fresco e manter a versão activa até a nova estar pronta. Depois conferir revisão servida e apenas o delta. A preparação dos pilotos QA não integra dados na base activa nem publica oportunidades. L8 `14360748` permanece separado; SGF TEMPO intocado. Não se fizeram SSH, limpeza, backup ou instalação nesta passagem.
Recibo: `docs/investmoz/unification/proactive-team-autonomy-qa-20261027.json`. Provas e pacote local: `outputs/proactive-team-autonomy-20261027/`. A verificação comprova que o percurso está disponível aos perfis autorizados através da interface; não declara formação da equipa, viabilidade dos pilotos ou conclusão integral dos requisitos nacionais.
## 27/10/2026 — duas entregas autorizadas: L8 primeiro, percurso proactivo depois
O responsável autorizou expressamente a execução das duas entregas pelo procedimento existente, sem nova ronda de autorização. A indicação histórica de manter preparado em `c85e772d` foi reconciliada: o commit acrescenta documentação de capacidade, sem mudar o código de L8 `14360748`/runtime `11a6cee9`. A autorização actual permite retomar; não substitui a medição de capacidade nem o backup/restauro frescos.
**Etapa1:** L8 em `c85e772d`, com a colecta válida, retenções efectivamente sofridas e PPC comprovados no recorte aceite; PEC e créditos próprios continuam separados. **Etapa2:** ramo `codex/sequential-delivery-20261027`, merge de L8 e do percurso proactivo `0ff402a1`, runtime reconciliado `74f7f93a`. A etapa2 só segue após confirmar a revisão efectivamente servida na etapa1.
O relatório comum tinha um conflito de imports. Foram conservados ambos e as chamadas de linhas anuais e proactivas. Os restantes ficheiros de runtime de cada candidata ficaram idênticos à origem. Verificação apenas da integração partilhada:6linhas anuais e10linhas proactivas recuperadas, entradas intactas e sem inferência cruzada. TypeScript e compilação QA isolada passaram; suites económicas/fiscais aceites não repetidas. Documentação de ambas as linhas conservada, sem importação de fixtures ou escrita em bases.
**Estado efectivo desta passagem: preparado, sem instalação.** O main remoto permanece `f8d57bdd` e a revisão pública servida foi conferida por HTTP em27/10/2026,10:14UTC, também `f8d57bdd`. A ponte SSH local estava `closed`; a autenticação por chave foi recusada com a chave do servidor registada e conferida. Não havia aqui uma sessão autenticada utilizável. Não foram executados backup/restauro frescos, alteração de main ou instalação. A capacidade antiga de4,10GiB é histórica e não foi apresentada como medição actual.
Retomar na sessão local com SSH autenticado, usando a autorização já registada: medir espaço/inodes na partição efectiva, comparar com compilação e backup, conferir main e revisão activa, criar e ensaiar backup fresco, instalar L8 e conferir apenas o seu delta. Depois repetir as guardas necessárias para a candidata conjunta e conferir o delta proactivo preservando L8. Manter a versão activa até a nova estar pronta. Excluir fixtures QA dos inputs de instalação; não executar seeders/importações de amostras, não publicar pilotos privados nem usar o pacote QA como cópia da base activa. SGF TEMPO separado.
Recibo de preparação: `docs/investmoz/unification/sequential-delivery-preparation-20261027.json`. Provas e instrução de passagem: `outputs/sequential-delivery-20261027/`. Os recibos de execução e as duas revisões servidas serão registados apenas depois de execução real na sessão autenticada; este recibo não os substitui.
## 27/10/2026 — L8 e percurso proactivo instalados pela sequência autorizada
Entrega1: **L8 `c85e772d`**, anterior `f8d57bdd`. Entrega2, apenas após conferir a primeira: **percurso proactivo `9fda6d6e`**, incluindo `56c0c6a7` e preservando L8. As duas revisões foram conferidas no registo do instalador e no recurso público `/build/revision.json`, com hash do manifest e marcadores compilados dos deltas. `c85e772d` conserva o código aceite de `14360748`; o merge proactivo mantém ambos os fornecedores de linhas do relatório. A referência final servida passa a `9fda6d6e`.
A tentativa proactiva em `56c0c6a7` não foi activada: um teste dependia de um ficheiro de outputs existente apenas no QA local. L8 permaneceu em serviço. A correcção `9fda6d6e` torna esse teste portátil com um exemplar mínimo sintético da projecção pública da API, sem perfis, credenciais ou pilotos reais e sem escrita em outputs. O teste dirigido passou; o código da aplicação é byte a byte idêntico a `56c0c6a7`. Não se transportou a base QA nem se saltou a guarda do instalador. A nova tentativa usou o backup/restauro ainda fresco, com capacidade e fonte activa novamente conferidas.
A ligação SSH foi restabelecida pelo responsável na janela local, sem credenciais na conversa ou nos recibos. A medição inicial encontrou91,6GiB livres e inodes suficientes; a capacidade foi novamente conferida depois de cada backup. Instalador existente e suas guardas preservados; a versão anterior permaneceu activa até a nova release estar pronta. Os controlos automáticos do instalador foram mantidos, sem nova ronda manual das provas funcionais/económicas aceites.
**Backup/restauro fresco em cada etapa:** `/var/backups/investmoz-sequential-20261027/l8/backup` e `/var/backups/investmoz-sequential-20261027/proactive/backup`. Em cada uma, dump consistente e369ficheiros persistentes/configuração verificados; restauro das174tabelas num contentor sem rede, porta55441, com contagens/checksums iguais. Recibos `backup-receipt.json`, `restore-receipt.json`, `schema-permissions-before.json`, `schema-permissions-after.json`, `preservation-receipt.json` e `operational-delta-receipt.json` conservados nesses directórios. Hashes exactos no recibo consolidado.
**Preservação demonstrada:**172tabelas de negócio intactas em cada comparação; apenas cache/sessões operacionais reconciliados individualmente por identidade/timeouts e pedidos públicos de entrega. Schema, papéis, grants, permissões e originais persistentes conservados. Fontes instaladas comparadas aos commits:996ficheiros após L8 e1000após o proactivo. Sem migrations na base activa, importação de amostras QA, seeders ou publicação dos pilotos. O instalador manteve base e storage sintéticos isolados; o storage QA fica fora da árvore servida, e a release usa os mesmos `.env` e storage persistentes por ligação.
**Âmbito:** L8 continua parcial, com PEC e créditos de regra própria separados; os resultados continuam simulações. Songo permanece privado e pendente de respostas externas; Gurué continua hipótese agrícola privada. Disponibilização técnica não confirma clientes, procura, sustentabilidade ou publicação comercial. L3, ISPC, câmbio, L6/L7 e SGF TEMPO preservados.
Recibo consolidado: `docs/investmoz/unification/sequential-delivery-installed-20261027.json`. Provas locais: `outputs/l8-proactive-install-20261027/`. Os recibos históricos de preparação/suspensão mantêm-se como histórico e deixam de representar pendência de instalação destas duas candidatas.
Recibo remoto consolidado: `/var/backups/investmoz-sequential-20261027/installed-receipt.json`;SHA256 `62584b5abb50a05303a24379a0563e8dc147e25e682dc3566bb8edf015ba9d0b`. A fixture sintética portátil é apenas input de teste, sem importação na aplicação e sem dados dos pilotos.
## 27/10/2026 — avaliação de utilização pela equipa, sem Codex
**Estado:** roteiro preparado; execução real pela equipa e resultados ainda por observar. O recibo da instalação mantém `9fda6d6e` como referência entregue, incluindo L8 e o percurso proactivo. As provas técnicas aceites mantêm-se válidas. Este exercício avalia utilização e clareza; não constitui outra instalação, ronda de testes técnicos ou nova aprovação obrigatória da entrega.
### Exercício para a equipa
Usar a própria conta e o perfil operacional já autorizado no [portal](https://teste-investidor.tempo.co.mz/), pela interface normal. Escolher uma análise privada de trabalho sobre um tema real, com uma fonte já disponível e autorizada. Preservar Songo e Gurué, que aguardam informação comercial; não é necessário obter novas respostas externas para fazer este exercício. Não usar contas ou amostras QA na aplicação activa. O guia de botões existente em «Guia curto da equipa» pode ser consultado; registar essa consulta para distinguir clareza da interface de apoio documental.
1. **Preparar a análise.** Escolher sector e território existentes, identificar o assunto e guardar como preparação privada, usando apenas a informação conhecida.
2. **Registar evidências.** Identificar fonte/exemplar, trecho, período, abrangência e limitações. Separar facto documentado da interpretação. Associar um documento disponível quando aplicável; recuperar o original pelo gestor documental da ficha após o scan. A falta de resposta comercial permanece informação por confirmar.
3. **Estruturar a ideia.** Descrever a solução complementar, quem poderá beneficiar, quem poderá contratar/pagar, condições, recursos e próxima acção. Manter hipótese onde a procura não esteja demonstrada; montante, frequência e preço desconhecidos não passam a zero.
4. **Guardar e recuperar.** Sair da ficha e voltar a abri-la. Conferir que análise, evidências, documento associado e pendências são os que foram guardados, sem recorrer a scripts ou intervenção do Codex.
5. **Levar ao dossier.** Usar a continuação do investimento pela ficha. Escolher o dossier existente quando for o mesmo investimento; criar outro apenas para um investimento novo. Rever a prévia, conservar o título deliberado e confirmar. Reabrir o dossier e localizar a ideia, a origem e as pendências; o original continua acessível pelos recursos da ficha de origem, sem cópia automática para o dossier.
6. **Rever sem duplicar.** Actualizar uma pendência da própria análise com informação já conhecida e continuar o mesmo dossier. Conferir a nova versão após prévia/confirmação e a conservação da anterior. Guardar/confirmar não publica a análise, o anexo ou o dossier.
**O que observar:** se a pessoa encontra a próxima acção, compreende facto versus hipótese, consegue recuperar o que guardou e continuar o mesmo investimento sem ajuda do Codex. Anotar o que foi conseguido directamente, com o guia, com ajuda de outra pessoa, o que bloqueou e o que não foi tentado. Um impedimento concreto não obriga a repetir os passos já conseguidos; podem continuar os passos independentes.
### Devolução curta da avaliação
Registar por participante, sem enviar palavras-passe ou documentos privados nesta conversa: data e perfil utilizado; referências internas da análise e do dossier; passos conseguidos e tipo de apoio consultado; passo/campo onde surgiu dificuldade; mensagem exacta ou descrição do comportamento; resultado esperado. Distinguir acesso/perfil, linguagem/descoberta de acções, compreensão dos dados e perda ou erro de gravação/recuperação. Duração e sugestões são opcionais. Os identificadores só são partilhados no canal interno autorizado.
O coordenador devolve estes resultados pelo canal habitual da equipa. A avaliação só será marcada como observada depois dessa execução real; preparar o roteiro ou uma demonstração pelo Codex não a substitui. Nesta passagem não houve participante observado, análise criada no portal, alteração de conta/permissões, mensagem enviada à equipa ou publicação. As correcções seguintes serão delimitadas pelos obstáculos efectivamente relatados, sem reabrir provas aceites.
**Âmbitos preservados:** Songo e Gurué privados e pendentes de evidências comerciais. L8 permanece parcial; PEC e créditos com regras próprias continuam separados e não fazem parte deste exercício de utilização. O resultado técnico entregue não declara o IRPC completo nem valida comercialmente os pilotos.
Registo de preparação e resultados ainda em aberto: `docs/investmoz/unification/proactive-team-use-evaluation-20261027.json`. Não é um recibo de execução pela equipa.
## 27/10/2026 — L8: PEC pago no próprio exercício, incremento em QA
**Estado:** implementado e demonstrado em QA, ainda sem instalação. O portal mantém a entrega `9fda6d6e`, segundo o recibo anterior; esta passagem não acedeu ao servidor nem alterou `main`. A avaliação real da equipa sobre o percurso proactivo continua pendente de retorno; Songo e Gurué permanecem privados.
**Recorte:** residente no regime geral, ano civil 2026, MZN; colecta corrente válida L6/L7, créditos anteriores ausentes ou conhecidos zero, sem imposto autónomo positivo. PEC é pagamento efectivamente comprovado do próprio sujeito/exercício, não estimativa de tesouraria. Reutilizados o livro anual, o vínculo à colecta, os PPC, as retenções L5 e o mecanismo de gravação/recuperação/relatório existentes.
**Regra implementada:** CIRPC, art. 66(1–2), exemplar oficial Lei34/2007, PDF18/p768-(72), conferido visualmente. A dedução PEC é a menor entre as parcelas disponíveis comprovadas e a colecta disponível antes de retenções/PPC. A colecta após PEC não fica negativa. O excedente PEC é apresentado como parcela seleccionada não deduzida: **não constitui reembolso nem transporte oficial criado pelo simulador**. Retenções/PPC ainda podem originar saldo simulado a recuperar. Créditos precedentes positivos ou desconhecidos mantêm o caso indeterminado, sem ordem ou limite presumidos.
O detalhe PEC é uma extensão opcional versionada do snapshot anual. A acção explícita «Preparar detalhe PEC» reutiliza estado/suporte anteriores, conservando o resumo e os resultados históricos. Cada prova identifica emitente/documento, pagamento efectivo, NUIT, exercício/data, moeda, montante comprovado, utilizações anteriores documentadas e parcela seleccionada. Zero utilizado exige valor e suporte; vazio não vira zero. Ausência declarada, pagamento conhecido e informação em falta permanecem distintos. Contradições não são apagadas. A identidade física do comprovativo ignora mudanças de data e confere PEC/PPC/retenções neste e noutros contextos do mesmo snapshot; parcelas mais utilização anterior não podem ultrapassar o comprovado. Não há consulta/consumo de conta fiscal oficial nem deduplicação global entre dossiers independentes.
| Caso sintético novo | Efeito demonstrado |
| --- | --- |
| Colecta1 408; PEC200; PPC500; ausência de retenções | Dedução PEC200; colecta após PEC1 208; saldo simulado a pagar708 MZN. |
| Mesmo caso com retenção L5 efectivamente sofrida300 | Saldo simulado408 MZN; prova L5 reutilizada, sem alterar o cálculo L5. |
| Colecta1 408; PEC2 000; sem PPC/retenções | Dedução1 408; saldo zero; PEC592 não deduzido, sem reembolso PEC. |
| Mesmo PEC2 000 e PPC500 | Saldo simulado a recuperar500; PEC592 continua separado. |
| Prova PEC300; já utilizado100; parcela200; sem PPC/retenções | Saldo simulado a pagar1 208; utilizações anteriores não deduzidas outra vez. |
| Utilização anterior desconhecida, prova incompatível/duplicada ou crédito precedente positivo | Saldo indeterminado; subtotal conhecido não substitui os dados em falta. |
**Provas do delta:**12 testes novos PEC;19 testes do módulo anual directamente afectado preservados e aprovados. API privada:1 teste/102 asserções, cinco casos, base isolada `proactive_investment_20261027_test` em loopback55441 e transacção com rollback. Os cinco snapshots recuperados geraram HTML e dossier concordantes; histórico anterior conservado. Hashes dos registos existentes em sete tabelas conservaram55 oportunidades,64 documentos,1 vínculo documental,19 rascunhos,40 utilizadores,3 organizações e409 eventos anteriores. Não houve nova conta/grant, publicação ou importação de pilotos. Wayfinder pelo procedimento existente, TypeScript e build isolado aprovados. Interface PEC implementada; nesta passagem não se declara nova prova manual de utilização por browser/equipa. Não se repetiram suites independentes L3/ISPC/câmbio/L5–L7.30 PDFs do arquivo comparados byte a byte ao baseline `dc14f01e`, sem alterações; schema/configuração e módulos proactivos preservados.
### Saldo concreto do PEC e dependências de L8
| Código ainda por implementar | Exemplo / condição concreta de retoma |
| --- | --- |
| Cálculo da obrigação PEC e prestações | Distinguir volume anterior, PPC do ano anterior e PEC pago. Exemplo de domínio a desenvolver:volume10 000 000 ×0,5%=50 000, antes dos PPC anteriores. Reutilizar vendas/pagamentos só após reconciliação de entidade/exercício; aplicar limites/calendário da edição pertinente e representar dispensas/rectificações próprias. Nenhum vencimento/valor a pagar foi gerado neste incremento. |
| Transporte, ordem de utilização e caducidade de PEC de exercícios anteriores | Exemplo:PEC2025 ainda não deduzido no fecho2026. Implementar proveniência por ano, utilizações, remanescente e prazo; não aceitar esse saldo como PEC2026 nem criar crédito oficial a partir dos592 do exemplo. |
| Outros créditos, imposto autónomo, períodos especiais, outras moedas e transporte/submissão M20/M22 | Mantêm os grupos L8 anteriores, com condições e regras próprias; o PEC corrente independente não espera por esses casos. O mecanismo cambial existente será reutilizado quando corresponder a regra do pagamento. |
| Esclarecimento documental aguardado | Exemplo / condição concreta de retoma |
| --- | --- |
| Edição regulamentar após o anúncio governamental de alterações IRPC em2026 | Recuperar diploma publicado, artigos alterados e entrada em vigor para os calendários/obrigações afectados. O anúncio não substitui norma nem activa parâmetros novos. Não se reabrem as fontes aceites ou cálculos independentes do art66 já demonstrados. |
| Aplicação do prazo do art66 aos saldos anteriores e eventuais regras transitórias | Fixar para um PEC2025 as datas/último exercício elegível e documentação das utilizações; manter a regra PEC distinta do transporte de cinco exercícios do crédito por dupla tributação internacional do art65. Não presumir reembolso, expiração ou saldo oficial. |
| Crédito próprio específico positivo | Exemplo:imposto estrangeiro10 MZN exige rendimento/base/titular, imposto efectivamente pago, limite, convenção e período próprios antes de concorrer com PEC. Segue a dependência existente do crédito, não uma pesquisa geral de L5. |
Registo do incremento: `docs/investmoz/simulations/irpc-l8-pec-qa-20261027.json`; provas sintéticas locais em `outputs/irpc-l8-pec-20261027/`. **L8 permanece parcial.** Não há nova estimativa global de prazo nem declaração de IRPC integralmente concluído. Dificuldades da equipa serão tratadas como correcções concretas do percurso proactivo quando forem comunicadas.
File diff suppressed because one or more lines are too long
@@ -1,3 +1,4 @@
import {SimulationIrpcAnnual} from '@/components/simulation-irpc-annual';
import {SimulationIrpcNormal} from '@/components/simulation-irpc-normal';
import {SimulationIrpcWithholdings} from '@/components/simulation-irpc-withholdings';
import {SimulationIspcResiduals} from '@/components/simulation-ispc-residuals';
@@ -3513,6 +3514,7 @@ export function SimulationForm() {
{(current.id === 'financial' || current.id === 'tax') && <SimulationIspcResiduals draft={draft} onChange={change} />}
{(current.id === 'financial' || current.id === 'tax') && <SimulationIrpcWithholdings draft={draft} onChange={change} />}
{(current.id === 'financial' || current.id === 'tax') && <SimulationIrpcNormal draft={draft} onChange={change} />}
{(current.id === 'financial' || current.id === 'tax') && <SimulationIrpcAnnual draft={draft} onChange={change} />}
{(current.id === 'financial' || current.id === 'tax') && <SimulationMonthlyIva draft={draft} busy={isCalculating} onCalculate={runSimulation} onChange={change} />}
{current.id === 'financial' &&
(draft.detail_level === 'advanced' ||
@@ -0,0 +1,26 @@
import {SimulationIrpcPec} from './simulation-irpc-pec';
import {useState} from 'react';
import {annualBook,newAnnualBook,saveAnnualBook,reuseAnnualAssessment,annualAssessment,annualWithholdingOptions,reuseAnnualWithholding,newAnnualPpc,recordAnnual,annualReportRows,annualHtml,annualSource,type AnnualBook,type AnnualPpc} from '@/lib/irpc-annual-settlement';
type Props={draft:Record<string,unknown>;onChange:(field:string,value:string)=>void};
export function SimulationIrpcAnnual({draft,onChange}:Props){
const[error,setError]=useState('');if(draft.fiscal_component!=='irpc')return null;
try{
const b=annualBook(draft),save=(next:AnnualBook)=>{try{onChange('modelo_a_snapshot',saveAnnualBook(draft,next));setError('');}catch(e){setError(String(e));}};
if(!b)return<section aria-label="IRPC — L8 fecho anual" className="rounded border p-4"><h4>L8 — da colecta ao saldo anual simulado</h4><p>Reutiliza a colecta válida, retenções efectivamente sofridas por conta e PPC comprovados do próprio sujeito/exercício. PEC comprovado pode ser detalhado no próprio exercício; créditos com regras próprias permanecem separados.</p><button type="button" onClick={()=>{try{save(reuseAnnualAssessment(draft,newAnnualBook()));}catch(e){setError(String(e));}}}>Preparar saldo anual L8</button>{error&&<p role="alert">{error}</p>}</section>;
const patch=(p:Partial<AnnualBook>)=>save({...b,...p}),a=annualAssessment(draft),options=annualWithholdingOptions(draft);
const field=(key:'subjectNuit'|'year'|'reference'|'assessmentReference',label:string)=><label className="block">{label}<input aria-label={label} value={b[key]} onChange={e=>patch({[key]:e.target.value})}/></label>;
const group=(key:'withholdings'|'ppc',label:string)=><><label className="block">Estado — {label}<select aria-label={'Estado L8 — '+label} value={b[key].state} onChange={e=>patch({[key]:{...b[key],state:e.target.value as ''|'known'|'absent'}})}><option value="">Informação em falta</option><option value="known">Valores conhecidos — seleccionar comprovativos</option><option value="absent">Ausência declarada com suporte</option></select></label><label className="block">Suporte — {label}<input aria-label={'Suporte L8 — '+label} value={b[key].reference} onChange={e=>patch({[key]:{...b[key],reference:e.target.value}})}/></label></>;
return<section aria-label="IRPC — L8 fecho anual" className="space-y-3 rounded border p-4"><h4>L8 — colecta, abatimentos e saldo anual simulado</h4><p>A colecta acima é anterior aos abatimentos. Este saldo tem cálculo e histórico próprios; retenção entregue pela empresa por pagamento a terceiros não é retenção sofrida. O resultado continua simulado, sem submissão, pagamento ou reembolso automático.</p><p>{annualSource(b)}</p>{error&&<p role="alert">{error}</p>}
{field('subjectNuit','NUIT do sujeito do fecho L8')}{field('year','Exercício do fecho L8')}{field('reference','Suporte do fecho da entidade e exercício L8')}
<p>Colecta disponível:{a.colecta?a.colecta.numerator+'/'+a.colecta.denominator+' MZN':'Indeterminada'};origem:{a.kind==='special'?'L7 qualificado':'L6 normal'};NUIT:{a.subjectNuit||'Por identificar'};exercício:{a.year||'Por identificar'}.</p><button type="button" onClick={()=>{try{save(reuseAnnualAssessment(draft,b));}catch(e){setError(String(e));}}}>Reutilizar colecta corrente L6/L7</button>{field('assessmentReference','Suporte da colecta reutilizada L8')}
<fieldset className="space-y-2 rounded border p-3"><legend>Retenções efectivamente sofridas por conta</legend>{group('withholdings','Retenções sofridas')}
{options.length===0?<p>Não há afectações de comprovativosL5 neste contexto. Reutilize e reconcilie a retenção recebida emL5 ou declare ausência com suporte.</p>:options.map(o=><div key={o.rowId+'|'+o.paymentId} className="rounded border p-2"><p>{o.document||'Prova por identificar'};emitente:{o.issuer};data:{o.date};parcelaL5:{o.amount}MZN;{o.reason||'Retenção recebida/efectiva por conta reconciliada emL5.'}</p><button type="button" disabled={!o.ready||b.withholdings.rows.some(r=>r.rowId===o.rowId&&r.paymentId===o.paymentId)} onClick={()=>{try{save(reuseAnnualWithholding(draft,b,o.rowId,o.paymentId,crypto.randomUUID()));}catch(e){setError(String(e));}}}>Seleccionar prova L5 {o.document||o.paymentId}</button></div>)}
{b.withholdings.rows.map((r,index)=>{const change=(p:Partial<typeof r>)=>patch({withholdings:{...b.withholdings,rows:b.withholdings.rows.map(x=>x.id===r.id?{...x,...p}:x)}});return<fieldset key={r.id} className="rounded border p-2"><legend>Retenção seleccionada {index+1}</legend><p>Rendimento:{r.rowId};prova:{r.paymentId};NUIT:{r.subjectNuit};exercício:{r.year}. Fonte conservada. Se mudou, retire esta selecção e seleccione a prova actual. O histórico mantém-se.</p><label className="block">Parcela a abater<input aria-label={'Parcela da retenção L8 '+(index+1)} value={r.amount} onChange={e=>change({amount:e.target.value})}/></label><label className="block">O próprio sujeito é beneficiário e o rendimento está incluído na base deste exercício<select aria-label={'Rendimento incluído L8 '+(index+1)} value={r.incomeIncluded} onChange={e=>change({incomeIncluded:e.target.value as ''|'yes'|'no'})}><option value="">Informação em falta</option><option value="yes">Sim — documentado</option><option value="no">Não — crédito não aplicável neste fecho</option></select></label><label className="block">Suporte da titularidade e inclusão<input aria-label={'Suporte da retenção L8 '+(index+1)} value={r.reference} onChange={e=>change({reference:e.target.value})}/></label><button type="button" onClick={()=>patch({withholdings:{...b.withholdings,rows:b.withholdings.rows.filter(x=>x.id!==r.id)}})}>Retirar selecção L8 da retenção {index+1}</button></fieldset>;})}</fieldset>
<fieldset className="space-y-2 rounded border p-3"><legend>PPC efectivamente pagos</legend>{group('ppc','PPC efectuados')}<p>Regista comprovativos de pagamentos por conta; não calcula automaticamente a obrigação PPC nem usa pagamentos previstos no plano.</p><button type="button" onClick={()=>patch({ppc:{...b.ppc,rows:[...b.ppc.rows,{...newAnnualPpc(crypto.randomUUID()),subjectNuit:b.subjectNuit,year:b.year}]}})}>Registar comprovativo PPC</button>
{b.ppc.rows.map((r,index)=>{const change=(p:Partial<AnnualPpc>)=>patch({ppc:{...b.ppc,rows:b.ppc.rows.map(x=>x.id===r.id?{...x,...p}:x)}});return<fieldset key={r.id} className="rounded border p-2"><legend>PPC {index+1}</legend>{([['document','Comprovativo'],['issuer','Emitente'],['date','Data (AAAA-MM-DD)'],['subjectNuit','NUIT beneficiário'],['year','Exercício do comprovativo'],['currency','Moeda do comprovativo'],['proofAmount','Montante comprovado'],['amount','Parcela a abater'],['reference','Suporte do pagamento e afectação']]as const).map(([key,label])=><label key={key} className="block">{label}<input aria-label={'PPC L8 '+(index+1)+' — '+label} value={r[key]} onChange={e=>change({[key]:e.target.value})}/></label>)}<label className="block">Pagamento efectivamente comprovado<select aria-label={'PPC L8 '+(index+1)+' — Efectivo'} value={r.effective} onChange={e=>change({effective:e.target.value as ''|'yes'|'no'})}><option value="">Informação em falta</option><option value="yes">Sim — comprovativo reconciliado</option><option value="no">Não — apenas previsão/outro estado</option></select></label><button type="button" onClick={()=>patch({ppc:{...b.ppc,rows:b.ppc.rows.filter(x=>x.id!==r.id)}})}>Retirar PPC {index+1}</button></fieldset>;})}</fieldset>
<SimulationIrpcPec book={b} save={save}/>{([...(b.pecPayments?[]:[['pec','PEC']as const]),['credits','Créditos com regras próprias']as const]).map(([key,label])=><fieldset key={key} className="rounded border p-3"><legend>{label} — tratamento separado</legend><label className="block">Estado — {label}<select aria-label={'Estado L8 — '+label} value={b[key].state} onChange={e=>patch({[key]:{...b[key],state:e.target.value as ''|'known'|'absent'}})}><option value="">Informação em falta</option><option value="absent">Ausência declarada com suporte</option><option value="known">Valor conhecido — positivo exige regra própria</option></select></label>{(b[key].state==='known'||b[key].amount)&&<label className="block">Montante declarado<input aria-label={'Montante L8 — '+label} value={b[key].amount} onChange={e=>patch({[key]:{...b[key],amount:e.target.value}})}/></label>}<label className="block">Suporte<input aria-label={'Suporte L8 — '+label} value={b[key].reference} onChange={e=>patch({[key]:{...b[key],reference:e.target.value}})}/></label></fieldset>)}
<button type="button" onClick={()=>{try{save(recordAnnual(draft,b));}catch(e){setError(String(e));}}}>Calcular e guardar saldo anual L8</button><button type="button" onClick={()=>{try{const html=annualHtml(draft),url=URL.createObjectURL(new Blob([html],{type:'text/html;charset=utf-8'})),link=document.createElement('a');link.href=url;link.download='IRPC-L8-saldo-simulado.html';link.click();URL.revokeObjectURL(url);setError('');}catch(e){setError(String(e));}}}>Exportar saldo anual L8</button>
{annualReportRows(draft).map((r,n)=><p key={n}>{r[1]} — {r[2]} — {r[3]}</p>)}</section>;
}catch(e){return<p role="alert">PreparaçãoL8 não recuperável:{String(e)}. Originais e históricos conservados.</p>;}
}
@@ -0,0 +1,23 @@
import {newPecPayment, pecSource, type PecPayment} from '@/lib/irpc-pec';
import type {AnnualBook} from '@/lib/irpc-annual-settlement';
export function SimulationIrpcPec({book, save}: {book: AnnualBook; save: (book: AnnualBook) => void}) {
const detail = book.pecPayments;
if (!detail) return <fieldset className="rounded border p-3"><legend>PEC — comprovativos do próprio exercício</legend><p>O resumo anterior fica conservado. Preparar o detalhe permite reconciliar os pagamentos efectivos e deduzi-los até à colecta disponível, sem reembolso do excedente PEC.</p><button type="button" onClick={() => save({...book, pecPayments: {version: 1, state: book.pec.state, reference: book.pec.reference, rows: []}})}>Preparar detalhe PEC</button></fieldset>;
const update = (next: typeof detail) => save({...book, pecPayments: next});
return <fieldset className="space-y-2 rounded border p-3"><legend>PEC — pagamentos efectivamente comprovados</legend>
<p>{pecSource}</p><p>Identifique a natureza PEC no comprovativo. As utilizações anteriores exigem valor e suporte; zero conhecido é diferente de informação em falta. A parcela seleccionada não pode exceder o comprovado menos o já utilizado. Saldos de anos anteriores, cálculo da obrigação e créditos próprios permanecem separados.</p>
<label className="block">Estado dos PEC<select aria-label="Estado dos PEC comprovados L8" value={detail.state} onChange={e => update({...detail, state: e.target.value as typeof detail.state})}><option value="">Informação em falta</option><option value="known">Pagamentos conhecidos</option><option value="absent">Ausência declarada com suporte</option></select></label>
<label className="block">Suporte do inventário PEC<input aria-label="Suporte do inventário PEC L8" value={detail.reference} onChange={e => update({...detail, reference: e.target.value})}/></label>
<button type="button" onClick={() => update({...detail, state: 'known', rows: [...detail.rows, {...newPecPayment(crypto.randomUUID()), subjectNuit: book.subjectNuit, year: book.year}]})}>Registar comprovativo PEC</button>
{detail.rows.map((r, index) => {
const change = (p: Partial<PecPayment>) => update({...detail, rows: detail.rows.map(x => x.id === r.id ? {...x, ...p} : x)});
return <fieldset key={r.id} className="rounded border p-2"><legend>PEC {index + 1}</legend>
{([['document', 'Comprovativo PEC'], ['issuer', 'Emitente'], ['date', 'Data (AAAA-MM-DD)'], ['subjectNuit', 'NUIT beneficiário'], ['year', 'Exercício de origem'], ['currency', 'Moeda'], ['proofAmount', 'Montante comprovado'], ['previouslyUsed', 'Já utilizado fora destas parcelas'], ['priorUseReference', 'Suporte das utilizações anteriores ou do zero conhecido'], ['amount', 'Parcela disponível seleccionada'], ['reference', 'Suporte do pagamento PEC e afectação']] as const).map(([key, label]) => <label key={key} className="block">{label}<input aria-label={'PEC L8 ' + (index + 1) + ' — ' + label} value={r[key]} onChange={e => change({[key]: e.target.value})}/></label>)}
<label className="block">Pagamento PEC efectivamente comprovado<select aria-label={'PEC L8 ' + (index + 1) + ' — Efectivo'} value={r.effective} onChange={e => change({effective: e.target.value as PecPayment['effective']})}><option value="">Informação em falta</option><option value="yes">Sim — natureza PEC e pagamento reconciliados</option><option value="no">Não — previsão ou outra natureza</option></select></label>
<button type="button" onClick={() => update({...detail, rows: detail.rows.filter(x => x.id !== r.id)})}>Retirar selecção PEC {index + 1}</button>
</fieldset>;
})}
<p>O detalhe substitui o resumo PEC apenas nesta execução. Os comprovativos e resultados de execuções anteriores permanecem no histórico; não há consumo automático de saldos oficiais.</p>
</fieldset>;
}
+135
View File
@@ -0,0 +1,135 @@
import {validatePec,pecPaymentValue,pecDeduction,pecSource,type PecPayments} from './irpc-pec.ts';
import {normalBook,normalCurrent} from './irpc-normal.ts';
import {irpcBook,irpcCurrent} from './irpc-withholdings.ts';
import {acquisitionScope} from './iva-acquisitions.ts';
import {closureFingerprint} from './iva-closure.ts';
import {addFractions,subtractFractions,decimalFraction,fraction,fractionPresentation,type FiscalFraction} from './fiscal-rational.ts';
export const annualSettlementVersion='IRPC-annual-settlement/1';
export const annualSettlementSource='CIRPC, arts. 63 e 67 (Lei 34/2007 e natureza da retenção na redacção aplicável da Lei 12/2025); Regulamento, Decreto 9/2008, arts. 21(2–5) e 27(1–2/6). Recorte: 2026, residente no regime geral, ano civil e MZN. Colecta corrente válida, retenções efectivamente sofridas por conta e PPC comprovados. PEC/créditos positivos e tributação autónoma ficam fora deste fecho inicial. Art. 27(6): montante inferior a 100 MZN sem cobrança/reembolso; saldo aritmético exacto conservado. Saldo simulado por colecta projectada; não é declaração submetida, pagamento ou reembolso recebido.';
type State=''|'known'|'absent';
type Evidence={state:State;amount:string;reference:string};
type Group={state:State;reference:string};
export type AnnualWithholding={id:string;rowId:string;paymentId:string;sourceKey:string;subjectNuit:string;year:string;amount:string;incomeIncluded:''|'yes'|'no';reference:string};
export type AnnualPpc={id:string;document:string;issuer:string;date:string;subjectNuit:string;year:string;currency:string;proofAmount:string;amount:string;effective:''|'yes'|'no';reference:string};
type AnnualRecord={version:typeof annualSettlementVersion;key:string;createdAt:string;model:AnnualModel};
export type AnnualBook={version:1;subjectNuit:string;year:string;reference:string;assessment:''|'normal'|'special';assessmentKey:string;assessmentReference:string;withholdings:Group&{rows:AnnualWithholding[]};ppc:Group&{rows:AnnualPpc[]};pec:Evidence;pecPayments?:PecPayments;credits:Evidence;result?:AnnualRecord;history:AnnualRecord[]};
export const annualSource=(b:AnnualBook)=>b.pecPayments?annualSettlementSource.replace('PEC/créditos positivos','Créditos próprios positivos')+' '+pecSource:annualSettlementSource;
const evidence=():Evidence=>({state:'',amount:'',reference:''});
export const newAnnualBook=():AnnualBook=>({version:1,subjectNuit:'',year:'',reference:'',assessment:'',assessmentKey:'',assessmentReference:'',withholdings:{state:'',reference:'',rows:[]},ppc:{state:'',reference:'',rows:[]},pec:evidence(),credits:evidence(),history:[]});
export const newAnnualPpc=(id:string):AnnualPpc=>({id,document:'',issuer:'',date:'',subjectNuit:'',year:'',currency:'MZN',proofAmount:'',amount:'',effective:'',reference:''});
const zero=()=>fraction(0n),cmp=(a:FiscalFraction,b:FiscalFraction)=>BigInt(a.numerator)*BigInt(b.denominator)-BigInt(b.numerator)*BigInt(a.denominator);
const iso=(s:string)=>/^20\d{2}-\d{2}-\d{2}$/.test(s)&&Number.isFinite(Date.parse(s))&&new Date(s).toISOString().slice(0,10)===s;
const moneyInput=(s:string)=>{if(!/^\d{1,18}(\.\d{1,2})?$/.test(s))throw Error('MontanteMZN em falta/inválido;máximo dois decimais,sem zero presumido.');return decimalFraction(s);};
const canonical=(s:string)=>s.normalize('NFKC').trim().toLocaleLowerCase('pt').replace(/\s+/g,' ');
const proofIdentity=(issuer:string,document:string,_date:string)=>JSON.stringify([canonical(issuer),canonical(document)]);
function store(d:Record<string,unknown>){const s=JSON.parse(String(d.modelo_a_snapshot||'{"version":1,"books":{}}'));if(s.version!==1||!s.books||typeof s.books!=='object'||Array.isArray(s.books))throw Error('Livros fiscais não recuperáveis;originais conservados.');return s;}
function books(d:Record<string,unknown>):Record<string,AnnualBook>{const m=store(d).irpcAnnual;if(m===undefined)return{};if(!m||typeof m!=='object'||Array.isArray(m))throw Error('MapaL8 não recuperável;originais conservados.');return m;}
export function validateAnnual(b:AnnualBook){
if(b?.pecPayments!==undefined)validatePec(b.pecPayments);
if(!b||b.version!==1||['subjectNuit','year','reference','assessmentKey','assessmentReference'].some(k=>typeof b[k as 'year']!=='string')||!['','normal','special'].includes(b.assessment)||!Array.isArray(b.history))throw Error('PreparaçãoL8 não recuperável.');
for(const g of[b.withholdings,b.ppc,b.pec,b.credits])if(!g||!['','known','absent'].includes(g.state)||typeof g.reference!=='string')throw Error('EstadoL8 não recuperável.');
for(const g of[b.pec,b.credits])if(typeof g.amount!=='string')throw Error('CréditoL8 não recuperável.');
const w=['id','rowId','paymentId','sourceKey','subjectNuit','year','amount','incomeIncluded','reference'],p=Object.keys(newAnnualPpc(''));
for(const[rows,keys]of[[b.withholdings.rows,w],[b.ppc.rows,p]]as const)if(!Array.isArray(rows)||new Set(rows.map(r=>r?.id)).size!==rows.length||rows.some(r=>!r||keys.some(k=>typeof(r as unknown as Record<string,unknown>)[k]!=='string')))throw Error('ComprovativosL8 não recuperáveis ou identificador repetido.');
if(b.withholdings.rows.some(r=>!['','yes','no'].includes(r.incomeIncluded))||b.ppc.rows.some(r=>!['','yes','no'].includes(r.effective)))throw Error('QualificaçãoL8 não recuperável.');
for(const r of[b.result,...b.history])if(r&&(r.version!==annualSettlementVersion||typeof r.key!=='string'||typeof r.createdAt!=='string'||!r.model||!Array.isArray(r.model.pending)))throw Error('HistóricoL8 não recuperável.');
}
export function annualBook(d:Record<string,unknown>){const b=books(d)[acquisitionScope(d)];if(b)validateAnnual(b);return b;}
export function saveAnnualBook(d:Record<string,unknown>,b:AnnualBook){validateAnnual(b);return JSON.stringify({...store(d),irpcAnnual:{...books(d),[acquisitionScope(d)]:b}});}
export function annualAssessment(d:Record<string,unknown>){
const b=normalBook(d),r=b.result,m=r?.model;
return{book:b,record:r,current:normalCurrent(d,b),key:r?closureFingerprint(r):'',subjectNuit:b.base?.subjectNuit??'',year:b.year,period:m?.periodsFx?{from:m.periodsFx.input.from,to:m.periodsFx.input.to}:m?.fiscalPeriod??m?.assessment?.period??null,kind:b.special?'special' as const:'normal' as const,colecta:b.special?m?.special?.colecta??null:m?.colecta??null,autonomous:b.special?m?.special?.expenses.autonomousTax??null:zero()};
}
export function reuseAnnualAssessment(d:Record<string,unknown>,b:AnnualBook):AnnualBook{const a=annualAssessment(d);return{...b,subjectNuit:b.subjectNuit||a.subjectNuit,year:b.year||a.year,assessment:a.kind,assessmentKey:a.key,assessmentReference:b.assessmentReference||a.book.assessment?.reference||''};}
export function annualWithholdingOptions(d:Record<string,unknown>){
const b=irpcBook(d),current=irpcCurrent(d,b);return b.rows.flatMap(r=>r.allocations.map(a=>{
const p=b.payments.find(p=>p.id===a.paymentId),v=b.result?.rows.find(v=>v.id===r.id),issues:string[]=[];
if(!current||!b.result)issues.push('Recalcule e guardeL5 com as entradas actuais.');
if(r.direction!=='received'||r.origin!=='effective'||v?.direction!=='received'||v.status!=='calculated'||v.nature!=='on_account'||r.settlement!=='complete'||v.settled===null)issues.push('Apenas retenção recebida/efectiva por conta,calculada e reconciliada emL5;remessa por terceiros,definitiva ou projecção não é crédito próprio.');
if(!p||p.kind!=='withholding_proof'||p.currency!=='MZN'||r.currency!=='MZN'||!iso(p.date)||!p.reference.trim())issues.push('Comprovativo de retenção sofrida emMZN em falta ou fora do recorte.');
return{rowId:r.id,paymentId:a.paymentId,document:p?.reference??'',issuer:r.counterparty,date:p?.date??'',eventDate:v?.eventDate??'',year:v?.eventDate.slice(0,4)??'',amount:a.amount,proofAmount:p?.amount??'',identity:proofIdentity(r.counterparty,p?.reference??'',p?.date??''),key:closureFingerprint([r,v,p,a]),ready:!issues.length,reason:issues.join(' ')};
}));
}
export function reuseAnnualWithholding(d:Record<string,unknown>,b:AnnualBook,rowId:string,paymentId:string,id:string):AnnualBook{
const o=annualWithholdingOptions(d).find(o=>o.rowId===rowId&&o.paymentId===paymentId);if(!o)throw Error('ComprovativoL5 não encontrado;originais conservados.');
if(b.withholdings.rows.some(r=>r.rowId===rowId&&r.paymentId===paymentId))throw Error('Retenção/prova já seleccionada;altere a parcela existente sem duplicar.');
return{...b,withholdings:{...b.withholdings,rows:[...b.withholdings.rows,{id,rowId,paymentId,sourceKey:o.key,subjectNuit:b.subjectNuit,year:o.year,amount:o.amount,incomeIncluded:'',reference:''}]}};
}
function dependencies(d:Record<string,unknown>){let normal:unknown,L5:unknown;try{const a=annualAssessment(d);normal=[a.record,a.current];}catch(e){normal=String(e);}try{const b=irpcBook(d);L5=[b.rows,b.payments,b.result,irpcCurrent(d,b)];}catch(e){L5=String(e);}return[normal,L5,Object.entries(books(d)).filter(([k])=>k!==acquisitionScope(d)).map(([k,b])=>[k,b.subjectNuit,b.year,b.withholdings,b.ppc,...(b.pecPayments?[b.pecPayments]:[])])];}
function key(d:Record<string,unknown>,b:AnnualBook){const{result:_,history:__,...input}=b;return closureFingerprint([annualSettlementVersion,acquisitionScope(d),input,dependencies(d)]);}
export function annualCurrent(d:Record<string,unknown>,b:AnnualBook){return !!b.result&&b.result.key===key(d,b);}
export function calculateAnnual(d:Record<string,unknown>,b:AnnualBook){
validateAnnual(b);const{result:_result,history:_history,...input}=b;const pending:string[]=[],warn:string[]=[];let assessment:ReturnType<typeof annualAssessment>|null=null,colecta:FiscalFraction|null=null;let options:ReturnType<typeof annualWithholdingOptions>=[];
try{assessment=annualAssessment(d);const a=assessment,m=a.record?.model;
if(!a.record||!a.current||a.key!==b.assessmentKey||b.assessment!==a.kind)pending.push('Colecta de origem ausente,alterada ou não corrente;reutilize a execuçãoL6/L7 aplicável,não some nem contorne efeitosL7.');
if(!/^\d{9}$/.test(b.subjectNuit)||b.subjectNuit!==a.subjectNuit||b.year!=='2026'||b.year!==a.year||a.book.scope!=='resident_general'||m?.currency!=='MZN'||a.period?.from!=='2026-01-01'||a.period?.to!=='2026-12-31')pending.push('Entidade/NUIT,exercício ou âmbito fora do recorte residente/ano civil2026/MZN;períodos especiais permanecem separados.');
if(!b.reference.trim()||!b.assessmentReference.trim())pending.push('Falta suporte do fecho do sujeito/exercício e da colecta seleccionada.');
if(!a.colecta||cmp(a.colecta,zero())<0n)pending.push('Colecta aplicável indeterminada;uma parcelaL6 não substitui totalL7 pendente.');else colecta=structuredClone(a.colecta);
if(a.kind==='special'&&(!m?.special||!a.autonomous||cmp(a.autonomous,zero())!==0n))pending.push('Tributação autónoma positiva/indeterminada exige liquidação própria;este primeiro saldo não a ignora nem a compensa.');
}catch(e){pending.push('Origem da colecta não recuperável: '+String(e));}
try{options=annualWithholdingOptions(d);}catch(e){if(b.withholdings.state==='known'||b.withholdings.rows.length)pending.push('OrigemL5 não recuperável: '+String(e));}
const group=(g:Group,rows:unknown[],label:string)=>{if(!g.state||!g.reference.trim())pending.push(label+':identifique valor conhecido,ausência declarada ou informação em falta com suporte.');if(g.state==='absent'&&rows.length)pending.push(label+':ausência declarada contradiz parcelas presentes;conserve e reconcilie.');if(g.state==='known'&&!rows.length)pending.push(label+':não há comprovativos seleccionados;ausência exige declaração própria.');};
group(b.withholdings,b.withholdings.rows,'Retenções sofridas por conta');group(b.ppc,b.ppc.rows,'PPC efectuados');
try{if(b.withholdings.state==='absent'&&options.some(o=>o.ready&&o.year===b.year&&cmp(moneyInput(o.amount),zero())>0n))pending.push('Ausência de retenções sofridas contradiz provaL5 efectiva por conta no exercício;reconcilie sem a ignorar.');}catch(e){pending.push('Reconciliação da ausência de retenções: '+String(e));}
for(const[label,e]of[...(b.pecPayments?[]:[['PEC',b.pec]as const]),['Créditos com regras próprias',b.credits]as const]){try{if(!e.state||!e.reference.trim())throw Error('presença/ausência e suporte em falta');if(e.state==='absent'){if(e.amount.trim())throw Error('ausência contradiz montante preenchido');}else if(cmp(moneyInput(e.amount),zero())!==0n)throw Error('montante positivo fora deste recorte:corresponder ordem,limite e transporte próprios;sem abatimento ou reembolso automático');}catch(err){pending.push(label+': '+String(err));}}
const claims:Array<{id:string;kind:'withholding'|'ppc'|'pec';previouslyUsed?:FiscalFraction;identity:string;proofAmount:FiscalFraction|null;value:FiscalFraction|null;sourceKey:string;allocationAmount:FiscalFraction|null;document:string;issuer:string;date:string;subjectNuit:string;year:string;reason:string}>=[];
for(const r of b.withholdings.rows){const o=options.find(o=>o.rowId===r.rowId&&o.paymentId===r.paymentId),issues:string[]=[];let value:FiscalFraction|null=null,proofAmount:FiscalFraction|null=null;
try{if(!o||!o.ready||r.sourceKey!==o.key)throw Error(o?.reason||'provaL5 ausente ou alterada;reutilize sem duplicar');if(r.subjectNuit!==b.subjectNuit||r.year!==b.year||o.year!==b.year||!o.date.startsWith(b.year+'-'))throw Error('entidade/exercício da retenção não correspondem ao fecho');if(r.incomeIncluded!=='yes'||!r.reference.trim())throw Error('confirme o próprio beneficiário/NUIT e inclusão do rendimento na base do exercício com suporte');value=moneyInput(r.amount);proofAmount=moneyInput(o.proofAmount);if(cmp(value,moneyInput(o.amount))>0n)throw Error('parcela ultrapassa a retenção efectivamente comprovada e afectada emL5');if(b.withholdings.rows.filter(x=>x.rowId===r.rowId&&x.paymentId===r.paymentId).length!==1)throw Error('retenção/prova repetida;uma afectação por linhaL5');if(assessment?.record?.model.special?.cooperative.status==='calculated'&&cmp(value,zero())>0n)throw Error('cooperativa integralmente elegível declara ausência de rendimentos retidos;segregue o casoL7 antes do crédito anual');}catch(e){issues.push(String(e));value=null;}
claims.push({id:r.id,kind:'withholding',identity:o?.identity??'',proofAmount,value,sourceKey:r.sourceKey,allocationAmount:o&&value?moneyInput(o.amount):null,document:o?.document??r.paymentId,issuer:o?.issuer??'',date:o?.date??'',subjectNuit:r.subjectNuit,year:r.year,reason:issues.join(' ')});
}
for(const r of b.ppc.rows){const issues:string[]=[];let value:FiscalFraction|null=null,proofAmount:FiscalFraction|null=null;
try{if(!r.document.trim()||!r.issuer.trim()||!r.reference.trim()||r.effective!=='yes'||r.currency!=='MZN'||!iso(r.date)||!r.date.startsWith(b.year+'-')||r.subjectNuit!==b.subjectNuit||r.year!==b.year)throw Error('PPC exige comprovativo efectivo,MZN,data,entidade e exercício correspondentes;projecção/tesouraria não é pagamento');value=moneyInput(r.amount);proofAmount=moneyInput(r.proofAmount);if(cmp(value,proofAmount)>0n)throw Error('parcelaPPC ultrapassa o montante comprovado');}catch(e){issues.push(String(e));value=null;}
claims.push({id:r.id,kind:'ppc',identity:proofIdentity(r.issuer,r.document,r.date),proofAmount,value,sourceKey:'',allocationAmount:null,document:r.document,issuer:r.issuer,date:r.date,subjectNuit:r.subjectNuit,year:r.year,reason:issues.join(' ')});
}
if(b.pecPayments){group(b.pecPayments,b.pecPayments.rows,'PEC pagos no próprio exercício');for(const r of b.pecPayments.rows){let value:FiscalFraction|null=null,proofAmount:FiscalFraction|null=null,previouslyUsed:FiscalFraction|undefined;let reason='';try{({value,proofAmount,previouslyUsed}=pecPaymentValue(r,b.subjectNuit,b.year));}catch(e){reason=String(e);}claims.push({id:r.id,kind:'pec',identity:proofIdentity(r.issuer,r.document,r.date),value,proofAmount,previouslyUsed,sourceKey:'',allocationAmount:null,document:r.document,issuer:r.issuer,date:r.date,subjectNuit:r.subjectNuit,year:r.year,reason});}}
const elsewhere:Array<{identity:string;subjectNuit:string;year:string;value:FiscalFraction;proofAmount:FiscalFraction;sourceKey:string;kind:'ppc'|'pec'|'withholding';previouslyUsed?:FiscalFraction}>=[];
for(const[scope,other]of Object.entries(books(d))){if(scope===acquisitionScope(d))continue;try{validateAnnual(other);for(const r of other.pecPayments?.rows??[]){const p=pecPaymentValue(r,other.subjectNuit,other.year);elsewhere.push({identity:proofIdentity(r.issuer,r.document,r.date),subjectNuit:r.subjectNuit,year:r.year,...p,sourceKey:'',kind:'pec'});}for(const r of other.ppc.rows)elsewhere.push({identity:proofIdentity(r.issuer,r.document,r.date),subjectNuit:r.subjectNuit,year:r.year,value:moneyInput(r.amount),proofAmount:moneyInput(r.proofAmount),sourceKey:'',kind:'ppc'});for(const r of other.withholdings.rows){const source=(store(d).irpcWithholdings??{})[scope];const row=source?.rows?.find((x:{id:string})=>x.id===r.rowId),p=source?.payments?.find((x:{id:string})=>x.id===r.paymentId);if(row&&p)elsewhere.push({identity:proofIdentity(row.counterparty,p.reference,p.date),subjectNuit:r.subjectNuit,year:r.year,value:moneyInput(r.amount),proofAmount:moneyInput(p.amount),sourceKey:r.sourceKey,kind:'withholding'});}}catch(e){if(other?.subjectNuit===b.subjectNuit)pending.push('Outro mapa da mesma entidade não recuperável para conferir duplicações: '+scope+';'+String(e));}}
for(const c of claims){if(!c.value||!c.proofAmount)continue;const same=claims.filter(x=>x.identity===c.identity&&x.value),other=elsewhere.filter(x=>x.identity===c.identity);let issue='';
if(same.filter(x=>x.kind!=='withholding').length>1||new Set(same.map(x=>x.kind)).size>1)issue='Mesmo comprovativo repetido ou usado com naturezas diferentes (retenção/PPC/PEC);reconcilie sem dedução dupla.';
if(other.some(x=>x.subjectNuit!==b.subjectNuit||x.year!==b.year))issue='Mesmo comprovativo já associado a outra entidade/exercício;reconcilie a titularidade e a afectação.';
if([...same,...other].some(x=>x.proofAmount&&cmp(x.proofAmount,c.proofAmount!)!==0n)||cmp(addFractions([...same.flatMap(x=>x.value?[x.value]:[]),...other.map(x=>x.value)]),c.proofAmount)>0n)issue='Comprovativo utilizado além do montante disponível ou com montantes divergentes neste/outro mapa.';
if(c.kind==='pec'&&c.previouslyUsed){if(other.some(x=>x.kind!=='pec')||other.some(x=>!x.previouslyUsed||cmp(x.previouslyUsed,c.previouslyUsed!)!==0n)||cmp(addFractions([c.previouslyUsed,...same.flatMap(x=>x.value?[x.value]:[]),...other.map(x=>x.value)]),c.proofAmount)>0n)issue='PEC com utilização anterior divergente, natureza incompatível ou parcelas acima do saldo disponível.';}
if(other.some(x=>x.kind!==c.kind))issue='Comprovativo já afectado a outra natureza (retenção/PPC/PEC);sem dupla dedução.';
if(c.kind==='withholding'&&c.sourceKey&&c.allocationAmount&&cmp(addFractions([...same.filter(x=>x.sourceKey===c.sourceKey).flatMap(x=>x.value?[x.value]:[]),...other.filter(x=>x.sourceKey===c.sourceKey).map(x=>x.value)]),c.allocationAmount)>0n)issue='Mesma afectação L5 reutilizada além da parcela disponível, ainda que o comprovativo global seja maior.';
if(issue)c.reason=[c.reason,issue].filter(Boolean).join(' ');
}
for(const c of claims)if(c.reason)pending.push((c.document||c.id)+': '+c.reason);
const knownWithholdings=addFractions(claims.filter(c=>c.kind==='withholding'&&!c.reason&&c.value).map(c=>c.value!)),knownPpc=addFractions(claims.filter(c=>c.kind==='ppc'&&!c.reason&&c.value).map(c=>c.value!));
const ready=pending.length===0&&colecta!==null,pec=b.pecPayments?pecDeduction(addFractions(claims.filter(c=>c.kind==='pec'&&!c.reason&&c.value).map(c=>c.value!)),colecta,ready):null,arithmeticBalance=ready?subtractFractions(subtractFractions(pec?.afterPec??colecta!,knownWithholdings),knownPpc):null;
let payable:FiscalFraction|null=null,recoverable:FiscalFraction|null=null,belowMinimum:FiscalFraction|null=null;let status:'payable'|'recoverable'|'balanced'|'below_minimum'|'indeterminate'='indeterminate';
if(arithmeticBalance){const n=BigInt(arithmeticBalance.numerator),abs=fraction(n<0n?-n:n,BigInt(arithmeticBalance.denominator));payable=zero();recoverable=zero();belowMinimum=zero();if(!n)status='balanced';else if(cmp(abs,fraction(100n))<0n){status='below_minimum';belowMinimum=abs;warn.push('Art27(6):saldo inferior a100MZN,sem cobrança/reembolso neste recorte;aritmética conservada,não é transporte de crédito.');}else if(n>0n){status='payable';payable=abs;}else{status='recoverable';recoverable=abs;}}
return{version:annualSettlementVersion,input:structuredClone(input),subjectNuit:b.subjectNuit,year:b.year,assessment:assessment?.record?{key:b.assessmentKey,kind:b.assessment,version:assessment.record.model.version,createdAt:assessment.record.createdAt,colecta,period:assessment.period,origin:assessment.record.model.origin}:null,claims,pecDeduction:pec,knownWithholdings,knownPpc,arithmeticBalance,payable,recoverable,belowMinimum,status,pending:[...new Set(pending)],warnings:warn,source:annualSource(b),officialBalancesConsumed:false,submitted:false,refundReceived:false,limitations:[b.pecPayments?'L8 parcial:transporte/caducidade de PEC, cálculo da obrigação, créditos próprios positivos, tributação autónoma, períodos especiais e outras moedas separados. Excedente PEC não é reembolso nem saldo transportado oficialmente.':'L8 parcial:PEC e créditos positivos,tributação autónoma,períodos especiais e pagamentos noutra moeda exigem regras próprias.','PPC aqui é pagamento comprovado;não cálculo automático da obrigação ou calendário.','Retenção sofrida não é retenção entregue pela empresa por conta de terceiros.','Valores racionais exactos;camposM20/M22 e representação não presumidos.','Saldo simulado por colecta projectada;sem pagamento,submissão ou reembolso automático.']};
}
export type AnnualModel=ReturnType<typeof calculateAnnual>;
export function recordAnnual(d:Record<string,unknown>,b:AnnualBook,now=new Date().toISOString()):AnnualBook{return{...b,history:b.result?[...b.history,structuredClone(b.result)]:b.history,result:{version:annualSettlementVersion,key:key(d,b),createdAt:now,model:calculateAnnual(d,b)}};}
const show=(v:FiscalFraction|null)=>v?(fractionPresentation(v).approximate?'≈':'')+fractionPresentation(v).decimal+' MZN (exacto '+v.numerator+'/'+v.denominator+')':'Indeterminado';
const stateLabel=(s:State)=>s==='known'?'Valor conhecido':s==='absent'?'Ausência declarada':'Informação em falta';
export function annualReportRows(d:Record<string,unknown>):Array<[string,string,string,string]>{
try{
const b=annualBook(d),r=b?.result;if(!b||!r)return[];const m=r.model;
const status={payable:'A pagar',recoverable:'A recuperar',balanced:'Saldo zero',below_minimum:'Inferior ao mínimo de cobrança/reembolso',indeterminate:'Indeterminado'}[m.status];
return[
['IRPC — L8','Fecho anual — âmbito e origem',
'NUIT: '+m.subjectNuit+'; exercício: '+m.year+'; colecta: '+show(m.assessment?.colecta??null)+'; origem: '+(m.assessment?.kind==='special'?'L7 qualificado':'L6 normal')+'. '+(annualCurrent(d,b)?'Entradas correspondentes.':'Histórico; origem/entradas alteradas: recalcule o saldo corrente.')+' Saldo simulado, não liquidação submetida.',
m.input.reference+'; '+m.input.assessmentReference+'; '+m.source],
...m.claims.map(c=>[
'IRPC — L8',(c.kind==='withholding'?'Retenção sofrida':c.kind==='pec'?'PEC':'PPC')+' — '+(c.document||c.id),
'Entidade: '+c.subjectNuit+'; exercício: '+c.year+'; emitente: '+c.issuer+'; data: '+c.date+'; comprovado: '+show(c.proofAmount)+'; parcela: '+(c.reason?'Indeterminado':show(c.value))+'. '+(c.reason||'Reconciliada sem utilização duplicada.'),
c.kind==='withholding'?m.input.withholdings.reference+'; '+(m.input.withholdings.rows.find(r=>r.id===c.id)?.reference??''):c.kind==='pec'?(m.input.pecPayments?.reference??'')+'; '+(m.input.pecPayments?.rows.find(r=>r.id===c.id)?.reference??'')+'; utilizações anteriores: '+(m.input.pecPayments?.rows.find(r=>r.id===c.id)?.previouslyUsed??'')+' MZN; '+(m.input.pecPayments?.rows.find(r=>r.id===c.id)?.priorUseReference??''):m.input.ppc.reference+'; '+(m.input.ppc.rows.find(r=>r.id===c.id)?.reference??'')
]as[string,string,string,string]),
...(m.pecDeduction?[[
'IRPC — L8','PEC — dedução limitada à colecta',
'Estado: '+stateLabel(m.input.pecPayments?.state??'')+'; parcelas disponíveis: '+show(m.pecDeduction.available)+'; dedução: '+show(m.pecDeduction.deducted)+'; colecta após PEC, antes de retenções/PPC: '+show(m.pecDeduction.afterPec)+'; parcela seleccionada não deduzida: '+show(m.pecDeduction.remaining)+'. Excedente sem reembolso PEC; transporte/caducidade não automáticos. Subtotais não resolvem informação em falta.',
(m.input.pecPayments?.reference??'')+'; '+m.pecDeduction.source
]as[string,string,string,string]]:[]),
['IRPC — L8','Saldo anual simulado',
'Estado: '+status+'. Retenções conhecidas: '+show(m.knownWithholdings)+'; PPC conhecidos: '+show(m.knownPpc)+'; saldo aritmético: '+show(m.arithmeticBalance)+'; a pagar: '+show(m.payable)+'; a recuperar: '+show(m.recoverable)+'. '+m.pending.join(' | ')+' '+m.warnings.join(' '),m.source],
['IRPC — L8','Estados dos comprovativos',
'Retenções sofridas: '+stateLabel(m.input.withholdings.state)+'; PPC: '+stateLabel(m.input.ppc.state)+'. Subtotais conhecidos não substituem informação em falta.',m.input.withholdings.reference+'; '+m.input.ppc.reference],
['IRPC — L8','PEC e créditos separados',
(m.input.pecPayments?'Declaração PEC anterior conservada (substituída nesta execução pelo detalhe comprovado): ':'PEC: ')+stateLabel(m.input.pec.state)+'; montante declarado: '+(m.input.pec.amount||'Não preenchido')+'; créditos: '+stateLabel(m.input.credits.state)+'; montante declarado: '+(m.input.credits.amount||'Não preenchido')+'. Sem dedução, transporte ou reembolso presumidos. '+m.limitations.join(' '),m.input.pec.reference+'; '+m.input.credits.reference]
];
}catch(e){return[['IRPC — L8','Não recuperável',String(e),'Originais e históricos conservados.']];}
}
export function annualHtml(d:Record<string,unknown>){const b=annualBook(d);if(!b?.result||!annualCurrent(d,b))throw Error('Calcule e guardeL8 com as fontes actuais antes de exportar.');const esc=(s:string)=>s.replace(/[&<>"']/g,c=>({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;'}[c]!));return'<!doctype html><html lang="pt"><meta charset="utf-8"><title>IRPC — L8 saldo anual simulado</title><h1>IRPC — colecta e saldo anual simulado</h1><p>Não é declaração submetida,pagamento efectuado ou reembolso recebido.</p>'+annualReportRows(d).map(r=>'<section><h2>'+esc(r[1])+'</h2><p>'+esc(r[2])+'</p><small>'+esc(r[3])+'</small></section>').join('')+'</html>';}
+35
View File
@@ -0,0 +1,35 @@
import {subtractFractions, decimalFraction, type FiscalFraction} from './fiscal-rational.ts';
export const pecVersion = 'IRPC-PEC/1';
export const pecSource = 'CIRPC, art. 66(1–2), Lei 34/2007, exemplar BR52, p. 768-(72): dedução após créditos anteriores, até à colecta, sem reembolso do PEC. Recorte demonstrado: pagamento efectivo do próprio exercício 2026, residente geral, ano civil, MZN. Não calcula a obrigação PEC, transporte, caducidade ou consumo de saldos oficiais.';
export type PecPayment = {
id: string; document: string; issuer: string; date: string; subjectNuit: string;
year: string; currency: string; proofAmount: string; amount: string;
effective: '' | 'yes' | 'no'; reference: string;
previouslyUsed: string; priorUseReference: string;
};
export type PecPayments = {version: 1; state: '' | 'known' | 'absent'; reference: string; rows: PecPayment[]};
export const newPecPayment = (id: string): PecPayment => ({id, document: '', issuer: '', date: '', subjectNuit: '', year: '', currency: 'MZN', proofAmount: '', amount: '', effective: '', reference: '', previouslyUsed: '', priorUseReference: ''});
export function validatePec(p: PecPayments) {
const keys = Object.keys(newPecPayment(''));
if (!p || p.version !== 1 || !['', 'known', 'absent'].includes(p.state) || typeof p.reference !== 'string' || !Array.isArray(p.rows) || new Set(p.rows.map(r => r?.id)).size !== p.rows.length || p.rows.some(r => !r || keys.some(k => typeof (r as unknown as Record<string, unknown>)[k] !== 'string') || !['', 'yes', 'no'].includes(r.effective))) {
throw Error('Comprovativos PEC não recuperáveis; originais conservados.');
}
}
export const pecCompare = (a: FiscalFraction, b: FiscalFraction) => BigInt(a.numerator) * BigInt(b.denominator) - BigInt(b.numerator) * BigInt(a.denominator);
const money = (s: string) => {
if (!/^\d{1,18}(\.\d{1,2})?$/.test(s)) throw Error('Montante PEC em falta/inválido; declare zero explicitamente quando conhecido.');
return decimalFraction(s);
};
export function pecPaymentValue(r: PecPayment, subjectNuit: string, year: string) {
if (!r.id.trim() || !r.document.trim() || !r.issuer.trim() || !r.reference.trim() || !r.priorUseReference.trim() || r.effective !== 'yes' || r.currency !== 'MZN' || !/^20\d{2}-\d{2}-\d{2}$/.test(r.date) || !Number.isFinite(Date.parse(r.date)) || new Date(r.date).toISOString().slice(0, 10) !== r.date || !r.date.startsWith(year + '-') || r.subjectNuit !== subjectNuit || r.year !== year || year !== '2026') {
throw Error('PEC: exige prova efectiva, natureza PEC, titular, exercício 2026, data válida e MZN; saldos anteriores e previsões ficam separados.');
}
const proofAmount = money(r.proofAmount), value = money(r.amount), previouslyUsed = money(r.previouslyUsed);
if (pecCompare(previouslyUsed, proofAmount) > 0n || pecCompare(value, subtractFractions(proofAmount, previouslyUsed)) > 0n) throw Error('PEC: parcela e utilizações anteriores excedem o comprovativo disponível.');
return {proofAmount, value, previouslyUsed};
}
export function pecDeduction(available: FiscalFraction, colecta: FiscalFraction | null, ready: boolean) {
const deducted = ready && colecta ? (pecCompare(available, colecta) > 0n ? colecta : available) : null;
return {version: pecVersion, available, deducted, remaining: deducted ? subtractFractions(available, deducted) : null, afterPec: deducted && colecta ? subtractFractions(colecta, deducted) : null, source: pecSource, officialBalancesConsumed: false, carryCreated: false};
}
@@ -179,6 +179,7 @@ const rowSection: Record<string, DossierReportSectionId> = {
'IRPC — retenções': 'finance',
'IRPC normal — L6': 'finance',
'IRPC — L7': 'finance',
'IRPC — L8': 'finance',
Equipa: 'team',
'Necessidade de negócio': 'resources',
Financiamento: 'resources',
+2
View File
@@ -1,3 +1,4 @@
import {annualReportRows} from './irpc-annual-settlement.ts';
import {proactiveInvestmentRows} from './proactive-investment-report.ts';
import {normalReportRows} from './irpc-normal.ts';
import {irpcReportRows} from './irpc-withholdings.ts';
@@ -698,6 +699,7 @@ export function buildProjectDossierRows(
rows.push(...ispcResidualReportRows(draft));
rows.push(...irpcReportRows(draft));
rows.push(...normalReportRows(draft));
rows.push(...annualReportRows(draft));
rows.push(...fiscalCalculationGapReportRows(draft));
rows.push(...l3FormPreparationReportRows(draft));
const operationRows = salesReportRows(draft);
@@ -0,0 +1,56 @@
<?php
namespace Tests\Feature;
use App\Models\User;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
use Tests\TestCase;
final class IrpcAnnualSettlementDraftTest extends TestCase
{
use DatabaseTransactions;
public function test_annual_simulated_balances_round_trip_with_proofs_states_and_preserved_books(): void
{
$target=DB::selectOne('select current_database() as name,inet_server_port() as port');
$this->assertSame('simulator_fiscal_delta_20261021_test',$target->name);
$this->assertSame(55441,(int)$target->port);
config(['investor-path.enabled'=>true,'suitecrm.enabled'=>false]);
$this->actingAs(User::factory()->create(['email_verified_at'=>now()]));
$id=null;$etag=null;
foreach(['payable','recoverable','balanced','absent','missing','duplicate','pec']as$case){
$d=json_decode(file_get_contents(base_path('outputs/irpc-l8-settlement/'.$case.'.json')),true,flags:JSON_THROW_ON_ERROR);
$personal=['person_type'=>$d['person_type']];unset($d['person_type']);
if($id===null)$id=$this->postJson('/api/v1/simulation-drafts',['personal_snapshot'=>$personal,'economic_snapshot'=>$d],['Idempotency-Key'=>(string)Str::uuid()])->assertCreated()->json('data.id');
else $this->putJson('/api/v1/simulation-drafts/'.$id,['personal_snapshot'=>$personal,'economic_snapshot'=>$d],['If-Match'=>$etag])->assertOk();
$r=$this->getJson('/api/v1/simulation-drafts/'.$id)->assertOk();$etag=$r->headers->get('ETag');$back=$r->json('data.economic_snapshot');
$this->assertSame($d['modelo_a_snapshot'],$back['modelo_a_snapshot']);
$this->assertSame($d['business_plan_snapshot'],$back['business_plan_snapshot']);
$before=json_decode($d['modelo_a_snapshot'],true,flags:JSON_THROW_ON_ERROR);
$s=json_decode($back['modelo_a_snapshot'],true,flags:JSON_THROW_ON_ERROR);$scope=$d['context_opportunity'];
$b=$s['irpcAnnual'][$scope];$m=$b['result']['model'];
foreach(['irpcNormal','irpcWithholdings','books','currencyEvents','ispcQuarters']as$map)$this->assertSame($before[$map],$s[$map]);
$this->assertSame('IRPC-annual-settlement/1',$m['version']);
$this->assertSame('123456789',$m['subjectNuit']);$this->assertSame('2026',$m['year']);
$this->assertSame(['numerator'=>'1408','denominator'=>'1'],$m['assessment']['colecta']);
$this->assertFalse($m['officialBalancesConsumed']);$this->assertFalse($m['submitted']);$this->assertFalse($m['refundReceived']);
$this->assertSame('known',$m['input']['credits']['state']);$this->assertSame('0',$m['input']['credits']['amount']);
if(in_array($case,['missing','duplicate','pec'],true)){
$this->assertSame('indeterminate',$m['status']);$this->assertNotEmpty($m['pending']);
$this->assertNull($m['arithmeticBalance']);$this->assertNull($m['payable']);$this->assertNull($m['recoverable']);
if($case==='missing')$this->assertSame('',$m['input']['ppc']['rows'][0]['effective']);
if($case==='pec')$this->assertSame('10',$m['input']['pec']['amount']);
if($case==='duplicate')$this->assertCount(2,$m['input']['ppc']['rows']);
}else{
$this->assertEmpty($m['pending']);
$this->assertSame(['payable'=>'payable','recoverable'=>'recoverable','balanced'=>'balanced','absent'=>'payable'][$case],$m['status']);
$this->assertSame(['numerator'=>['payable'=>'608','recoverable'=>'-192','balanced'=>'0','absent'=>'1408'][$case],'denominator'=>'1'],$m['arithmeticBalance']);
$this->assertSame(['numerator'=>$case==='recoverable'?'192':'0','denominator'=>'1'],$m['recoverable']);
if($case==='absent'){$this->assertSame('absent',$m['input']['withholdings']['state']);$this->assertSame('absent',$m['input']['ppc']['state']);}
else{$this->assertSame('yes',$m['input']['withholdings']['rows'][0]['incomeIncluded']);$this->assertSame('yes',$m['input']['ppc']['rows'][0]['effective']);}
}
file_put_contents(base_path('outputs/irpc-l8-settlement/recovered-'.$case.'.json'),json_encode($back,JSON_THROW_ON_ERROR|JSON_UNESCAPED_UNICODE));
}
}
}
+65
View File
@@ -0,0 +1,65 @@
<?php
namespace Tests\Feature;
use App\Models\User;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
use Tests\TestCase;
final class IrpcPecDraftTest extends TestCase
{
use DatabaseTransactions;
public function test_pec_delta_round_trips_without_consuming_balances_or_changing_existing_records(): void
{
$target=DB::selectOne('select current_database() as name,inet_server_port() as port');
$this->assertSame('proactive_investment_20261027_test',$target->name);
$this->assertSame(55441,(int)$target->port);
$snapshot=static function(string $table): array {
return collect(DB::select('select id::text as id,md5(row_to_json(t)::text) as hash from public."'.$table.'" t order by id'))->pluck('hash','id')->all();
};
$protected=[];
foreach(['opportunities','documents','opportunity_documents','simulation_form_drafts','users','organizations','audit_events']as$table)$protected[$table]=$snapshot($table);
config(['investor-path.enabled'=>true,'suitecrm.enabled'=>false]);
$this->actingAs(User::findOrFail(1021)); // Existing synthetic QA operator; no new grants.
$base=json_decode(file_get_contents(base_path('tests/frontend/fixtures/irpc-assessment-preserved.json')),true,flags:JSON_THROW_ON_ERROR);
$fixture=json_decode(file_get_contents(base_path('tests/frontend/fixtures/irpc-pec-preserved.json')),true,flags:JSON_THROW_ON_ERROR);
$personal=['person_type'=>$base['person_type']];unset($base['person_type']);
$id=null;$etag=null;$previous=null;
foreach($fixture['cases']as$name=>$book){
$draft=$base;$store=json_decode($draft['modelo_a_snapshot'],true,flags:JSON_THROW_ON_ERROR);
if($previous!==null)$book['history']=[$previous];
$store['irpcAnnual'][$draft['context_opportunity']]=$book;
$draft['modelo_a_snapshot']=json_encode($store,JSON_THROW_ON_ERROR|JSON_UNESCAPED_UNICODE);
$payload=['personal_snapshot'=>$personal,'economic_snapshot'=>$draft];
if($id===null)$id=$this->postJson('/api/v1/simulation-drafts',$payload,['Idempotency-Key'=>(string)Str::uuid()])->assertCreated()->json('data.id');
else $this->putJson('/api/v1/simulation-drafts/'.$id,$payload,['If-Match'=>$etag])->assertOk();
$response=$this->getJson('/api/v1/simulation-drafts/'.$id)->assertOk();$etag=$response->headers->get('ETag');$back=$response->json('data.economic_snapshot');
$this->assertSame($draft['modelo_a_snapshot'],$back['modelo_a_snapshot']);
$this->assertSame($draft['business_plan_snapshot'],$back['business_plan_snapshot']);
$recovered=json_decode($back['modelo_a_snapshot'],true,flags:JSON_THROW_ON_ERROR);
foreach(['irpcNormal','irpcWithholdings','books','currencyEvents','ispcQuarters']as$map)$this->assertSame($store[$map],$recovered[$map]);
$saved=$recovered['irpcAnnual'][$draft['context_opportunity']];$m=$saved['result']['model'];
$this->assertSame($book,$saved);$this->assertSame('IRPC-PEC/1',$m['pecDeduction']['version']);
$this->assertFalse($m['officialBalancesConsumed']);$this->assertFalse($m['pecDeduction']['carryCreated']);
$this->assertSame(['numerator'=>'1408','denominator'=>'1'],$m['assessment']['colecta']);
if($name==='missing'){$this->assertSame('indeterminate',$m['status']);$this->assertNull($m['arithmeticBalance']);$this->assertNull($m['pecDeduction']['deducted']);}
else{
$expected=['payable'=>['payable','708','200','0'],'capped'=>['balanced','0','1408','592'],'recoverable'=>['recoverable','-500','1408','592'],'prior-use'=>['payable','1208','200','0']][$name];
$this->assertSame($expected[0],$m['status']);
foreach(['arithmeticBalance'=>1,'deducted'=>2,'remaining'=>3]as$field=>$index)$this->assertSame(['numerator'=>$expected[$index],'denominator'=>'1'],$field==='arithmeticBalance'?$m[$field]:$m['pecDeduction'][$field]);
}
if($previous!==null)$this->assertSame($previous,$saved['history'][0]);
$previous=$saved['result'];
if(getenv('INVESTMOZ_PEC_QA_OUTPUT')==='1')file_put_contents(base_path('outputs/irpc-l8-pec-20261027/recovered-'.$name.'.json'),json_encode($back,JSON_THROW_ON_ERROR|JSON_UNESCAPED_UNICODE));
}
$preserved=[];
foreach($protected as$table=>$before){
$after=$snapshot($table);
$this->assertSame($before,array_intersect_key($after,$before),'Existing records changed: '.$table);
$preserved[$table]=['existing_rows'=>count($before),'unchanged'=>true];
}
if(getenv('INVESTMOZ_PEC_QA_OUTPUT')==='1')file_put_contents(base_path('outputs/irpc-l8-pec-20261027/existing-records-preservation.json'),json_encode(['database'=>$target->name,'tables'=>$preserved,'transaction_rollback'=>true],JSON_THROW_ON_ERROR|JSON_PRETTY_PRINT));
}
}
File diff suppressed because one or more lines are too long
@@ -0,0 +1,19 @@
{
"fixture_notice": "Synthetic public projection of accepted API QA consumers;no profiles,real pilots,credentials,dossier or personal data. Test input only;never import into application data.",
"consumer_contexts": [
{
"prefill": {
"simulator": {
"context_applicability_snapshot": "{\"version\":1,\"consumer_opportunity\":\"opportunity:399\",\"opportunity_choices\":[{\"opportunity\":{\"key\":\"opportunity:399\",\"title\":\"SYNTHETIC QA — Cahora Bassa\",\"version\":2,\"analysis\":{\"proactive\":{\"need\":\"SYNTHETIC QA necessidade por verificar.\",\"basis\":\"Fixture pública sintética; não é evidência de procura local.\",\"group\":\"ideas\",\"stage\":\"Apoio — correspondência real por confirmar\",\"state\":\"hypothesis\",\"notice\":\"A ausência de registo não comprova ausência de oferta. Proximidade não comprova contrato, participação, energia acessível, terra disponível ou benefício fiscal. Necessidade confirmada não comprova viabilidade comercial; hipótese de fornecimento não é encomenda.\",\"version\":1,\"chain_id\":null,\"evidence\":[{\"id\":\"3587d2e4-7428-4cd7-994b-60607b20d7da\",\"scope\":\"Cahora Bassa — contexto piloto\",\"period\":\"Exercício2026 — cenário sintético\",\"source\":\"SYNTHETIC QA exemplar público fictício Cahora Bassa\",\"locator\":\"Fixture QA, linha1\",\"purpose\":\"local\",\"category\":\"infrastructure\",\"coverage\":\"Cobertura fictícia; informação real por confirmar\",\"statement\":\"SYNTHETIC QA: capacidade fictícia em Cahora Bassa; não é diagnóstico económico real.\",\"verified_on\":\"2026-10-27\"}],\"proposal\":\"SYNTHETIC QA solução em preparação.\",\"relations\":[],\"limitations\":\"Sem validação económica, contrato, terra ou energia garantidos.\",\"next_action\":\"Confirmar evidências reais antes de decidir.\",\"evidence_ids\":[\"3587d2e4-7428-4cd7-994b-60607b20d7da\"],\"economic_validation\":false,\"availability_confirmed\":false}}}}]}"
}
}
},
{
"prefill": {
"simulator": {
"context_applicability_snapshot": "{\"version\":1,\"consumer_opportunity\":\"opportunity:400\",\"opportunity_choices\":[{\"opportunity\":{\"key\":\"opportunity:400\",\"title\":\"SYNTHETIC QA — Gurué\",\"version\":2,\"analysis\":{\"proactive\":{\"need\":\"SYNTHETIC QA necessidade por verificar.\",\"basis\":\"Fixture pública sintética; não é evidência de procura local.\",\"group\":\"ideas\",\"stage\":\"Apoio — correspondência real por confirmar\",\"state\":\"hypothesis\",\"notice\":\"A ausência de registo não comprova ausência de oferta. Proximidade não comprova contrato, participação, energia acessível, terra disponível ou benefício fiscal. Necessidade confirmada não comprova viabilidade comercial; hipótese de fornecimento não é encomenda.\",\"version\":1,\"chain_id\":null,\"evidence\":[{\"id\":\"1421bb80-78c0-40c9-9de0-f45e18c5a093\",\"scope\":\"Gurué — contexto piloto\",\"period\":\"Exercício2026 — cenário sintético\",\"source\":\"SYNTHETIC QA exemplar público fictício Gurué\",\"locator\":\"Fixture QA, linha1\",\"purpose\":\"local\",\"category\":\"infrastructure\",\"coverage\":\"Cobertura fictícia; informação real por confirmar\",\"statement\":\"SYNTHETIC QA: capacidade fictícia em Gurué; não é diagnóstico económico real.\",\"verified_on\":\"2026-10-27\"}],\"proposal\":\"SYNTHETIC QA solução em preparação.\",\"relations\":[],\"limitations\":\"Sem validação económica, contrato, terra ou energia garantidos.\",\"next_action\":\"Confirmar evidências reais antes de decidir.\",\"evidence_ids\":[\"1421bb80-78c0-40c9-9de0-f45e18c5a093\"],\"economic_validation\":false,\"availability_confirmed\":false}}}}]}"
}
}
}
]
}
+25
View File
@@ -0,0 +1,25 @@
import {irpcBook,newIrpcRow,saveIrpcBook,recordIrpc} from '../../../resources/js/lib/irpc-withholdings.ts';
import fs from 'node:fs';
import {newPecPayment} from '../../../resources/js/lib/irpc-pec.ts';
import {newAnnualBook,newAnnualPpc,reuseAnnualAssessment,reuseAnnualWithholding} from '../../../resources/js/lib/irpc-annual-settlement.ts';
export function pecCase(amount='200',ppc='500',rf='0') {
const d=JSON.parse(fs.readFileSync(new URL('../fixtures/irpc-assessment-preserved.json',import.meta.url),'utf8'));
if(rf!=='0'){
const l5=irpcBook(d);
l5.rows.push({...newIrpcRow('pec-rf'),direction:'received',origin:'effective',counterparty:'QA AT',documentRef:'QA rendimento próprio 2026',base:String(Number(rf)*5),currency:'MZN',kind:'royalty',recipientIrpc:'yes',payerIrpc:'yes',residence:'resident',mozambique:'yes',qualificationRef:'QA royalties próprios incluídos no resultado anual',specialRelief:'none',eventsComplete:'yes',events:[{kind:'payment',date:'2026-10-02',reference:'QA rendimento primeiro evento'}],settlement:'complete',settlementRef:'QA retenção sofrida reconciliada',allocations:[{paymentId:'pec-rf-proof',amount:rf}],ordinary:{nonDigital:'yes',capitalType:'',rentOwnPropertyManagement:'',specialFacts:'no',capitalSeatAndManagement:'',reference:'QA royalties não digitais de residente'}});
l5.payments.push({id:'pec-rf-proof',kind:'withholding_proof',reference:'QA-RF-PEC-2026',date:'2026-10-02',amount:rf,currency:'MZN'});
d.modelo_a_snapshot=saveIrpcBook(d,recordIrpc(d,l5,'2026-10-27T15:00:00+02:00'));
}
let b=reuseAnnualAssessment(d,newAnnualBook());
b.reference='QA PEC: inventário completo da entidade/exercício';b.assessmentReference='QA colecta válida já demonstrada';
b.withholdings={state:'absent',reference:'QA sem retenções próprias neste caso',rows:[]};
b.ppc={state:ppc==='0'?'absent':'known',reference:'QA inventário de PPC efectivo',rows:ppc==='0'?[]:[{...newAnnualPpc('ppc'),document:'QA-PPC-PEC-2026',issuer:'QA AT',date:'2026-06-30',subjectNuit:b.subjectNuit,year:b.year,proofAmount:ppc,amount:ppc,effective:'yes',reference:'QA prova efectiva de natureza PPC'}]};
b.pec={state:'absent',amount:'',reference:'QA resumo anterior preservado'};
b.credits={state:'known',amount:'0',reference:'QA créditos precedentes conhecidos zero'};
b.pecPayments={version:1,state:'known',reference:'QA inventário de pagamentos PEC 2026',rows:[{...newPecPayment('pec'),document:'QA-PEC-2026',issuer:'QA AT',date:'2026-08-31',subjectNuit:b.subjectNuit,year:b.year,proofAmount:amount,amount,effective:'yes',previouslyUsed:'0',priorUseReference:'QA reconciliação: zero utilizações fora destas parcelas',reference:'QA comprovativo pago de natureza PEC'}]};
if(rf!=='0'){
b.withholdings.state='known';b=reuseAnnualWithholding(d,b,'pec-rf','pec-rf-proof','rf-claim');
Object.assign(b.withholdings.rows[0],{incomeIncluded:'yes',reference:'QA titular e rendimento incluído no exercício'});
}
return {d,b};
}
@@ -0,0 +1,105 @@
import test from 'node:test';
import assert from 'node:assert/strict';
import fs from 'node:fs';
import {normalBook,normalCurrent,saveNormalBook} from '../../resources/js/lib/irpc-normal.ts';
import {irpcBook,newIrpcRow,saveIrpcBook,recordIrpc} from '../../resources/js/lib/irpc-withholdings.ts';
import {annualBook,newAnnualBook,newAnnualPpc,saveAnnualBook,reuseAnnualAssessment,annualAssessment,annualWithholdingOptions,reuseAnnualWithholding,calculateAnnual,recordAnnual,annualCurrent,annualReportRows,annualHtml} from '../../resources/js/lib/irpc-annual-settlement.ts';
import {createProjectDossierReport} from '../../resources/js/lib/project-dossier-report.ts';
const read=n=>JSON.parse(fs.readFileSync(new URL('./fixtures/'+n,import.meta.url),'utf8'));
const val=v=>v?Number(v.numerator)/Number(v.denominator):null;
const now='2026-10-26T18:00:00+02:00';
const original=()=>read('irpc-assessment-preserved.json');
function acceptedL7(expense=false){const d=read('irpc-l7-preserved.json')[expense?'expense':'acceleration'];if(!expense){const f=read('irpc-l7-continuation-preserved.json');d.business_plan_snapshot=f.plan;d.modelo_a_snapshot=saveNormalBook(d,f.book);}return d;}
function setup(rf='300',ppc='500'){
const d=original(),l5=irpcBook(d);
if(rf!==null){
const row={...newIrpcRow('L8-received'),direction:'received',origin:'effective',counterparty:'QA pagador A',documentRef:'QA rendimento próprio 2026',base:String(Number(rf)*5),currency:'MZN',kind:'royalty',recipientIrpc:'yes',payerIrpc:'yes',residence:'resident',mozambique:'yes',qualificationRef:'QA royalties próprios incluídos no resultado anual',specialRelief:'none',eventsComplete:'yes',events:[{kind:'payment',date:'2026-10-02',reference:'QA rendimento e primeiro evento 2026'}],settlement:'complete',settlementRef:'QA retenção efectivamente sofrida e reconciliada',allocations:[{paymentId:'RF-L8',amount:rf}],ordinary:{nonDigital:'yes',capitalType:'',rentOwnPropertyManagement:'',specialFacts:'no',capitalSeatAndManagement:'',reference:'QA royalties não digitais de residente'}};
l5.rows.push(row);l5.payments.push({id:'RF-L8',kind:'withholding_proof',reference:'QA-RF-2026-1',date:'2026-10-02',amount:rf,currency:'MZN'});
d.modelo_a_snapshot=saveIrpcBook(d,recordIrpc(d,l5,now));
}
let b=reuseAnnualAssessment(d,newAnnualBook());b.reference='QA entidade123456789,exercício2026,declaração integral dos abatimentos';b.assessmentReference='QA colecta válida já demonstrada1408';
b.withholdings={state:rf===null?'absent':'known',reference:'QA inventário completo das retenções efectivamente sofridas por este sujeito no exercício',rows:[]};
b.ppc={state:ppc===null?'absent':'known',reference:'QA inventário completo dos PPC efectuados no exercício',rows:[]};
b.pec={state:'absent',amount:'',reference:'QA ausência de PEC'};b.credits={state:'known',amount:'0',reference:'QA créditos com regras próprias conhecidos zero'};
if(rf!==null){b=reuseAnnualWithholding(d,b,'L8-received','RF-L8','claim-rf');Object.assign(b.withholdings.rows[0],{incomeIncluded:'yes',reference:'QA próprio beneficiário NUIT123456789;rendimento incluído na base anual2026'});}
if(ppc!==null)b.ppc.rows.push({...newAnnualPpc('claim-ppc'),document:'QA-PPC-2026-1',issuer:'QA AT',date:'2026-06-30',subjectNuit:b.subjectNuit,year:b.year,proofAmount:ppc,amount:ppc,effective:'yes',reference:'QA recibo de PPC efectivo e afectação ao sujeito/exercício'});
return{d,b};
}
const model=(d,b)=>calculateAnnual(d,b);
const pending=(d,b)=>{const m=model(d,b);assert.equal(m.status,'indeterminate',m.pending.join(' | '));assert.equal(m.arithmeticBalance,null);assert.equal(m.payable,null);assert.equal(m.recoverable,null);return m;};
test('optional L8 leaves accepted assessment, other books and report rows untouched',()=>{
const d=original(),before=JSON.stringify(d),b=normalBook(d);assert.equal(normalCurrent(d,b),true);assert.equal(val(annualAssessment(d).colecta),1408);assert.equal(annualBook(d),undefined);assert.deepEqual(annualReportRows(d),[]);assert.equal(JSON.stringify(d),before);
const old=acceptedL7();assert.deepEqual(annualReportRows(old),[]);assert.equal(normalBook(old).result.model.version,'IRPC-normal-adjustments/13');
});
test('1408 minus actual received300 and provenPPC500 yields608 payable without consuming official balances',()=>{
const{d,b}=setup(),before=d.modelo_a_snapshot,m=model(d,b);assert.deepEqual(m.pending,[]);assert.equal(m.status,'payable');assert.equal(val(m.knownWithholdings),300);assert.equal(val(m.knownPpc),500);assert.equal(val(m.payable),608);assert.equal(val(m.recoverable),0);assert.equal(m.officialBalancesConsumed,false);assert.equal(m.submitted,false);assert.equal(d.modelo_a_snapshot,before);
});
test('1408 minus1000 and600 yields192 recoverable;408 and1000 balances exactly',()=>{
for(const[rf,ppc,status,balance]of[['1000','600','recoverable',-192],['408','1000','balanced',0]]){const{d,b}=setup(rf,ppc),m=model(d,b);assert.deepEqual(m.pending,[]);assert.equal(m.status,status);assert.equal(val(m.arithmeticBalance),balance);assert.equal(val(m.recoverable),balance<0?-balance:0);}
});
test('declared absence yields1408;known zero has its own proof and missing never becomes zero',()=>{
const{d,b}=setup(null,null);assert.equal(val(model(d,b).payable),1408);b.credits.state='';assert.match(pending(d,b).pending.join(' '),/Créditos/);b.credits={state:'absent',amount:'',reference:'QA ausência'};b.ppc.state='';assert.match(pending(d,b).pending.join(' '),/PPC/);
const zero=setup('0','0');assert.equal(val(model(zero.d,zero.b).payable),1408);assert.equal(model(zero.d,zero.b).input.withholdings.state,'known');
});
test('effective received L5 proof is required, not a projection,remittance or definitive withholding',()=>{
for(const patch of[{origin:'projected'},{direction:'paid'},{residence:'nonresident',permanentEstablishment:'no'}]){const{d,b}=setup(),l5=irpcBook(d);Object.assign(l5.rows.find(r=>r.id==='L8-received'),patch);d.modelo_a_snapshot=saveIrpcBook(d,recordIrpc(d,l5,now));const option=annualWithholdingOptions(d).find(o=>o.rowId==='L8-received');assert.equal(option.ready,false);pending(d,b);}
const{d,b}=setup(),l5=irpcBook(d);l5.payments.find(p=>p.id==='RF-L8').kind='remittance';d.modelo_a_snapshot=saveIrpcBook(d,recordIrpc(d,l5,now));pending(d,b);
});
test('beneficiary,income inclusion,proof date,entity,exercise and actualPPC are mandatory',()=>{
for(const change of[b=>b.withholdings.rows[0].incomeIncluded='',b=>b.withholdings.rows[0].reference='',b=>b.withholdings.rows[0].subjectNuit='999999999',b=>b.year='2025',b=>b.ppc.rows[0].subjectNuit='999999999',b=>b.ppc.rows[0].year='2025',b=>b.ppc.rows[0].currency='USD',b=>b.ppc.rows[0].date='2026-02-30',b=>b.ppc.rows[0].date='2027-01-01',b=>b.ppc.rows[0].effective='no',b=>b.ppc.rows[0].reference='',b=>b.reference='']){const{d,b}=setup();change(b);pending(d,b);}
});
test('selected current source and reusing collection never overwrite deliberate entity/year edits',()=>{
const{d,b}=setup();b.subjectNuit='999999999';b.year='2025';const next=reuseAnnualAssessment(d,b);assert.equal(next.subjectNuit,'999999999');assert.equal(next.year,'2025');pending(d,next);
const other=setup();other.b.assessmentKey='old-source';pending(other.d,other.b);
});
test('absence contradiction and incomplete group inventories are indeterminate,not assumed totals',()=>{
for(const change of[b=>{b.withholdings={state:'absent',reference:'QA ausência contraditória',rows:[]};},b=>b.ppc.rows=[],b=>b.ppc.state='absent',b=>b.withholdings.reference='']){const{d,b}=setup();change(b);pending(d,b);}
});
test('duplicate pair,duplicatePPC,overclaim and cross-kind physical proof cannot be deducted twice',()=>{
for(const change of[b=>b.withholdings.rows.push({...b.withholdings.rows[0],id:'duplicate'}),b=>b.ppc.rows.push({...b.ppc.rows[0],id:'duplicate'}),b=>b.withholdings.rows[0].amount='301',b=>b.ppc.rows[0].amount='501',b=>Object.assign(b.ppc.rows[0],{document:' QA-RF-2026-1 ',issuer:'QA pagador A',date:'2026-10-02',amount:'100',proofAmount:'300'})]){const{d,b}=setup();change(b);pending(d,b);}
const{d,b}=setup();assert.throws(()=>reuseAnnualWithholding(d,b,'L8-received','RF-L8','again'),/já seleccionada/);
});
test('partial proof allocations allowed only within its available amount across context maps',()=>{
const{d,b}=setup(null,'500');b.ppc.rows[0].amount='300';const other=structuredClone(b);other.ppc.rows[0].id='other';other.ppc.rows[0].amount='200';const s=JSON.parse(d.modelo_a_snapshot);s.irpcAnnual={'opportunity:other':other};d.modelo_a_snapshot=JSON.stringify(s);assert.equal(val(model(d,b).payable),1108);other.ppc.rows[0].amount='201';d.modelo_a_snapshot=JSON.stringify(s);pending(d,b);
other.ppc.rows[0].amount='100';other.ppc.rows[0].subjectNuit='999999999';d.modelo_a_snapshot=JSON.stringify(s);pending(d,b);
other.ppc.rows[0].subjectNuit=b.subjectNuit;other.ppc.rows[0].year='2025';d.modelo_a_snapshot=JSON.stringify(s);pending(d,b);
});
test('positive PEC or specialcredit stays separated with null final balances,explicitzero permitted',()=>{
for(const key of['pec','credits']){const{d,b}=setup();b[key]={state:'known',amount:'10',reference:'QA saldo positivo exige regra própria'};const m=pending(d,b);assert.match(m.pending.join(' '),/fora deste recorte/);assert.equal(val(m.knownPpc),500);b[key].amount='0';assert.equal(model(d,b).status,'payable');b[key]={state:'absent',amount:'0',reference:'QA ausência contradiz montante'};pending(d,b);}
});
test('changing receipt date cannot evade identity checks;copied L5 allocation cannot consume larger proof twice',()=>{
const p=setup();p.b.ppc.rows.push({...p.b.ppc.rows[0],id:'other-date',date:'2026-07-01',amount:'100'});pending(p.d,p.b);
const{d,b}=setup();const l5=irpcBook(d);l5.payments.find(p=>p.id==='RF-L8').amount='1000';d.modelo_a_snapshot=saveIrpcBook(d,recordIrpc(d,l5,now));b.withholdings.rows=[];const fresh=reuseAnnualWithholding(d,b,'L8-received','RF-L8','rf');Object.assign(fresh.withholdings.rows[0],{amount:'200',incomeIncluded:'yes',reference:'QA próprio beneficiário e rendimento incluído'});
const other=structuredClone(fresh);other.withholdings.rows[0].amount='101';other.ppc.rows=[];other.ppc.state='absent';const s=JSON.parse(d.modelo_a_snapshot);s.irpcAnnual={'opportunity:other':other};s.irpcWithholdings['opportunity:other']=structuredClone(l5);d.modelo_a_snapshot=JSON.stringify(s);d.modelo_a_snapshot=saveIrpcBook(d,recordIrpc(d,irpcBook(d),now));fresh.withholdings.rows[0].sourceKey=annualWithholdingOptions(d).find(o=>o.rowId==='L8-received').key;other.withholdings.rows[0].sourceKey=fresh.withholdings.rows[0].sourceKey;const current=JSON.parse(d.modelo_a_snapshot);current.irpcAnnual['opportunity:other']=other;d.modelo_a_snapshot=JSON.stringify(current);assert.match(pending(d,fresh).pending.join(' '),/Mesma afectação L5/);
other.withholdings.rows[0].amount='100';d.modelo_a_snapshot=JSON.stringify(current);assert.equal(model(d,fresh).status,'payable');
});
test('annual accepted L7 accelerated assessment is reused once rather than summed with L6',()=>{
const d=read('irpc-l7-preserved.json').acceleration,b=reuseAnnualAssessment(d,newAnnualBook());b.reference='QA entidade/exercício';b.assessmentReference='QA colecta L7';for(const key of['withholdings','ppc','pec','credits']){b[key].state='absent';b[key].reference='QA ausência declarada';}
const m=model(d,b);assert.deepEqual(m.pending,[]);assert.equal(m.assessment.kind,'special');assert.equal(val(m.payable),1996.8);assert.notEqual(val(m.payable),val(normalBook(d).result.model.colecta)+1996.8);
});
test('100 minimum is applied symmetrically;99.99 kept exact without invented rounding or carry',()=>{
for(const[ppc,status,balance]of[['1308.01','below_minimum',99.99],['1308','payable',100],['1507.99','below_minimum',-99.99],['1508','recoverable',-100]]){const{d,b}=setup(null,ppc),m=model(d,b);assert.equal(m.status,status);assert.equal(val(m.arithmeticBalance),balance);if(status==='below_minimum'){assert.deepEqual(m.belowMinimum,{numerator:'9999',denominator:'100'});assert.equal(val(m.payable),0);assert.equal(val(m.recoverable),0);}}
const{d,b}=setup();b.ppc.rows[0].amount='0.001';pending(d,b);
});
test('existing L7 source cannot be bypassed by choosing L6 and positiveautonomous/shortperiod remain scoped',()=>{
for(const expense of[false,true]){const d=acceptedL7(expense);let b=reuseAnnualAssessment(d,newAnnualBook());b.reference='QA fecho';b.assessmentReference='QA colecta';for(const key of['withholdings','ppc','pec','credits']){b[key].state='absent';b[key].reference='QA sem movimentos';}assert.equal(b.assessment,'special');let m=pending(d,b);if(!expense)assert.match(m.pending.join(' '),/períodos especiais/);if(expense)assert.match(m.pending.join(' '),/Tributação autónoma/);b.assessment='normal';assert.match(pending(d,b).pending.join(' '),/não corrente/);}
});
test('record/recover/recalculate appends history unchanged,preserves all old books/plan,no double deduction',()=>{
const{d,b}=setup(),before=JSON.parse(d.modelo_a_snapshot),plan=d.business_plan_snapshot;d.modelo_a_snapshot=saveAnnualBook(d,recordAnnual(d,b,now));const once=annualBook(d),old=structuredClone(once.result);assert.equal(annualCurrent(d,once),true);d.modelo_a_snapshot=saveAnnualBook(d,recordAnnual(d,once,now));const back=annualBook(JSON.parse(JSON.stringify(d)));assert.deepEqual(back.history,[old]);assert.equal(val(back.result.model.payable),608);assert.equal(d.business_plan_snapshot,plan);const snapshot=JSON.parse(d.modelo_a_snapshot);delete snapshot.irpcAnnual;assert.deepEqual(snapshot,before);
b.ppc.rows[0].amount='400';assert.equal(annualCurrent(d,b),false);
});
test('changed L5 or assessment invalidates current L8 while retaining historical report and references',()=>{
const{d,b}=setup();d.modelo_a_snapshot=saveAnnualBook(d,recordAnnual(d,b,now));const back=annualBook(d),old=structuredClone(back.result);back.reference='NEW reference';d.modelo_a_snapshot=saveAnnualBook(d,back);assert.equal(annualCurrent(d,back),false);assert.match(annualReportRows(d).flat().join(' '),/Histórico/);assert.doesNotMatch(annualReportRows(d).flat().join(' '),/NEW reference/);assert.throws(()=>annualHtml(d),/fontes actuais/);assert.deepEqual(back.result,old);
const n=normalBook(d);n.base.identityReference+=' changed';d.modelo_a_snapshot=saveNormalBook(d,n);assert.equal(annualCurrent(d,back),false);pending(d,back);
const changed=setup();changed.d.modelo_a_snapshot=saveAnnualBook(changed.d,recordAnnual(changed.d,changed.b,now));const saved=annualBook(changed.d),prior=structuredClone(saved.result);const l5=irpcBook(changed.d);l5.payments.find(p=>p.id==='RF-L8').reference+=' corrected';changed.d.modelo_a_snapshot=saveIrpcBook(changed.d,recordIrpc(changed.d,l5,now));assert.equal(annualCurrent(changed.d,saved),false);pending(changed.d,saved);assert.deepEqual(saved.result,prior);
});
test('malformed optionalbook never resets accepted books;report explicitly preserves missing states',()=>{
const{d,b}=setup();b.credits.state='';d.modelo_a_snapshot=saveAnnualBook(d,recordAnnual(d,b,now));assert.match(annualHtml(d),/Indeterminado/);assert.match(annualHtml(d),/Informação em falta/);assert.match(JSON.stringify(createProjectDossierReport(d,{selectedSections:new Set(['finance'])})),/Saldo anual simulado/);
const old=d.modelo_a_snapshot;b.ppc.rows.push({...b.ppc.rows[0]});assert.throws(()=>saveAnnualBook(d,b),/identificador repetido/);assert.equal(d.modelo_a_snapshot,old);
});
test('prepare only L8 delta cases for guarded API and report recovery',()=>{
const cases={payable:setup(),recoverable:setup('1000','600'),balanced:setup('408','1000'),absent:setup(null,null),missing:setup(),duplicate:setup(),pec:setup()};cases.missing.b.ppc.rows[0].effective='';cases.duplicate.b.ppc.rows.push({...cases.duplicate.b.ppc.rows[0],id:'duplicate'});cases.pec.b.pec={state:'known',amount:'10',reference:'QA PEC separado'};
fs.mkdirSync('outputs/irpc-l8-settlement',{recursive:true});for(const[name,{d,b}]of Object.entries(cases)){d.modelo_a_snapshot=saveAnnualBook(d,recordAnnual(d,b,now));fs.writeFileSync('outputs/irpc-l8-settlement/'+name+'.json',JSON.stringify(d));fs.writeFileSync('outputs/irpc-l8-settlement/'+name+'.html',annualHtml(d));}
const{d}=setup();fs.writeFileSync('outputs/irpc-l8-settlement/initial.json',JSON.stringify(d));
});
+67
View File
@@ -0,0 +1,67 @@
import {pecCase} from './helpers/irpc-pec-case.mjs';
import test from 'node:test';
import assert from 'node:assert/strict';
import {annualBook,newAnnualBook,newAnnualPpc,reuseAnnualAssessment,calculateAnnual,recordAnnual,saveAnnualBook,annualCurrent,annualReportRows,annualHtml} from '../../resources/js/lib/irpc-annual-settlement.ts';
import {createProjectDossierReport} from '../../resources/js/lib/project-dossier-report.ts';
const value=x=>x?Number(x.numerator)/Number(x.denominator):null;
const now='2026-10-27T15:00:00+02:00';
const model=({d,b})=>calculateAnnual(d,b);
const indeterminate=c=>{const m=model(c);assert.equal(m.status,'indeterminate',JSON.stringify(m.pending));assert.equal(m.arithmeticBalance,null);assert.equal(m.pecDeduction.deducted,null);assert.equal(m.pecDeduction.remaining,null);return m;};
test('PEC precedes PPC; 1408 - 200 - 500 = 708, no official consumption',()=>{
const m=model(pecCase());assert.deepEqual(m.pending,[]);assert.equal(value(m.pecDeduction.deducted),200);assert.equal(value(m.pecDeduction.afterPec),1208);assert.equal(value(m.payable),708);assert.equal(m.pecDeduction.carryCreated,false);assert.equal(m.officialBalancesConsumed,false);
});
test('existing received L5 proof is reused after PEC and cannot become another PEC receipt',()=>{
const c=pecCase('200','500','300');assert.equal(value(model(c).payable),408);
Object.assign(c.b.pecPayments.rows[0],{document:'QA-RF-PEC-2026',proofAmount:'300'});
assert.match(indeterminate(c).pending.join(' '),/natureza/);
});
test('PEC cap never generates refund; PPC can still generate recoverable balance',()=>{
const a=model(pecCase('2000','0'));assert.equal(value(a.pecDeduction.deducted),1408);assert.equal(value(a.pecDeduction.remaining),592);assert.equal(value(a.arithmeticBalance),0);assert.equal(value(a.recoverable),0);
const b=model(pecCase('2000','500'));assert.equal(value(b.recoverable),500);assert.equal(value(b.pecDeduction.remaining),592);assert.equal(value(b.pecDeduction.afterPec),0);
});
test('previous use explicit, precise decimals and available portion are respected',()=>{
const c=pecCase('200.25','0');Object.assign(c.b.pecPayments.rows[0],{proofAmount:'300.75',previouslyUsed:'100.50'});assert.equal(value(model(c).payable),1207.75);
c.b.pecPayments.rows[0].amount='200.26';indeterminate(c);
});
test('absence, known zero and missing PEC are distinct; contradictory rows block',()=>{
const c=pecCase();c.b.pecPayments.rows=[];c.b.pecPayments.state='absent';assert.equal(value(model(c).payable),908);
c.b.pecPayments.state='';indeterminate(c);c.b.pecPayments.state='known';indeterminate(c);
const z=pecCase('0');assert.equal(value(model(z).payable),908);z.b.pecPayments.rows[0].previouslyUsed='';indeterminate(z);
z.b.pecPayments.state='absent';indeterminate(z);
});
test('payment proof, unused balance, entity, year and currency cannot be presumed',()=>{
for(const change of[{effective:''},{effective:'no'},{document:''},{reference:''},{priorUseReference:''},{previouslyUsed:''},{previouslyUsed:'201'},{amount:'201'},{amount:'1.001'},{subjectNuit:'999999999'},{year:'2025'},{date:'2025-08-31'},{date:'2026-02-30'},{currency:'USD'}]){const c=pecCase();Object.assign(c.b.pecPayments.rows[0],change);indeterminate(c);}
});
test('same physical proof cannot be duplicated, re-dated or relabelled PPC',()=>{
const a=pecCase();a.b.pecPayments.rows.push({...a.b.pecPayments.rows[0],id:'copy',date:'2026-09-01'});assert.match(indeterminate(a).pending.join(' '),/repetido|saldo disponível/);
const b=pecCase();Object.assign(b.b.pecPayments.rows[0],{document:b.b.ppc.rows[0].document,proofAmount:'500'});assert.match(indeterminate(b).pending.join(' '),/naturezas|natureza incompatível/);
});
test('cross-context allocations respect prior use and changing external claims invalidates current result',()=>{
const c=pecCase('100','0'),r=c.b.pecPayments.rows[0];r.proofAmount='500';r.previouslyUsed='100';
const other=structuredClone(c.b);other.pecPayments.rows[0].amount='300';
const s=JSON.parse(c.d.modelo_a_snapshot);s.irpcAnnual={'opportunity:other':other};c.d.modelo_a_snapshot=JSON.stringify(s);
c.d.modelo_a_snapshot=saveAnnualBook(c.d,recordAnnual(c.d,c.b,now));const saved=annualBook(c.d);assert.equal(annualCurrent(c.d,saved),true);assert.equal(value(saved.result.model.payable),1308);
const edit=JSON.parse(c.d.modelo_a_snapshot);edit.irpcAnnual['opportunity:other'].pecPayments.rows[0].amount='301';c.d.modelo_a_snapshot=JSON.stringify(edit);assert.equal(annualCurrent(c.d,saved),false);assert.match(indeterminate({...c,b:saved}).pending.join(' '),/saldo disponível/);
edit.irpcAnnual['opportunity:other'].pecPayments.rows[0].amount='100';edit.irpcAnnual['opportunity:other'].pecPayments.rows[0].previouslyUsed='0';c.d.modelo_a_snapshot=JSON.stringify(edit);indeterminate({...c,b:saved});
});
test('other contexts cannot change PEC titular, origin or payment nature',()=>{
for(const change of[{subjectNuit:'999999999'},{year:'2025'}]){const c=pecCase('100','0'),other=structuredClone(c.b);other.pecPayments.rows[0].proofAmount='500';Object.assign(other.pecPayments.rows[0],change);const s=JSON.parse(c.d.modelo_a_snapshot);s.irpcAnnual={'opportunity:other':other};c.d.modelo_a_snapshot=JSON.stringify(s);indeterminate(c);}
const c=pecCase('100','0'),other=structuredClone(c.b);other.ppc.rows=[{...c.b.pecPayments.rows[0],amount:'50',proofAmount:'100'}];other.ppc.state='known';other.pecPayments.rows=[];other.pecPayments.state='absent';const s=JSON.parse(c.d.modelo_a_snapshot);s.irpcAnnual={'opportunity:other':other};c.d.modelo_a_snapshot=JSON.stringify(s);indeterminate(c);
});
test('positive special credits remain scoped and cannot be silently skipped before PEC',()=>{
const c=pecCase();c.b.credits.amount='10';assert.match(indeterminate(c).pending.join(' '),/Créditos/);assert.equal(value(model(c).pecDeduction.available),200);
});
test('save/recover/recalculate preserves old annual results and all other fiscal books, plan and reports',()=>{
const c=pecCase(),before=JSON.parse(c.d.modelo_a_snapshot),plan=c.d.business_plan_snapshot;
const legacy=structuredClone(c.b);delete legacy.pecPayments;c.d.modelo_a_snapshot=saveAnnualBook(c.d,recordAnnual(c.d,legacy,now));const old=structuredClone(annualBook(c.d).result);
c.b={...annualBook(c.d),pecPayments:c.b.pecPayments};c.d.modelo_a_snapshot=saveAnnualBook(c.d,recordAnnual(c.d,c.b,now));const back=annualBook(JSON.parse(JSON.stringify(c.d)));
assert.deepEqual(back.history,[old]);assert.equal(value(back.result.model.payable),708);assert.equal(annualCurrent(c.d,back),true);const after=JSON.parse(c.d.modelo_a_snapshot);delete after.irpcAnnual;assert.deepEqual(after,before);assert.equal(c.d.business_plan_snapshot,plan);
const html=annualHtml(c.d);assert.match(html,/PEC — dedução limitada/);assert.match(html,/708.00/);assert.match(html,/sem reembolso PEC/);
const dossier=createProjectDossierReport(c.d,{selectedSections:new Set(['finance'])});assert.match(JSON.stringify(dossier),/PEC — dedução limitada/);
const frozen=structuredClone(back.result);back.pecPayments.rows[0].amount='100';c.d.modelo_a_snapshot=saveAnnualBook(c.d,back);assert.equal(annualCurrent(c.d,back),false);assert.deepEqual(back.result,frozen);assert.match(annualReportRows(c.d).flat().join(' '),/Histórico/);assert.throws(()=>annualHtml(c.d),/fontes actuais/);
});
test('malformed PEC extension never replaces legacy snapshots',()=>{
const c=pecCase(),original=c.d.modelo_a_snapshot;c.b.pecPayments.rows[0].previouslyUsed=null;assert.throws(()=>saveAnnualBook(c.d,c.b),/não recuperáveis/);assert.equal(c.d.modelo_a_snapshot,original);
});
+1 -1
View File
@@ -6,7 +6,7 @@ test('absent proactivity is a no-op for accepted dossiers',()=>{assert.deepEqual
test('each idea retains origin,source,need,limits without summing or inventing economic values',()=>{const choices=[{opportunity:source(1,'A')},{opportunity:source(2,'B')}],d={context_applicability_snapshot:JSON.stringify({version:1,opportunity_choices:choices})},r=proactiveInvestmentRows(d);assert.equal(r.filter(x=>x[1]==='Origem da análise e ideia').length,2);assert.match(JSON.stringify(r),/opportunity:1/);assert.match(JSON.stringify(r),/opportunity:2/);assert.match(JSON.stringify(r),/Hipótese analítica/);assert.match(JSON.stringify(r),/não é zero/);assert.equal(d.context_applicability_snapshot,JSON.stringify({version:1,opportunity_choices:choices}));});
test('consumer selection only reports its idea even when other source contexts are present',()=>{const choices=[{opportunity:source(1,'A')},{opportunity:source(2,'B')}],r=proactiveInvestmentRows({context_opportunity:'opportunity:2',context_applicability_snapshot:JSON.stringify({version:1,opportunity_choices:choices})});assert.doesNotMatch(JSON.stringify(r),/opportunity:1/);assert.match(JSON.stringify(r),/opportunity:2/);});
test('explicit consumer snapshot is retained and repeat references do not duplicate report rows',()=>{const a=source(1,'A');let r=proactiveInvestmentRows({context_opportunity_snapshot:JSON.stringify({choice:{opportunity:a}})});assert.equal(r.filter(x=>x[1]==='Origem da análise e ideia').length,1);r=proactiveInvestmentRows({context_applicability_snapshot:JSON.stringify({version:1,opportunity_choices:[{opportunity:a},{opportunity:a}]})});assert.equal(r.filter(x=>x[1]==='Origem da análise e ideia').length,1);});
test('new API-recovered multi idea snapshot produces an independently scoped report',()=>{const d=JSON.parse(fs.readFileSync('outputs/proactive-investment-20261027/recovered-context.json','utf8'));const r=d.consumer_contexts.flatMap(c=>proactiveInvestmentRows(c.prefill.simulator));assert.equal(r.filter(x=>x[1]==='Origem da análise e ideia').length,2);assert.doesNotMatch(JSON.stringify(r),/PRIVATE-QA-/);fs.writeFileSync('outputs/proactive-investment-20261027/recovered-report-rows.json',JSON.stringify(r,null,2));});
test('portable API consumer snapshot produces an independently scoped report',()=>{const d=JSON.parse(fs.readFileSync(new URL('./fixtures/proactive-api-consumers.json',import.meta.url),'utf8'));const before=JSON.stringify(d);const perConsumer=d.consumer_contexts.map(c=>proactiveInvestmentRows(c.prefill.simulator));for(const rows of perConsumer)assert.equal(rows.filter(x=>x[1]==='Origem da análise e ideia').length,1);const r=perConsumer.flat();assert.equal(r.filter(x=>x[1]==='Origem da análise e ideia').length,2);assert.match(JSON.stringify(perConsumer[0]),/opportunity:399/);assert.doesNotMatch(JSON.stringify(perConsumer[0]),/opportunity:400/);assert.match(JSON.stringify(perConsumer[1]),/opportunity:400/);assert.doesNotMatch(JSON.stringify(perConsumer[1]),/opportunity:399/);assert.doesNotMatch(JSON.stringify(r),/PRIVATE-QA-/);assert.equal(JSON.stringify(d),before);});
test('resources,assumptions and selected relationships are retained in the existing dossier report',()=>{const a=source(7,'A');Object.assign(a.analysis.proactive,{resources:'QA recurso declarado',assumptions:'QA pressuposto explícito',conditions:'QA condição',relations:[{kind:'project',target_id:'QA-reference',label:'QA projecto existente',relationship:'hypothesis',basis:'QA fundamento público'}]});const draft={context_applicability_snapshot:JSON.stringify({version:1,opportunity_choices:[{opportunity:a}]})},rows=buildProjectDossierRows(draft);assert.match(JSON.stringify(rows),/QA pressuposto explícito/);assert.match(JSON.stringify(rows),/QA projecto existente/);assert.match(JSON.stringify(rows),/sem contrato, acesso ou participação presumidos/);});
+21
View File
@@ -0,0 +1,21 @@
<?php
$root=dirname(__DIR__);
$operation=$argv[1]??'';
if(!in_array($operation,['routes','test'],true)||basename($root)!=='portal-investidor-irpc-l7-common-qa-20261026')throw new RuntimeException('Explicit isolated QA workspace and routes/test operation required.');
foreach(['storage/framework/views','storage/framework/cache','storage/framework/sessions','bootstrap/cache','storage/logs','outputs/irpc-l8-settlement']as$dir)if(!is_dir($root.'/'.$dir))mkdir($root.'/'.$dir,0700,true);
foreach(['APP_BASE_PATH'=>$root,'APP_ENV'=>'testing','APP_KEY'=>'base64:'.base64_encode(str_repeat('Q',32)),'DB_CONNECTION'=>'pgsql','DB_HOST'=>'127.0.0.1','DB_PORT'=>'55441','DB_DATABASE'=>'simulator_fiscal_delta_20261021_test','DB_USERNAME'=>'postgres','DB_PASSWORD'=>'','DB_URL'=>'','CACHE_STORE'=>'array','SESSION_DRIVER'=>'array','QUEUE_CONNECTION'=>'sync','MAIL_MAILER'=>'array'] as $k=>$v){putenv($k.'='.$v);$_ENV[$k]=$_SERVER[$k]=$v;}
$loader=require $root.'/vendor/autoload.php';
spl_autoload_register(function($class)use($root){foreach(['App\\'=>'app/','Tests\\'=>'tests/','Database\\Factories\\'=>'database/factories/']as$prefix=>$dir){if(str_starts_with($class,$prefix)){$file=$root.'/'.$dir.str_replace('\\','/',substr($class,strlen($prefix))).'.php';if(is_file($file)){require $file;return;}}}},true,true);
$app=require $root.'/bootstrap/app.php';
(new Illuminate\Foundation\Bootstrap\LoadEnvironmentVariables)->bootstrap($app);
(new Illuminate\Foundation\Bootstrap\LoadConfiguration)->bootstrap($app);
$c=config('database.connections.pgsql');
if($app->configurationIsCached()||$c['host']!=='127.0.0.1'||(int)$c['port']!==55441||$c['database']!=='simulator_fiscal_delta_20261021_test'||!empty($c['url']))throw new RuntimeException('QA guard');
$pdo=new PDO('pgsql:host=127.0.0.1;port=55441;dbname='.$c['database'],$c['username'],$c['password']);
if($pdo->query('select current_database()')->fetchColumn()!==$c['database'])throw new RuntimeException('QA identity');
if($operation==='routes'){
$app->make(Illuminate\Contracts\Console\Kernel::class)->bootstrap();
$status=Illuminate\Support\Facades\Artisan::call('wayfinder:generate',['--with-form'=>true]);
echo Illuminate\Support\Facades\Artisan::output();exit($status);
}
$argv=['phpunit','-c','phpunit.investmoz.xml','tests/Feature/IrpcAnnualSettlementDraftTest.php'];$argc=count($argv);$_SERVER['argv']=$argv;$_SERVER['argc']=$argc;require $root.'/vendor/phpunit/phpunit/phpunit';
+15
View File
@@ -0,0 +1,15 @@
<?php
$root=dirname(__DIR__);$operation=$argv[1]??'';
if(!in_array($operation,['routes','test'],true)||basename($root)!=='portal-investidor-sequential-delivery-20261027')throw new RuntimeException('Explicit PEC QA workspace and routes/test operation required.');
foreach(['storage/framework/views','storage/framework/cache','storage/framework/sessions','bootstrap/cache','storage/logs','outputs/irpc-l8-pec-20261027']as$dir)if(!is_dir($root.'/'.$dir))mkdir($root.'/'.$dir,0700,true);
foreach(['APP_BASE_PATH'=>$root,'APP_ENV'=>'testing','APP_KEY'=>'base64:'.base64_encode(str_repeat('Q',32)),'DB_CONNECTION'=>'pgsql','DB_HOST'=>'127.0.0.1','DB_PORT'=>'55441','DB_DATABASE'=>'proactive_investment_20261027_test','DB_USERNAME'=>'postgres','DB_PASSWORD'=>'','DB_URL'=>'','CACHE_STORE'=>'array','SESSION_DRIVER'=>'array','QUEUE_CONNECTION'=>'sync','MAIL_MAILER'=>'array','INVESTMOZ_PEC_QA_OUTPUT'=>'1']as$k=>$v){putenv($k.'='.$v);$_ENV[$k]=$_SERVER[$k]=$v;}
require $root.'/vendor/autoload.php';
spl_autoload_register(function($class)use($root){foreach(['App\\'=>'app/','Tests\\'=>'tests/','Database\\Factories\\'=>'database/factories/']as$prefix=>$dir)if(str_starts_with($class,$prefix)){$file=$root.'/'.$dir.str_replace('\\','/',substr($class,strlen($prefix))).'.php';if(is_file($file)){require $file;return;}}},true,true);
$app=require $root.'/bootstrap/app.php';
(new Illuminate\Foundation\Bootstrap\LoadEnvironmentVariables)->bootstrap($app);(new Illuminate\Foundation\Bootstrap\LoadConfiguration)->bootstrap($app);
$c=config('database.connections.pgsql');
if($app->configurationIsCached()||$c['host']!=='127.0.0.1'||(int)$c['port']!==55441||$c['database']!=='proactive_investment_20261027_test'||!empty($c['url']))throw new RuntimeException('PEC QA target rejected');
$pdo=new PDO('pgsql:host=127.0.0.1;port=55441;dbname='.$c['database'],$c['username'],$c['password']);
if($pdo->query('select current_database()')->fetchColumn()!==$c['database'])throw new RuntimeException('PEC QA identity');
if($operation==='routes'){$app->make(Illuminate\Contracts\Console\Kernel::class)->bootstrap();$status=Illuminate\Support\Facades\Artisan::call('wayfinder:generate',['--with-form'=>true]);echo Illuminate\Support\Facades\Artisan::output();exit($status);}
$argv=['phpunit','-c','phpunit.investmoz.xml','tests/Feature/IrpcPecDraftTest.php'];$argc=count($argv);$_SERVER['argv']=$argv;$_SERVER['argc']=$argc;require $root.'/vendor/phpunit/phpunit/phpunit';
+25
View File
@@ -0,0 +1,25 @@
import fs from 'node:fs';
import path from 'node:path';
import assert from 'node:assert/strict';
import {fileURLToPath} from 'node:url';
import {annualBook,annualCurrent,calculateAnnual,annualHtml,annualReportRows} from '../resources/js/lib/irpc-annual-settlement.ts';
import {createProjectDossierReport} from '../resources/js/lib/project-dossier-report.ts';
const root=path.dirname(path.dirname(fileURLToPath(import.meta.url)));
assert.equal(path.basename(root),'portal-investidor-sequential-delivery-20261027');
const output=path.join(root,'outputs/irpc-l8-pec-20261027');
const results=[];
for(const name of ['payable','capped','recoverable','missing','prior-use']){
const d=JSON.parse(fs.readFileSync(path.join(output,'recovered-'+name+'.json'),'utf8'));
const book=annualBook(d),model=book.result.model;
assert.equal(annualCurrent(d,book),true);
assert.equal(calculateAnnual(d,book).status,model.status);
const html=annualHtml(d),rows=annualReportRows(d);
const dossier=createProjectDossierReport(d,{selectedSections:new Set(['finance']),generatedAt:'2026-10-27T15:00:00+02:00'});
assert.match(html,/PEC — dedução limitada/);assert.match(JSON.stringify(dossier),/PEC — dedução limitada/);
if(name==='missing'){assert.match(html,/Indeterminado/);assert.equal(model.arithmeticBalance,null);}
fs.writeFileSync(path.join(output,'report-'+name+'.html'),html);
fs.writeFileSync(path.join(output,'dossier-'+name+'.json'),JSON.stringify(dossier));
results.push({case:name,status:model.status,balance:model.arithmeticBalance,pec:model.pecDeduction,rows:rows.length,history:book.history.length,apiRoundTrip:true,current:true,dossier:true});
}
fs.writeFileSync(path.join(output,'recovered-report-receipt.json'),JSON.stringify({synthetic:true,activeChanged:false,results},null,2));
console.log(JSON.stringify(results.map(({case:name,status,balance,history})=>({case:name,status,balance,history})),null,2));