Skip to content

docs: cross-check gate LayoutParserReact#200 / epic #368 vs estado atual - #412

Merged
elson-vinicius-lopes merged 1 commit into
developfrom
docs/cross-check-gate-200-368
Sep 16, 2026
Merged

elson-vinicius-lopes merged 1 commit into
developfrom
docs/cross-check-gate-200-368

Conversation

@elson-vinicius-lopes

Copy link
Copy Markdown
Collaborator

Issue #368 — cruzamento linha a linha dos 8 itens do gate #200 contra o estado atual de `develop`. Só documentação.

Resultado

6 dos 8 itens já estavam implementados (muita coisa avançou desde agosto: #379/#380/#381/#367 fecharam a maior parte de MappingDraft/TCL-XSLT/Test Lab; `workspaces/me` confirmado no incidente do login).

# Item Veredito
1 `GET /api/workspaces/me` JÁ EXISTE
2 Pacote fiscal versionado JÁ EXISTE
3 MappingDraft JÁ EXISTE (bem mais completo)
4 Contrato de saída TCL/XSL/XSLT JÁ EXISTE
5 MappingExplanation JÁ EXISTE (era "não existe" em agosto)
6 Capabilities Sysmiddle read-only JÁ EXISTE (enforcement); falta payload consultável (gap novo, 6b)
7 Test Lab (XSD/diff/cobertura/provenance) JÁ EXISTE (entregue pela #380)
8 OpenAPI / contract check automatizado PARCIAL — Swagger existe, sem gate de breaking-change em CI

Sub-issues propostas

  1. Doc-only (`@lp-doc`) — documentar os 6 itens fechados pro time React.
  2. Contract check de OpenAPI em CI (`@lp-devops`, P).
  3. Endpoint de capability query (`@lp-backend-dev`, P) — só se o React confirmar necessidade.

🤖 Generated with Claude Code

…ual da API

6 dos 8 itens originais ja estao implementados (workspaces/me, pacote fiscal,
MappingDraft, contrato de saida TCL/XSL/XSLT, MappingExplanation, Test Lab
diff+cobertura), 1 esta parcial (OpenAPI gerado mas sem contract-check em CI)
e 1 revela gap pequeno nao previsto (capability como payload consultavel).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

Dependency Review

✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.

Scanned Files

None

@elson-vinicius-lopes
elson-vinicius-lopes merged commit c91acd6 into develop Sep 16, 2026
3 checks passed
@elson-vinicius-lopes
elson-vinicius-lopes deleted the docs/cross-check-gate-200-368 branch September 16, 2026 00:11
elson-vinicius-lopes added a commit that referenced this pull request Sep 16, 2026
* feat(xml-analysis): endpoint de reconstrução reversa + validação contra TXT original (issue #151) (#407)

* feat(xml-analysis): fecha issue #151 — endpoint de reconstrução reversa + validação contra TXT original

ReverseReconstructionService (best-effort XML->TXT) já existia mas não estava
plugado em nenhum controller/DI. Adiciona POST api/xml-analysis/reverse-reconstruct,
que recebe LayoutXml + o crosswalk FieldToXmlMapping[] já resolvido + TargetXml, e
devolve o TXT reconstruído.

Fecha o gap real da issue (item 3 do critério de aceite): quando OriginalTxt é
informado, ReverseReconstructionValidator compara campo a campo o valor escrito
(via XML) contra o valor real parseado do TXT original (mesmo ILayoutParserService
do pathway direto) — sem ele, a resposta não finge validação nenhuma.

ReconstructionResult ganha ReconstructedFields (issue #151) para dar a
granularidade por campo que a validação precisa, sem reparsear ReconstructedText.

Layout com WithBreakLines=false (MQSeries/IDOC) vira scopeWarning, não erro —
mantém o escopo MVP já declarado no serviço.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* chore(security): baseline do SCS0003 no reverse-reconstruct (issue #151)

O gate de CI (Security Code Scan - gate por severidade) bloqueou o PR #407 por
um achado novo: SCS0003 (XPath injection) em
Services/XmlAnalysis/ReverseReconstructionService.cs:158
(navigator.SelectSingleNode(target.Xpath)).

target.Xpath vem do corpo do POST api/xml-analysis/reverse-reconstruct, mas tanto
ele quanto o TargetXml contra o qual roda vem da MESMA request do MESMO chamador
autenticado - sem cenario de vazamento cross-documento. E leitura pura, ja dentro
de try/catch(XPathException). Aceito conscientemente como debito de baixo risco,
documentado no proprio finding.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>

* feat(ai): preferências de usuário além do prompt customizado (issue #322) (#409)

* feat(ai): preferências de usuário além do prompt customizado (issue #322)

Adiciona idioma de exibição, nível de detalhe da explicação e engine padrão
(TCL/XSLT) como preferências persistentes em tbLpAiUserSession (colunas novas
via ALTER idempotente), com upsert parcial (SetPreferencesAsync) e leitura com
defaults (GetPreferencesAsync). Endpoint dedicado PUT/GET api/transformation/
ai-preferences, [Authorize] + fail-closed 404 sem identidade, 422 para engine/
nível de detalhe fora dos valores aceitos.

O prompt customizado (ai-prompt-adicional, issue #98) continua no
AiUserInstructionStore em memória — não migrado para o SQL nesta issue, só
exposto junto na leitura de GetAiPreferences para consulta única.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* docs(memory): registra decisão dos dois stores de sessão de IA (issue #322)

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>

* docs(architecture): cross-check gate React#200/epic #368 vs estado atual da API (#412)

6 dos 8 itens originais ja estao implementados (workspaces/me, pacote fiscal,
MappingDraft, contrato de saida TCL/XSL/XSLT, MappingExplanation, Test Lab
diff+cobertura), 1 esta parcial (OpenAPI gerado mas sem contract-check em CI)
e 1 revela gap pequeno nao previsto (capability como payload consultavel).

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>

* docs: fechar gate React#200/epic #368 — documentar 6 contratos já implementados (issue #413) (#419)

Cross-check de 2026-09-15 confirmou que 6 dos 8 itens da tabela original do gate #200
já estão implementados sem código novo: GET /api/workspaces/me, pacote fiscal
versionado, MappingDraft (FiscalProfile, editor manual de artefato, filtros de
release, arquivamento), contrato de saída TCL/XSL/XSLT (hash/status/imutabilidade),
MappingExplanation e o Fiscal Test Lab (diff por regra, diff release×release,
cobertura de obrigatórios). Documenta o gap real que sobra (capability Sysmiddle
como payload consultável, issue #415) sem tratá-lo como resolvido.

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>

* feat(mapping-drafts): endpoint de listagem por workspace (issue #416) (#420)

Front reportou gap: Mapping Studio exigia digitar o GUID do draft manualmente,
sem forma de descobrir/listar. Adiciona GET .../mapping-drafts espelhando o
padrão de descoberta já usado em mapping-releases (issue #377): paginação,
RBAC de leitura (qualquer papel de membro) e filtro opcional por engine.
Draft não tem "status" próprio (só as regras têm), então não há filtro de
status neste endpoint.

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
elson-vinicius-lopes added a commit that referenced this pull request Sep 16, 2026
* feat(xml-analysis): endpoint de reconstrução reversa + validação contra TXT original (issue #151) (#407)

* feat(xml-analysis): fecha issue #151 — endpoint de reconstrução reversa + validação contra TXT original

ReverseReconstructionService (best-effort XML->TXT) já existia mas não estava
plugado em nenhum controller/DI. Adiciona POST api/xml-analysis/reverse-reconstruct,
que recebe LayoutXml + o crosswalk FieldToXmlMapping[] já resolvido + TargetXml, e
devolve o TXT reconstruído.

Fecha o gap real da issue (item 3 do critério de aceite): quando OriginalTxt é
informado, ReverseReconstructionValidator compara campo a campo o valor escrito
(via XML) contra o valor real parseado do TXT original (mesmo ILayoutParserService
do pathway direto) — sem ele, a resposta não finge validação nenhuma.

ReconstructionResult ganha ReconstructedFields (issue #151) para dar a
granularidade por campo que a validação precisa, sem reparsear ReconstructedText.

Layout com WithBreakLines=false (MQSeries/IDOC) vira scopeWarning, não erro —
mantém o escopo MVP já declarado no serviço.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* chore(security): baseline do SCS0003 no reverse-reconstruct (issue #151)

O gate de CI (Security Code Scan - gate por severidade) bloqueou o PR #407 por
um achado novo: SCS0003 (XPath injection) em
Services/XmlAnalysis/ReverseReconstructionService.cs:158
(navigator.SelectSingleNode(target.Xpath)).

target.Xpath vem do corpo do POST api/xml-analysis/reverse-reconstruct, mas tanto
ele quanto o TargetXml contra o qual roda vem da MESMA request do MESMO chamador
autenticado - sem cenario de vazamento cross-documento. E leitura pura, ja dentro
de try/catch(XPathException). Aceito conscientemente como debito de baixo risco,
documentado no proprio finding.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>

* feat(ai): preferências de usuário além do prompt customizado (issue #322) (#409)

* feat(ai): preferências de usuário além do prompt customizado (issue #322)

Adiciona idioma de exibição, nível de detalhe da explicação e engine padrão
(TCL/XSLT) como preferências persistentes em tbLpAiUserSession (colunas novas
via ALTER idempotente), com upsert parcial (SetPreferencesAsync) e leitura com
defaults (GetPreferencesAsync). Endpoint dedicado PUT/GET api/transformation/
ai-preferences, [Authorize] + fail-closed 404 sem identidade, 422 para engine/
nível de detalhe fora dos valores aceitos.

O prompt customizado (ai-prompt-adicional, issue #98) continua no
AiUserInstructionStore em memória — não migrado para o SQL nesta issue, só
exposto junto na leitura de GetAiPreferences para consulta única.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* docs(memory): registra decisão dos dois stores de sessão de IA (issue #322)

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>

* docs(architecture): cross-check gate React#200/epic #368 vs estado atual da API (#412)

6 dos 8 itens originais ja estao implementados (workspaces/me, pacote fiscal,
MappingDraft, contrato de saida TCL/XSL/XSLT, MappingExplanation, Test Lab
diff+cobertura), 1 esta parcial (OpenAPI gerado mas sem contract-check em CI)
e 1 revela gap pequeno nao previsto (capability como payload consultavel).

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>

* docs: fechar gate React#200/epic #368 — documentar 6 contratos já implementados (issue #413) (#419)

Cross-check de 2026-09-15 confirmou que 6 dos 8 itens da tabela original do gate #200
já estão implementados sem código novo: GET /api/workspaces/me, pacote fiscal
versionado, MappingDraft (FiscalProfile, editor manual de artefato, filtros de
release, arquivamento), contrato de saída TCL/XSL/XSLT (hash/status/imutabilidade),
MappingExplanation e o Fiscal Test Lab (diff por regra, diff release×release,
cobertura de obrigatórios). Documenta o gap real que sobra (capability Sysmiddle
como payload consultável, issue #415) sem tratá-lo como resolvido.

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>

* feat(mapping-drafts): endpoint de listagem por workspace (issue #416) (#420)

Front reportou gap: Mapping Studio exigia digitar o GUID do draft manualmente,
sem forma de descobrir/listar. Adiciona GET .../mapping-drafts espelhando o
padrão de descoberta já usado em mapping-releases (issue #377): paginação,
RBAC de leitura (qualquer papel de membro) e filtro opcional por engine.
Draft não tem "status" próprio (só as regras têm), então não há filtro de
status neste endpoint.

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>

* fix(deploy): portar migracao NSSM -> servico nativo para producao (#426)

deploy.yml nunca teve a logica de deteccao/migracao do servico legado
NSSM (C:\Users\Administrator\Downloads\nssm-2.24) que o ci-dev.yml ja
usa a cada deploy de dev - producao so fazia Stop-Service/Start-Service
genericos, sem checar o ImagePath do registro nem recriar como servico
Windows nativo (Program.cs usa UseWindowsService() ha tempo).

Porta a mesma logica do ci-dev.yml: no stop, checa se o ImagePath
contem "nssm" e, se sim, remove o registro (sc.exe delete); no restart,
recria o servico nativo (sc.exe create/description/failure) caso ele
nao exista - cobrindo tanto a migracao quanto o primeiro deploy num
host novo. Como sc.exe delete apaga a chave Environment que o step
"Configurar ambiente do servico" ja tinha escrito antes nesse mesmo
registro NSSM, captura o Environment antes do delete e restaura apos
criar o servico nativo, para nao perder Database__Password/
IdentityDatabase__*/etc. na primeira subida.

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>

* feat(fiscal): endpoint de arvore de layout dupla origem/destino (issue #425) (#427)

Implementa GET /api/workspaces/{workspaceId}/mappings/{mappingId}/layout-tree
conforme o ADR "adr-layout-tree-endpoint-425": generaliza GuidXPathCatalog
(ai/XslSynth.Contracts) com extracao de cardinalidade (MinimalOccurrence/
MaximumOccurrence) e um novo BuildTree recursivo (achatando wrappers Choice/
Sequence como irmaos, mesma convencao do XPath ja existente), troca a fonte
de arquivo local por lookup via ICachedLayoutService/ICachedMapperService ja
registrados em producao, e expoe o contrato source/target/rules para o React
replicar a UI de dupla-arvore do Connect Us.

Regras[] reaproveitam apenas LinkMappingItemVO (unico ponto do MapperVO real
onde origem e destino sao GUIDs de no, nao path de DSL) - decisao explicita
do ADR pra nao inventar GUID de origem para as regras DSL (MapperRule).

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
elson-vinicius-lopes added a commit that referenced this pull request Sep 16, 2026
* feat(xml-analysis): endpoint de reconstrução reversa + validação contra TXT original (issue #151) (#407)

* feat(xml-analysis): fecha issue #151 — endpoint de reconstrução reversa + validação contra TXT original

ReverseReconstructionService (best-effort XML->TXT) já existia mas não estava
plugado em nenhum controller/DI. Adiciona POST api/xml-analysis/reverse-reconstruct,
que recebe LayoutXml + o crosswalk FieldToXmlMapping[] já resolvido + TargetXml, e
devolve o TXT reconstruído.

Fecha o gap real da issue (item 3 do critério de aceite): quando OriginalTxt é
informado, ReverseReconstructionValidator compara campo a campo o valor escrito
(via XML) contra o valor real parseado do TXT original (mesmo ILayoutParserService
do pathway direto) — sem ele, a resposta não finge validação nenhuma.

ReconstructionResult ganha ReconstructedFields (issue #151) para dar a
granularidade por campo que a validação precisa, sem reparsear ReconstructedText.

Layout com WithBreakLines=false (MQSeries/IDOC) vira scopeWarning, não erro —
mantém o escopo MVP já declarado no serviço.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* chore(security): baseline do SCS0003 no reverse-reconstruct (issue #151)

O gate de CI (Security Code Scan - gate por severidade) bloqueou o PR #407 por
um achado novo: SCS0003 (XPath injection) em
Services/XmlAnalysis/ReverseReconstructionService.cs:158
(navigator.SelectSingleNode(target.Xpath)).

target.Xpath vem do corpo do POST api/xml-analysis/reverse-reconstruct, mas tanto
ele quanto o TargetXml contra o qual roda vem da MESMA request do MESMO chamador
autenticado - sem cenario de vazamento cross-documento. E leitura pura, ja dentro
de try/catch(XPathException). Aceito conscientemente como debito de baixo risco,
documentado no proprio finding.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>

* feat(ai): preferências de usuário além do prompt customizado (issue #322) (#409)

* feat(ai): preferências de usuário além do prompt customizado (issue #322)

Adiciona idioma de exibição, nível de detalhe da explicação e engine padrão
(TCL/XSLT) como preferências persistentes em tbLpAiUserSession (colunas novas
via ALTER idempotente), com upsert parcial (SetPreferencesAsync) e leitura com
defaults (GetPreferencesAsync). Endpoint dedicado PUT/GET api/transformation/
ai-preferences, [Authorize] + fail-closed 404 sem identidade, 422 para engine/
nível de detalhe fora dos valores aceitos.

O prompt customizado (ai-prompt-adicional, issue #98) continua no
AiUserInstructionStore em memória — não migrado para o SQL nesta issue, só
exposto junto na leitura de GetAiPreferences para consulta única.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* docs(memory): registra decisão dos dois stores de sessão de IA (issue #322)

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>

* docs(architecture): cross-check gate React#200/epic #368 vs estado atual da API (#412)

6 dos 8 itens originais ja estao implementados (workspaces/me, pacote fiscal,
MappingDraft, contrato de saida TCL/XSL/XSLT, MappingExplanation, Test Lab
diff+cobertura), 1 esta parcial (OpenAPI gerado mas sem contract-check em CI)
e 1 revela gap pequeno nao previsto (capability como payload consultavel).

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>

* docs: fechar gate React#200/epic #368 — documentar 6 contratos já implementados (issue #413) (#419)

Cross-check de 2026-09-15 confirmou que 6 dos 8 itens da tabela original do gate #200
já estão implementados sem código novo: GET /api/workspaces/me, pacote fiscal
versionado, MappingDraft (FiscalProfile, editor manual de artefato, filtros de
release, arquivamento), contrato de saída TCL/XSL/XSLT (hash/status/imutabilidade),
MappingExplanation e o Fiscal Test Lab (diff por regra, diff release×release,
cobertura de obrigatórios). Documenta o gap real que sobra (capability Sysmiddle
como payload consultável, issue #415) sem tratá-lo como resolvido.

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>

* feat(mapping-drafts): endpoint de listagem por workspace (issue #416) (#420)

Front reportou gap: Mapping Studio exigia digitar o GUID do draft manualmente,
sem forma de descobrir/listar. Adiciona GET .../mapping-drafts espelhando o
padrão de descoberta já usado em mapping-releases (issue #377): paginação,
RBAC de leitura (qualquer papel de membro) e filtro opcional por engine.
Draft não tem "status" próprio (só as regras têm), então não há filtro de
status neste endpoint.

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>

* fix(deploy): portar migracao NSSM -> servico nativo para producao (#426)

deploy.yml nunca teve a logica de deteccao/migracao do servico legado
NSSM (C:\Users\Administrator\Downloads\nssm-2.24) que o ci-dev.yml ja
usa a cada deploy de dev - producao so fazia Stop-Service/Start-Service
genericos, sem checar o ImagePath do registro nem recriar como servico
Windows nativo (Program.cs usa UseWindowsService() ha tempo).

Porta a mesma logica do ci-dev.yml: no stop, checa se o ImagePath
contem "nssm" e, se sim, remove o registro (sc.exe delete); no restart,
recria o servico nativo (sc.exe create/description/failure) caso ele
nao exista - cobrindo tanto a migracao quanto o primeiro deploy num
host novo. Como sc.exe delete apaga a chave Environment que o step
"Configurar ambiente do servico" ja tinha escrito antes nesse mesmo
registro NSSM, captura o Environment antes do delete e restaura apos
criar o servico nativo, para nao perder Database__Password/
IdentityDatabase__*/etc. na primeira subida.

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>

* feat(fiscal): endpoint de arvore de layout dupla origem/destino (issue #425) (#427)

Implementa GET /api/workspaces/{workspaceId}/mappings/{mappingId}/layout-tree
conforme o ADR "adr-layout-tree-endpoint-425": generaliza GuidXPathCatalog
(ai/XslSynth.Contracts) com extracao de cardinalidade (MinimalOccurrence/
MaximumOccurrence) e um novo BuildTree recursivo (achatando wrappers Choice/
Sequence como irmaos, mesma convencao do XPath ja existente), troca a fonte
de arquivo local por lookup via ICachedLayoutService/ICachedMapperService ja
registrados em producao, e expoe o contrato source/target/rules para o React
replicar a UI de dupla-arvore do Connect Us.

Regras[] reaproveitam apenas LinkMappingItemVO (unico ponto do MapperVO real
onde origem e destino sao GUIDs de no, nao path de DSL) - decisao explicita
do ADR pra nao inventar GUID de origem para as regras DSL (MapperRule).

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>

* fix(fiscal): alinhar identidade de nó entre layout-tree e explanation (#430) (#431)

* fix(fiscal): alinhar identidade de nó entre layout-tree e explanation (#430)

Problema 1: SysmiddleExplanationAdapter.ToExplainedRule priorizava
TargetLeafName (nome legível) sobre TargetGuid em SourceRefs/TargetRefs,
enquanto LayoutTreeService.ResolveRules sempre usa InputGuid/TargetGuid —
o cruzamento regra<->nó no front quebrava quando TargetLeafName estava
preenchido. Agora ambos usam sempre InputGuid/TargetGuid; o nome legível
continua disponível via HumanDescription.

Problema 2: regras DSL (MapperRule/branches condicionais) aparecem em
explanation.rules com sourceRefs/targetRefs prefixados I./T. (texto da
DSL, não GUID de nó), mas nunca entravam em layout-tree.rules[] -
LayoutTreeService.ResolveRules já documentava essa decisão ("inventar um
GUID aqui violaria nunca inventa"). Optei por (b): documentar
explicitamente via novo campo LayoutTreeResponse.Limitations, populado
quando o mapper tem regras DSL, em vez de (a) resolver os prefixos pra
GUID - o catálogo GuidXPathCatalog resolve por GUID, não por nome de
campo, e reconstruir esse contexto está fora do escopo desta issue.

Testes cobrindo os dois casos em MappingExplanationAdaptersTests e
LayoutTreeServiceTests; ajustado LayoutTreeControllerTests pro novo
parâmetro posicional.

* docs: documentar GET .../layout-tree e divergência de cobertura das rules (#425/#430)

Adiciona §8.3 bilíngue ao README com exemplo de request/response e nota
explícita sobre limitations[]: rules[] do layout-tree cobre só vínculo
direto campo->campo, diferente de explanation.rules[] que inclui regras
condicionais/DSL. XML docs em LayoutTree.cs e LayoutTreeController.cs já
estavam completos, sem alteração necessária.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
elson-vinicius-lopes added a commit that referenced this pull request Sep 17, 2026
* feat(xml-analysis): endpoint de reconstrução reversa + validação contra TXT original (issue #151) (#407)

* feat(xml-analysis): fecha issue #151 — endpoint de reconstrução reversa + validação contra TXT original

ReverseReconstructionService (best-effort XML->TXT) já existia mas não estava
plugado em nenhum controller/DI. Adiciona POST api/xml-analysis/reverse-reconstruct,
que recebe LayoutXml + o crosswalk FieldToXmlMapping[] já resolvido + TargetXml, e
devolve o TXT reconstruído.

Fecha o gap real da issue (item 3 do critério de aceite): quando OriginalTxt é
informado, ReverseReconstructionValidator compara campo a campo o valor escrito
(via XML) contra o valor real parseado do TXT original (mesmo ILayoutParserService
do pathway direto) — sem ele, a resposta não finge validação nenhuma.

ReconstructionResult ganha ReconstructedFields (issue #151) para dar a
granularidade por campo que a validação precisa, sem reparsear ReconstructedText.

Layout com WithBreakLines=false (MQSeries/IDOC) vira scopeWarning, não erro —
mantém o escopo MVP já declarado no serviço.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* chore(security): baseline do SCS0003 no reverse-reconstruct (issue #151)

O gate de CI (Security Code Scan - gate por severidade) bloqueou o PR #407 por
um achado novo: SCS0003 (XPath injection) em
Services/XmlAnalysis/ReverseReconstructionService.cs:158
(navigator.SelectSingleNode(target.Xpath)).

target.Xpath vem do corpo do POST api/xml-analysis/reverse-reconstruct, mas tanto
ele quanto o TargetXml contra o qual roda vem da MESMA request do MESMO chamador
autenticado - sem cenario de vazamento cross-documento. E leitura pura, ja dentro
de try/catch(XPathException). Aceito conscientemente como debito de baixo risco,
documentado no proprio finding.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>

* feat(ai): preferências de usuário além do prompt customizado (issue #322) (#409)

* feat(ai): preferências de usuário além do prompt customizado (issue #322)

Adiciona idioma de exibição, nível de detalhe da explicação e engine padrão
(TCL/XSLT) como preferências persistentes em tbLpAiUserSession (colunas novas
via ALTER idempotente), com upsert parcial (SetPreferencesAsync) e leitura com
defaults (GetPreferencesAsync). Endpoint dedicado PUT/GET api/transformation/
ai-preferences, [Authorize] + fail-closed 404 sem identidade, 422 para engine/
nível de detalhe fora dos valores aceitos.

O prompt customizado (ai-prompt-adicional, issue #98) continua no
AiUserInstructionStore em memória — não migrado para o SQL nesta issue, só
exposto junto na leitura de GetAiPreferences para consulta única.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* docs(memory): registra decisão dos dois stores de sessão de IA (issue #322)

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>

* docs(architecture): cross-check gate React#200/epic #368 vs estado atual da API (#412)

6 dos 8 itens originais ja estao implementados (workspaces/me, pacote fiscal,
MappingDraft, contrato de saida TCL/XSL/XSLT, MappingExplanation, Test Lab
diff+cobertura), 1 esta parcial (OpenAPI gerado mas sem contract-check em CI)
e 1 revela gap pequeno nao previsto (capability como payload consultavel).

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>

* docs: fechar gate React#200/epic #368 — documentar 6 contratos já implementados (issue #413) (#419)

Cross-check de 2026-09-15 confirmou que 6 dos 8 itens da tabela original do gate #200
já estão implementados sem código novo: GET /api/workspaces/me, pacote fiscal
versionado, MappingDraft (FiscalProfile, editor manual de artefato, filtros de
release, arquivamento), contrato de saída TCL/XSL/XSLT (hash/status/imutabilidade),
MappingExplanation e o Fiscal Test Lab (diff por regra, diff release×release,
cobertura de obrigatórios). Documenta o gap real que sobra (capability Sysmiddle
como payload consultável, issue #415) sem tratá-lo como resolvido.

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>

* feat(mapping-drafts): endpoint de listagem por workspace (issue #416) (#420)

Front reportou gap: Mapping Studio exigia digitar o GUID do draft manualmente,
sem forma de descobrir/listar. Adiciona GET .../mapping-drafts espelhando o
padrão de descoberta já usado em mapping-releases (issue #377): paginação,
RBAC de leitura (qualquer papel de membro) e filtro opcional por engine.
Draft não tem "status" próprio (só as regras têm), então não há filtro de
status neste endpoint.

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>

* fix(deploy): portar migracao NSSM -> servico nativo para producao (#426)

deploy.yml nunca teve a logica de deteccao/migracao do servico legado
NSSM (C:\Users\Administrator\Downloads\nssm-2.24) que o ci-dev.yml ja
usa a cada deploy de dev - producao so fazia Stop-Service/Start-Service
genericos, sem checar o ImagePath do registro nem recriar como servico
Windows nativo (Program.cs usa UseWindowsService() ha tempo).

Porta a mesma logica do ci-dev.yml: no stop, checa se o ImagePath
contem "nssm" e, se sim, remove o registro (sc.exe delete); no restart,
recria o servico nativo (sc.exe create/description/failure) caso ele
nao exista - cobrindo tanto a migracao quanto o primeiro deploy num
host novo. Como sc.exe delete apaga a chave Environment que o step
"Configurar ambiente do servico" ja tinha escrito antes nesse mesmo
registro NSSM, captura o Environment antes do delete e restaura apos
criar o servico nativo, para nao perder Database__Password/
IdentityDatabase__*/etc. na primeira subida.

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>

* feat(fiscal): endpoint de arvore de layout dupla origem/destino (issue #425) (#427)

Implementa GET /api/workspaces/{workspaceId}/mappings/{mappingId}/layout-tree
conforme o ADR "adr-layout-tree-endpoint-425": generaliza GuidXPathCatalog
(ai/XslSynth.Contracts) com extracao de cardinalidade (MinimalOccurrence/
MaximumOccurrence) e um novo BuildTree recursivo (achatando wrappers Choice/
Sequence como irmaos, mesma convencao do XPath ja existente), troca a fonte
de arquivo local por lookup via ICachedLayoutService/ICachedMapperService ja
registrados em producao, e expoe o contrato source/target/rules para o React
replicar a UI de dupla-arvore do Connect Us.

Regras[] reaproveitam apenas LinkMappingItemVO (unico ponto do MapperVO real
onde origem e destino sao GUIDs de no, nao path de DSL) - decisao explicita
do ADR pra nao inventar GUID de origem para as regras DSL (MapperRule).

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>

* fix(fiscal): alinhar identidade de nó entre layout-tree e explanation (#430) (#431)

* fix(fiscal): alinhar identidade de nó entre layout-tree e explanation (#430)

Problema 1: SysmiddleExplanationAdapter.ToExplainedRule priorizava
TargetLeafName (nome legível) sobre TargetGuid em SourceRefs/TargetRefs,
enquanto LayoutTreeService.ResolveRules sempre usa InputGuid/TargetGuid —
o cruzamento regra<->nó no front quebrava quando TargetLeafName estava
preenchido. Agora ambos usam sempre InputGuid/TargetGuid; o nome legível
continua disponível via HumanDescription.

Problema 2: regras DSL (MapperRule/branches condicionais) aparecem em
explanation.rules com sourceRefs/targetRefs prefixados I./T. (texto da
DSL, não GUID de nó), mas nunca entravam em layout-tree.rules[] -
LayoutTreeService.ResolveRules já documentava essa decisão ("inventar um
GUID aqui violaria nunca inventa"). Optei por (b): documentar
explicitamente via novo campo LayoutTreeResponse.Limitations, populado
quando o mapper tem regras DSL, em vez de (a) resolver os prefixos pra
GUID - o catálogo GuidXPathCatalog resolve por GUID, não por nome de
campo, e reconstruir esse contexto está fora do escopo desta issue.

Testes cobrindo os dois casos em MappingExplanationAdaptersTests e
LayoutTreeServiceTests; ajustado LayoutTreeControllerTests pro novo
parâmetro posicional.

* docs: documentar GET .../layout-tree e divergência de cobertura das rules (#425/#430)

Adiciona §8.3 bilíngue ao README com exemplo de request/response e nota
explícita sobre limitations[]: rules[] do layout-tree cobre só vínculo
direto campo->campo, diferente de explanation.rules[] que inclui regras
condicionais/DSL. XML docs em LayoutTree.cs e LayoutTreeController.cs já
estavam completos, sem alteração necessária.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>

* fix(learning): corrigir split de linha MQSeries no aprendizado de layout (#434)

MQSeries e um stream continuo de largura fixa (600 chars) sem
terminador de linha entre "linhas" logicas. LayoutLearningService
fazia content.Split('\r','\n') incondicionalmente, tratando o
arquivo inteiro como 1 unica linha gigante -> TotalFields=0 (13 dos
14 mapeadores .mq_series em Examples/ afetados; evidencia real em
LAY_TXT_MQSERIES_ENVNFE_4.00_NFe/layout_learned.json, LineLength
35400 para um arquivo de 59 linhas de 600 chars).

Correcoes:
- ParseController: nao colapsa mais "mqseries" em "txt" ao chamar
  LearnFromFileAsync, preservando a distincao de formato.
- LayoutLearningService: para fileType="mqseries", usa o mesmo
  ILineSplitter/PositionalFormat.ContinuousStream do parse real em
  vez de split por \r\n, garantindo que aprendizado e parse
  concordem sobre onde as linhas comecam/terminam.
- Corrigido tambem um segundo bug exposto pelo primeiro: o
  agrupamento de linhas por prefixo literal (DetectLinePatterns)
  nunca junta 3+ linhas MQSeries porque cada linha comeca com um
  contador sequencial de 9 digitos unico por linha (nao um prefixo
  textual repetido como "LINHA001") -- mesmo com o split fisico
  correto, isso ainda dava TotalFields=0. Agrupamento dedicado
  (DetectContinuousStreamGroups) separa HEADER do restante.

Validado contra 4 arquivos .mq_series reais de clientes diferentes
(LAY_TXT_MQSERIES_ENVNFE_4.00_NFe, LAY_CNHI_..., LAY_IVECCO_...,
LAY_TXT_COMAU_...): TotalFields foi de 0 para 8/8/8/10 e TotalLines
passou a bater com tamanho_arquivo/600 em vez de sempre 1.

Testes novos: LayoutLearningServiceMqSeriesTests (fixture sintetico
de 600 chars/linha sem terminador, cobrindo split fisico, aprendizado
de campos reais, e regressao negativa de IDOC/record-per-line).

* Feat/xslt generation loop corpus neogrid (#435)

* feat(ai): primeira rodada real do loop RAG->XSLT no corpus Neogrid (caso InutNFe)

Reusa o loop ja existente em ai/XslSynth (DatasetFewShotIndex + metrics-batch,
RAG->Ollama->validacao) sobre 159 pares reais tcl/xsl indexados do corpus
Examples/{tcl,xsl}, avaliando o par NFe006c_InutNFe_NeoGridToSefaz com o
modelo fine-tuned layoutparser-sysmiddle-dsl:1.5b.

Resultado real (nao simulado): 10/11 campos de <infInut> saem byte-a-byte
identicos ao XSLT de producao (Id/tpAmb/xServ/cUF/ano/CNPJ/mod/serie/
nNFIni/nNFFin); xJust diverge (regra de negocio de prefixo+truncamento
nao inferivel do TCL); falta o wrapper estrutural (xsl:template, root
inutNFe+namespace+versao).

appsettings.Development.json ganha RAG:ExamplesPath/XsdValidation:BasePath
apontando pro corpus local de sessao (.claude/temp/, gitignored).

Persistencia via SqlMappingReleaseStore (padrao dbo.tbMappingRelease)
NAO implementada nesta rodada: sem credencial IdentityDatabase nesta
sessao para validar contra o schema real - documentado como bloqueio,
nao simulado. Detalhe completo na memoria do agente.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* docs(memory): registrar validação real da persistência experimental RAG->XSLT

Round-trip real (INSERT+SELECT) via SqlMappingReleaseStore contra o
IdentityDatabase confirmado com credencial de dotnet user-secrets: ReleaseId
1d612a3c-8b30-4fcb-9fdf-dad1b085608b criado e relido com conteúdo/hash
idênticos. O teste de integração usado para validar foi removido antes do
commit (ci-dev.yml não injeta IdentityDatabase:* no step de dotnet test,
então o teste quebraria o gate de qualquer PR em vez de fazer skip
gracioso) — resultado documentado na memória do agente para não se perder.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>

* feat(fiscal): catalogo de exemplos de referencia TCL/XSL da Neogrid (#437)

Endpoint GET /api/reference-examples (+ /{id} para conteudo) expondo o
corpus real de transformacoes da Neogrid como material de referencia/
oraculo, deliberadamente fora do dominio MappingDraft/MappingRelease
(sem workspaceId, sem ArtifactSource) para nao misturar exemplo estatico
com governanca de release real.

ReferenceExampleCatalogService le disco via ReferenceExamples:BasePath
(configuravel, sem hardcode de path local), pareando arquivos .tcl/.xsl
por DocType/Versao/nome-base; degrada para lista vazia se o path nao
existir. Registrado em Program.cs no grupo Fiscal.

Testes cobrem: listagem com fixture sintetica (par completo, tcl sem
par, filtro por docType), leitura de conteudo por id, e degradacao
graciosa com BasePath vazio/inexistente.

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant