Skip to content

Criar validações para o elemento <history> #1087

@Rossi-Luciano

Description

@Rossi-Luciano

Objetivo

Implementar validações para o elemento <history> conforme a especificação SPS 1.10, aumentando a conformidade de X% para 75% (9 de 12 regras).

Nota: Algumas validações para <history> podem já estar parcialmente implementadas no repositório. Este Issue visa reavaliar, complementar e garantir cobertura completa das regras SPS 1.10.


Contexto

O elemento <history> agrupa as datas de histórico do documento (recebido, aceito, revisado, preprint, correções, retratações, etc.). Validações corretas garantem que datas obrigatórias estejam presentes, que formatos sejam consistentes (dois dígitos para dia/mês), e que apenas valores permitidos sejam usados para @date-type.

Conformidade atual: X de 12 regras implementadas (X%)
Meta após implementação: 9 de 12 regras (75%)


Documentação SPS

Referência oficial: https://docs.google.com/document/d/1GTv4Inc2LS_AXY-ToHT3HmO66UT0VAHWJNOIqzBNSgA/edit?tab=t.0#heading=h.history

Regras principais conforme SPS 1.10:

  1. Ocorrência:

    • <history> deve aparecer no máximo uma vez em <article-meta> ou <front-stub>
  2. Datas obrigatórias:

    • <date date-type="received"> é obrigatório (exceto para errata, retratação, adendo, manifestação de preocupação e parecer)
    • <date date-type="accepted"> é obrigatório (exceto para errata, retratação, adendo, manifestação de preocupação e parecer)
  3. Valores permitidos para @date-type:

    • received - Data de recebimento do manuscrito
    • accepted - Data de aceitação do manuscrito
    • corrected - Data de aprovação de Errata ou Adendo
    • expression-of-concern - Data de aprovação de Manifestação de Preocupação
    • pub - Data de publicação
    • preprint - Data de publicação como preprint
    • resubmitted - Data de reenvio do manuscrito
    • retracted - Data de aprovação de retratação
    • rev-recd - Data de recebimento do manuscrito revisado
    • rev-request - Data de solicitação de revisões
    • reviewer-report-received - Data de envio de parecer (exclusivo para @article-type="reviewer-report")
  4. Elementos obrigatórios por tipo de data:

    • Para received, accepted, corrected, retracted, expression-of-concern: <day>, <month> e <year> são obrigatórios
    • Para todos os outros tipos: pelo menos <year> é obrigatório
  5. Formato obrigatório:

    • <day> deve ter dois dígitos: 01, 02, ..., 31
    • <month> deve ter dois dígitos: 01, 02, ..., 12
  6. Validação de data:

    • Valores de <day>, <month> e <year> devem formar uma data válida

Regras a Implementar

P0 – Críticas (implementar obrigatoriamente)

# Regra Nível Descrição
1 Validar unicidade de <history> ERROR O elemento <history> deve aparecer no máximo uma vez em <article-meta> ou <front-stub>
2 Validar presença de @date-type em <date> CRITICAL O atributo @date-type é obrigatório em todos os <date> dentro de <history>
3 Validar valores permitidos de @date-type ERROR O valor de @date-type deve estar na lista de valores permitidos
4 Validar presença de <date date-type="received"> CRITICAL A data com @date-type="received" é obrigatória (exceto para errata, retratação, adendo, manifestação de preocupação e parecer)
5 Validar presença de <date date-type="accepted"> CRITICAL A data com @date-type="accepted" é obrigatória (exceto para errata, retratação, adendo, manifestação de preocupação e parecer)
6 Validar completude de data para tipos críticos CRITICAL Para received, accepted, corrected, retracted, expression-of-concern: <day>, <month> e <year> são obrigatórios
7 Validar presença mínima de <year> CRITICAL Para todos os tipos de data, pelo menos <year> deve estar presente

P1 – Importantes (implementar se possível)

# Regra Nível Descrição
8 Validar formato de <day> (dois dígitos) ERROR O elemento <day> deve ter exatamente dois dígitos (01-31)
9 Validar formato de <month> (dois dígitos) ERROR O elemento <month> deve ter exatamente dois dígitos (01-12)
10 Validar data válida ERROR Valores de <day>, <month> e <year> devem formar uma data válida (ex: 31/02 é inválido)

P2 – Futuras (fora do escopo deste Issue)

# Regra Motivo de exclusão
11 Validar ordem cronológica de datas (received < accepted < pub) Média complexidade - requer lógica de comparação de datas e decisão sobre quais datas comparar
12 Validar uso correto de reviewer-report-received com @article-type="reviewer-report" Baixa prioridade - requer validação cruzada com atributo de artigo

Arquivos a Criar/Modificar

Avaliar existentes (podem ter validações parciais):

  • packtools/sps/models/dates.py ou history.py – Verificar se modelo existe
  • packtools/sps/validation/dates.py ou history.py – Verificar validações existentes
  • packtools/sps/validation/rules/history_rules.json ou similar – Verificar configuração

Criar (se não existirem):

  • packtools/sps/models/history.py – Modelo de extração de dados
  • packtools/sps/validation/history.py – Validações
  • packtools/sps/validation/rules/history_rules.json – Configuração de níveis de erro
  • tests/sps/validation/test_history.py – Testes unitários

Referenciar (implementações similares):

  • packtools/sps/validation/article_doi.py – Validação de unicidade
  • packtools/sps/validation/utils.py – Funções auxiliares (build_response)

Exemplos de XML

XML Válido (deve passar sem erros):

<!-- Exemplo 1: Histórico completo com todas as datas obrigatórias -->
<article-meta>
    <history>
        <date date-type="received">
            <day>15</day>
            <month>03</month>
            <year>2024</year>
        </date>
        <date date-type="accepted">
            <day>12</day>
            <month>05</month>
            <year>2024</year>
        </date>
    </history>
</article-meta>

<!-- Exemplo 2: Histórico com preprint (apenas ano obrigatório) -->
<article-meta>
    <history>
        <date date-type="received">
            <day>15</day>
            <month>03</month>
            <year>2024</year>
        </date>
        <date date-type="accepted">
            <day>12</day>
            <month>05</month>
            <year>2024</year>
        </date>
        <date date-type="preprint">
            <day>21</day>
            <month>09</month>
            <year>2023</year>
        </date>
    </history>
</article-meta>

<!-- Exemplo 3: Histórico com correção (data completa obrigatória) -->
<article-meta>
    <history>
        <date date-type="received">
            <day>15</day>
            <month>03</month>
            <year>2024</year>
        </date>
        <date date-type="accepted">
            <day>12</day>
            <month>05</month>
            <year>2024</year>
        </date>
        <date date-type="corrected">
            <day>03</day>
            <month>07</month>
            <year>2025</year>
        </date>
    </history>
</article-meta>

<!-- Exemplo 4: Histórico com retratação (data completa obrigatória) -->
<article-meta>
    <history>
        <date date-type="received">
            <day>10</day>
            <month>01</month>
            <year>2023</year>
        </date>
        <date date-type="accepted">
            <day>05</day>
            <month>03</month>
            <year>2023</year>
        </date>
        <date date-type="retracted">
            <day>20</day>
            <month>06</month>
            <year>2024</year>
        </date>
    </history>
</article-meta>

<!-- Exemplo 5: Histórico com manifestação de preocupação -->
<article-meta>
    <history>
        <date date-type="received">
            <day>08</day>
            <month>02</month>
            <year>2024</year>
        </date>
        <date date-type="accepted">
            <day>15</day>
            <month>04</month>
            <year>2024</year>
        </date>
        <date date-type="expression-of-concern">
            <day>10</day>
            <month>08</month>
            <year>2024</year>
        </date>
    </history>
</article-meta>

<!-- Exemplo 6: Histórico com apenas ano para pub -->
<article-meta>
    <history>
        <date date-type="received">
            <day>01</day>
            <month>01</month>
            <year>2024</year>
        </date>
        <date date-type="accepted">
            <day>01</day>
            <month>03</month>
            <year>2024</year>
        </date>
        <date date-type="pub">
            <year>2024</year>
        </date>
    </history>
</article-meta>

<!-- Exemplo 7: Histórico com revisões -->
<article-meta>
    <history>
        <date date-type="received">
            <day>01</day>
            <month>06</month>
            <year>2024</year>
        </date>
        <date date-type="rev-request">
            <year>2024</year>
        </date>
        <date date-type="rev-recd">
            <year>2024</year>
        </date>
        <date date-type="accepted">
            <day>15</day>
            <month>09</month>
            <year>2024</year>
        </date>
    </history>
</article-meta>

XML Inválido – Caso 1: Múltiplos (ERROR)

<article-meta>
    <history>
        <date date-type="received">
            <day>15</day>
            <month>03</month>
            <year>2024</year>
        </date>
    </history>
    <history>
        <date date-type="accepted">
            <day>12</day>
            <month>05</month>
            <year>2024</year>
        </date>
    </history>
</article-meta>

Erro esperado: Elemento <history> deve aparecer no máximo uma vez

XML Inválido – Caso 2: sem @date-type (CRITICAL)

<article-meta>
    <history>
        <date>
            <day>15</day>
            <month>03</month>
            <year>2024</year>
        </date>
    </history>
</article-meta>

Erro esperado: Atributo @date-type é obrigatório em <date>

XML Inválido – Caso 3: @date-type com valor inválido (ERROR)

<article-meta>
    <history>
        <date date-type="submitted">
            <day>15</day>
            <month>03</month>
            <year>2024</year>
        </date>
        <date date-type="accepted">
            <day>12</day>
            <month>05</month>
            <year>2024</year>
        </date>
    </history>
</article-meta>

Erro esperado: Valor "submitted" não está na lista de valores permitidos para @date-type

XML Inválido – Caso 4: Sem data "received" (CRITICAL)

<article-meta>
    <history>
        <date date-type="accepted">
            <day>12</day>
            <month>05</month>
            <year>2024</year>
        </date>
    </history>
</article-meta>

Erro esperado: Data com @date-type="received" é obrigatória

XML Inválido – Caso 5: Sem data "accepted" (CRITICAL)

<article-meta>
    <history>
        <date date-type="received">
            <day>15</day>
            <month>03</month>
            <year>2024</year>
        </date>
    </history>
</article-meta>

Erro esperado: Data com @date-type="accepted" é obrigatória

XML Inválido – Caso 6: "received" sem (CRITICAL)

<article-meta>
    <history>
        <date date-type="received">
            <month>03</month>
            <year>2024</year>
        </date>
        <date date-type="accepted">
            <day>12</day>
            <month>05</month>
            <year>2024</year>
        </date>
    </history>
</article-meta>

Erro esperado: Para @date-type="received", <day> é obrigatório

XML Inválido – Caso 7: "accepted" sem (CRITICAL)

<article-meta>
    <history>
        <date date-type="received">
            <day>15</day>
            <month>03</month>
            <year>2024</year>
        </date>
        <date date-type="accepted">
            <day>12</day>
            <year>2024</year>
        </date>
    </history>
</article-meta>

Erro esperado: Para @date-type="accepted", <month> é obrigatório

XML Inválido – Caso 8: "corrected" sem (CRITICAL)

<article-meta>
    <history>
        <date date-type="received">
            <day>15</day>
            <month>03</month>
            <year>2024</year>
        </date>
        <date date-type="accepted">
            <day>12</day>
            <month>05</month>
            <year>2024</year>
        </date>
        <date date-type="corrected">
            <day>03</day>
            <month>07</month>
        </date>
    </history>
</article-meta>

Erro esperado: Para @date-type="corrected", <year> é obrigatório

XML Inválido – Caso 9: "preprint" sem (CRITICAL)

<article-meta>
    <history>
        <date date-type="received">
            <day>15</day>
            <month>03</month>
            <year>2024</year>
        </date>
        <date date-type="accepted">
            <day>12</day>
            <month>05</month>
            <year>2024</year>
        </date>
        <date date-type="preprint">
            <day>21</day>
            <month>09</month>
        </date>
    </history>
</article-meta>

Erro esperado: Para @date-type="preprint", pelo menos <year> é obrigatório

XML Inválido – Caso 10: com um dígito (ERROR)

<article-meta>
    <history>
        <date date-type="received">
            <day>5</day>
            <month>03</month>
            <year>2024</year>
        </date>
        <date date-type="accepted">
            <day>12</day>
            <month>05</month>
            <year>2024</year>
        </date>
    </history>
</article-meta>

Erro esperado: Elemento <day> deve ter dois dígitos (use 05 ao invés de 5)

XML Inválido – Caso 11: com um dígito (ERROR)

<article-meta>
    <history>
        <date date-type="received">
            <day>15</day>
            <month>3</month>
            <year>2024</year>
        </date>
        <date date-type="accepted">
            <day>12</day>
            <month>05</month>
            <year>2024</year>
        </date>
    </history>
</article-meta>

Erro esperado: Elemento <month> deve ter dois dígitos (use 03 ao invés de 3)

XML Inválido – Caso 12: Data inválida (31 de fevereiro) (ERROR)

<article-meta>
    <history>
        <date date-type="received">
            <day>31</day>
            <month>02</month>
            <year>2024</year>
        </date>
        <date date-type="accepted">
            <day>12</day>
            <month>05</month>
            <year>2024</year>
        </date>
    </history>
</article-meta>

Erro esperado: Data inválida: dia 31 não existe em fevereiro

XML Inválido – Caso 13: Mês inválido (13) (ERROR)

<article-meta>
    <history>
        <date date-type="received">
            <day>15</day>
            <month>13</month>
            <year>2024</year>
        </date>
        <date date-type="accepted">
            <day>12</day>
            <month>05</month>
            <year>2024</year>
        </date>
    </history>
</article-meta>

Erro esperado: Mês inválido: 13 (deve estar entre 01 e 12)

XML Inválido – Caso 14: Dia inválido (32) (ERROR)

<article-meta>
    <history>
        <date date-type="received">
            <day>32</day>
            <month>03</month>
            <year>2024</year>
        </date>
        <date date-type="accepted">
            <day>12</day>
            <month>05</month>
            <year>2024</year>
        </date>
    </history>
</article-meta>

Erro esperado: Dia inválido: 32 (deve estar entre 01 e 31)


Padrão de Implementação

Diretrizes Gerais:

  1. Seguir padrões existentes no repositório:

    • Consultar implementações similares como article_doi.py (validação de unicidade)
    • Usar estrutura de classes já estabelecida no packtools
    • IMPORTANTE: Verificar se já existem validações parciais para <history> e integrá-las ou complementá-las
  2. Internacionalização (i18n):

    • OBRIGATÓRIO: Todas as mensagens devem suportar internacionalização
    • Usar advice_text e advice_params em build_response()
    • Consultar conversas anteriores sobre implementação de i18n no packtools
    • Referência: validações em article_contribs.py que já implementam i18n completo
  3. Validações condicionais:

    • Validações que dependem de contexto devem retornar None quando não aplicável
    • Exemplo: datas obrigatórias (received, accepted) não se aplicam para errata, retratação, adendo, manifestação de preocupação e parecer
    • Exemplo: validação de completude de data (day/month/year) depende do tipo de data
    • Usar filter_results() nos testes para remover None
  4. Uso de build_response():

    • Sempre usar parent=self.data (dict completo, nunca string)
    • Campo response deve conter: "OK", "WARNING", "ERROR", "CRITICAL"
    • Sempre fornecer advice_text e advice_params para i18n
  5. Modelo de dados:

    • Criar propriedade que retorna lista de dicionários com todas as datas
    • Cada dict deve conter: date_type, day, month, year, parent, parent_id, parent_lang
    • Detectar contexto do documento (se é errata, retratação, etc.) para validações condicionais
  6. Validação de formato de dois dígitos:

    • Verificar comprimento exato de string: len(day) == 2
    • Validar que consiste apenas de dígitos: day.isdigit()
  7. Validação de data válida:

    • Usar biblioteca datetime para validar se day/month/year formam data válida
    • Considerar anos bissextos para fevereiro
    • Tratar exceções de ValueError ao construir data
  8. Listas de valores permitidos:

    • Criar constantes para tipos de data que requerem completude: COMPLETE_DATE_TYPES = ["received", "accepted", "corrected", "retracted", "expression-of-concern"]
    • Criar lista de todos os valores permitidos para @date-type

Testes Esperados

Casos de teste obrigatórios:

Unicidade:

  • Um único <history> em <article-meta> (OK)
  • Dois ou mais <history> em <article-meta> (ERROR)
  • Nenhum <history> em <article-meta> (OK - opcional)

Atributo @date-type:

  • <date> com @date-type válido (OK)
  • <date> sem @date-type (CRITICAL)
  • @date-type vazio ou só espaços (CRITICAL)
  • Todos os valores permitidos de @date-type (OK para cada um)
  • Valor inválido de @date-type (ERROR)

Datas obrigatórias:

  • Histórico com received e accepted (OK)
  • Histórico sem received (CRITICAL)
  • Histórico sem accepted (CRITICAL)
  • Histórico sem received nem accepted (CRITICAL)
  • Errata/retratação/adendo sem received (OK - exceção)

Completude de data por tipo:

  • received com day/month/year (OK)
  • received sem day (CRITICAL)
  • received sem month (CRITICAL)
  • received sem year (CRITICAL)
  • accepted com day/month/year (OK)
  • accepted sem day (CRITICAL)
  • accepted sem month (CRITICAL)
  • accepted sem year (CRITICAL)
  • corrected com day/month/year (OK)
  • corrected sem day (CRITICAL)
  • retracted com day/month/year (OK)
  • retracted sem month (CRITICAL)
  • expression-of-concern com day/month/year (OK)
  • expression-of-concern sem year (CRITICAL)

Ano mínimo para outros tipos:

  • preprint com year (OK)
  • preprint sem year (CRITICAL)
  • pub com year (OK)
  • pub sem year (CRITICAL)
  • rev-recd com year (OK)
  • rev-recd sem year (CRITICAL)

Formato de dois dígitos:

  • <day> com dois dígitos 01 (OK)
  • <day> com dois dígitos 31 (OK)
  • <day> com um dígito 5 (ERROR)
  • <day> com três dígitos 001 (ERROR)
  • <month> com dois dígitos 01 (OK)
  • <month> com dois dígitos 12 (OK)
  • <month> com um dígito 3 (ERROR)
  • <month> com três dígitos 012 (ERROR)

Validação de data:

  • Data válida 29/02/2024 (ano bissexto) (OK)
  • Data inválida 29/02/2023 (não bissexto) (ERROR)
  • Data inválida 31/02/2024 (ERROR)
  • Data inválida 32/01/2024 (ERROR)
  • Data inválida 31/04/2024 (abril tem 30 dias) (ERROR)
  • Mês 00 (ERROR)
  • Mês 13 (ERROR)
  • Dia 00 (ERROR)
  • Dia 32 (ERROR)
  • Ano negativo (ERROR)
  • Ano 0000 (WARNING - improvável)

Casos de borda:

  • Múltiplas datas do mesmo tipo (OK - permitido)
  • <day>, <month>, <year> vazios (CRITICAL)
  • <day>, <month>, <year> apenas espaços (CRITICAL)
  • <day>, <month>, <year> com texto não numérico (ERROR)
  • Histórico vazio sem nenhuma <date> (WARNING)

Total esperado: ~55 testes unitários

Estrutura de testes:

  • Usar filter_results() para remover None dos resultados
  • Asserções devem usar campo response (não is_valid)
  • Testes devem ser autocontidos e descritivos
  • Agrupar testes por categoria (unicidade, datas obrigatórias, formatos, validação de data)

Critérios de Aceite

O PR será aceito quando:

  • Verificação de validações existentes: Código existente para <history> foi analisado e integrado ou substituído adequadamente
  • Todas as regras P0 implementadas (7 validações CRITICAL/ERROR)
  • Todas as regras P1 implementadas (3 validações ERROR)
  • Testes unitários passando com cobertura mínima de ~55 casos
  • Nenhum teste existente quebrado
  • Arquivo history_rules.json criado com todos os níveis de erro
  • Internacionalização completa em todas as mensagens (i18n obrigatório)
  • Código seguindo padrões do packtools (build_response, filter_results, validações condicionais)
  • Modelo de dados criado com extração adequada de elementos de data
  • Validação de unicidade funcionando
  • Validação condicional de datas obrigatórias (exceção para errata/retratação/etc.)
  • Validação de formato de dois dígitos funcionando
  • Validação de data válida usando datetime
  • Documentação inline clara (docstrings)

Referências

Documentação SPS:

Padrões JATS:

Referências internas packtools:

  • Internacionalização: Consultar conversas anteriores sobre implementação de i18n
  • Implementações similares: article_doi.py (unicidade)
  • Funções auxiliares: utils.py (build_response)

Labels Sugeridas

enhancement validation SPS-1.10 good-first-issue


Impacto Esperado

Antes:

  • Conformidade SPS 1.10 para <history>: X% (verificar validações existentes)
  • Datas obrigatórias podem estar ausentes
  • Formatos inconsistentes de dia/mês (um vs dois dígitos)
  • Datas inválidas podem passar sem detecção
  • Valores inválidos de @date-type não detectados

Depois:

  • Conformidade SPS 1.10 para <history>: 75% (9 de 12 regras)
  • Validação CRITICAL de datas obrigatórias (received, accepted)
  • Validação CRITICAL de elementos obrigatórios por tipo de data
  • Validação ERROR de formato de dois dígitos para dia/mês
  • Validação ERROR de datas válidas (calendário)
  • Validação ERROR de valores permitidos de @date-type
  • ~55 testes unitários garantindo qualidade
  • Internacionalização completa (PT/EN/ES)

Benefícios:

  • Melhora a qualidade dos XMLs SciELO
  • Garante consistência de formato de datas
  • Detecta erros críticos antes da publicação
  • Previne datas impossíveis no calendário
  • Facilita processamento automatizado de datas
  • Promove conformidade com padrões internacionais
  • Melhora rastreabilidade do histórico editorial
  • Facilita manutenção e depuração de XMLs

Metadata

Metadata

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions