Add supplementary material validations for SPS 1.10#1129
Add supplementary material validations for SPS 1.10#1129
Conversation
- Add validate_id: @id presence in supplementary-material (CRITICAL) - Add validate_sec_title: <title> in sec (CRITICAL) - Add validate_content: <graphic>/<media> presence (WARNING) - Add validate_id_uniqueness: unique @id values (ERROR) - Update inline error level from CRITICAL to ERROR - Fix validate_label to use suppl_label (preserved from model) - Add suppl_label, suppl_caption, has_content to model data - Update rules JSON with new error level configs - Rewrite tests: 16 tests covering all validations Co-authored-by: robertatakenaka <505143+robertatakenaka@users.noreply.github.com>
Co-authored-by: robertatakenaka <505143+robertatakenaka@users.noreply.github.com>
Rossi-Luciano
left a comment
There was a problem hiding this comment.
Bug: validações de supplementary_material.py não produzem resultados no pipeline
Identificado via análise cruzada de xml_validations.py, xml_validator.py e relatório CSV gerado pelo pipeline de validação do upload3/scms-upload com XML artificial de cobertura total do módulo.
Diagnóstico
O XML artificial continha elementos <supplementary-material> cobrindo todos os casos de validação do módulo (validate_id, validate_sec_type, validate_label, validate_not_in_app_group, validate_content, validate_prohibited_inline, validate_position, validate_sec_title, validate_id_uniqueness). O asset checker e o módulo de acessibilidade processaram corretamente todos os elementos — confirmando que o XML foi parseado com sucesso. No entanto, nenhuma entrada com group="supplementary-material" apareceu no CSV. O grupo foi silenciosamente descartado.
Problema 1 — Causa raiz: "supplementary_materials_rules" ausente de get_default_rules()
Em xml_validations.py, validate_supplementary_materials acessa:
rules.update(params["supplementary_materials_rules"])Se a chave "supplementary_materials_rules" não estiver registrada em xml_validator_rules.py / get_default_rules(), a linha levanta KeyError na primeira iteração do gerador. Em xml_validator.py, get_validation_results captura a exceção no bloco except externo e descarta o grupo inteiro — sem registrar nenhum resultado no CSV.
O comentário # TODO presente na função validate_supplementary_materials confirma que a integração estava incompleta ao ser mergeada.
Correção: adicionar "supplementary_materials_rules" ao dicionário retornado por get_default_rules() em xml_validator_rules.py, com o conteúdo definido em supplementary_material_rules.json:
"supplementary_materials_rules": {
"sec_type_error_level": "CRITICAL",
"position_error_level": "CRITICAL",
"label_error_level": "CRITICAL",
"app_group_error_level": "CRITICAL",
"inline_error_level": "ERROR",
"id_error_level": "CRITICAL",
"sec_title_error_level": "CRITICAL",
"content_error_level": "WARNING",
"id_uniqueness_error_level": "ERROR",
"mime_types_and_subtypes": [
{"mimetype": "video", "mime-subtype": "mp4"},
{"mimetype": "audio", "mime-subtype": "mp3"},
{"mimetype": "application", "mime-subtype": "zip"},
{"mimetype": "application", "mime-subtype": "pdf"},
{"mimetype": "application", "mime-subtype": "xlsx"}
],
"mime_type_error_level": "CRITICAL",
"media_attributes_error_level": "CRITICAL",
"parent_suppl_mat_expected": ["app-group", "app"],
}Após a correção, remover o comentário # TODO de validate_supplementary_materials.
Problema 2 — Campo obtained incorreto em validate_sec_type()
Em supplementary_material.py (validação), validate_sec_type define:
obtained=self.data.get("parent_tag"),O campo obtained deve refletir o valor encontrado para o atributo sendo validado — neste caso @sec-type. parent_tag é a tag do elemento pai (sempre "sec" neste contexto), não o valor de @sec-type. Além disso, quando sec_type=None (atributo ausente), a mensagem de advice exibe literalmente "None":
In <sec sec-type="None"><supplementary-material> replace "None" with "supplementary-material".
Correção:
# antes
obtained=self.data.get("parent_tag"),
# depois
obtained=sec_type,E ajustar o advice para tratar sec_type=None de forma descritiva:
sec_type_display = sec_type if sec_type else "(ausente)"
advice=f'In <sec sec-type="{sec_type_display}"><supplementary-material> '
f'replace "{sec_type_display}" with "supplementary-material".',Problema 3 — visual_elem incorreto quando <supplementary-material> não tem conteúdo
Em supplementary_material.py (model), SupplementaryMaterial.data define:
"visual_elem": "media" if self.media else "graphic",Quando nem self.media nem self.graphic estão presentes (caso has_content=False), visual_elem recebe "graphic" em vez de None. O valor é enganoso e pode mascarar o diagnóstico de validate_content.
Correção:
"visual_elem": "media" if self.media else ("graphic" if self.graphic else None),Problema 4 — Shadowing de variável em validate_position()
Em XmlSupplementaryMaterialValidation.validate_position(), a variável sections é declarada com xpath e depois sobrescrita com findall:
sections = self.xml_tree.xpath('.//sec[@sec-type="supplementary-material"]')
if not sections:
return
# ...
if article_body is not None:
sections = article_body.findall("sec") # ← sobrescreve sectionsNão causa bug funcional no código atual, mas é frágil: qualquer refatoração que referencie sections após o if article_body bloco assumindo o valor do xpath obterá resultado incorreto.
Correção: usar nomes de variável distintos:
suppl_sections = self.xml_tree.xpath('.//sec[@sec-type="supplementary-material"]')
if not suppl_sections:
return
# ...
if article_body is not None:
body_sections = article_body.findall("sec")
if body_sections and body_sections[-1].get("sec-type") == "supplementary-material":
is_last_in_body = True
O que esse PR faz?
Implementa validações para
<supplementary-material>e<sec sec-type="supplementary-material">conforme SPS 1.10, cobrindo 7 de 10 regras (70%):@idem<supplementary-material><label>em<supplementary-material>(fix: usava label do media)<title>em<sec sec-type="supplementary-material"><inline-supplementary-material><graphic>ou<media>@idCorrige bug no modelo onde
media.datasobrescrevia olabeldo<supplementary-material>— novo camposuppl_labelpreserva o valor original. Corrige testetest_validate_full_workflowque falhava porNoneem resultados de validação.Onde a revisão poderia começar?
packtools/sps/validation/supplementary_material.py— contém toda a lógica de validação nova.Como este poderia ser testado manualmente?
27 testes (16 validação + 11 modelo), todos passando.
Algum cenário de contexto que queira dar?
Modelo (
supplementary_material.py):SupplementaryMaterial.datafazbase_data.update(self.media.data)que sobrescrevelabel/captioncom os valores do<media>(geralmenteNone). Campossuppl_labelesuppl_captionforam adicionados para preservar os valores do<supplementary-material>.Validações que retornam None: Métodos como
validate_transcript()emaccessibility_data.pyretornamNonepara casos não aplicáveis. Oxml_validator.pyjá filtra comif not item: continue. O testetest_validate_full_workflowfoi corrigido para seguir o mesmo padrão.Screenshots
N/A
Quais são tickets relevantes?
N/A
Referências
Original prompt
This section details on the original issue you should resolve
<issue_title>Criar validações para o elemento </issue_title>
<issue_description>## Objetivo
Implementar validações para o elemento
<supplementary-material>e a seção<sec sec-type="supplementary-material">conforme a especificação SPS 1.10, aumentando a conformidade de X% para 70% (7 de 10 regras).Nota: Algumas validações para
<supplementary-material>podem já estar parcialmente implementadas no repositório. Este Issue visa reavaliar, complementar e garantir cobertura completa das regras SPS 1.10.Contexto
Material suplementar corresponde a todo conteúdo enviado separadamente do PDF do documento que complementa o trabalho publicado. No XML, deve ser representado por uma seção
<sec sec-type="supplementary-material">contendo elementos<supplementary-material>individuais. Validações corretas garantem presença de elementos obrigatórios, estrutura adequada, e conformidade com recomendações PMC/JATS.Conformidade atual: X de 10 regras implementadas (X%)
Meta após implementação: 7 de 10 regras (70%)
Documentação SPS
Referência oficial: https://docs.google.com/document/d/1GTv4Inc2LS_AXY-ToHT3HmO66UT0VAHWJNOIqzBNSgA/edit?tab=t.0#heading=h.supplementarymaterial
Regras principais conforme SPS 1.10:
Ocorrência:
<supplementary-material>pode aparecer zero ou mais vezes em<sec>e<article-meta><sec sec-type="supplementary-material">deve ser a última seção de<body>ou aparecer em<back>Atributos obrigatórios:
@sec-type="supplementary-material"em<sec>(obrigatório)@idem<supplementary-material>(obrigatório)<media>:@id,@mime-type,@mime-subtype,@xlink:href(obrigatórios)<graphic>:@xlink:href(obrigatório)Elementos obrigatórios:
<sec sec-type="supplementary-material">requer<title>(obrigatório)<supplementary-material>requer<label>(obrigatório)Estrutura:
<sec sec-type="supplementary-material">como container<supplementary-material>para cada item suplementar<supplementary-material>:<graphic>para figuras<media>para outros tipos (PDF, Word, Excel, vídeo, etc.)Elementos opcionais:
<caption>com<title>(opcional em<supplementary-material>)Restrições:
<inline-supplementary-material>Regras de links externos:
<supplementary-material><ext-link>adicional no textoDistinções importantes:
<app-group>e<app>, não material suplementarRegras a Implementar
P0 – Críticas (implementar obrigatoriamente)
@idem<supplementary-material>@idé obrigatório em<supplementary-material><label>em<supplementary-material><label>é obrigatório em cada<supplementary-material><title>em<sec sec-type="supplementary-material"><title>é obrigatório em<sec sec-type="supplementary-material"><inline-supplementary-material><inline-supplementary-material>não é permitidoP1 – Importantes (implementar se possível)
<graphic>ou<media>)<supplementary-material>deve conter<graphic>(para figuras) ou<media>(para outros tipos)<sec sec-type="supplementary-material">quando há<supplementary-material><sec sec-type="supplementary-material">@idem<supplementary-material><supplementary-material>deve ter um@idúnicoP2 – Futuras (fora do escopo deste Issue)
Arquivos a Criar/Modificar
Avaliar existentes (podem ter validações parciais):
✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.