Pular para conteúdo

Shadow de Paridade do Conteúdo Institucional

Status: S1–S3 concluídos e certificados; S4 — Shadow em dados reais — é o próximo gate seguro em 08/09/2026.

Base do código SIGESC: main em 4ba3f502995433f7261ababc4fc7b7ebba3b003c — merge da PR #531 (S3).

Produção permanece: 2c203568d9575b47bd66345695692a88de3a7743 — F5 Cobertura Curricular v2. Até o encerramento de S3, nenhuma etapa Shadow foi promovida para produção e nenhum consumidor operacional foi cortado.


1. Problema

Após o cutover canônico de escrita do conteúdo docente, novas gravações pertencem a content_entries. A coleção learning_objects permanece como legado histórico/read-only.

Entretanto, existem consumidores institucionais que ainda calculam indicadores diretamente a partir de learning_objects. Se esses consumidores permanecerem assim, seus números tenderão a subcontar lançamentos novos mesmo que o Diário do professor esteja correto.

A solução não é trocar mecanicamente learning_objects por content_entries. Parte dos consumidores mede volume/tempo/carga de registros; outra parte mede Cobertura Curricular, cuja semântica já foi alterada pela F5 para usar Plano de Ensino publicado como denominador.

Portanto, o cutover deve separar dois domínios:

  1. Reporting de conteúdo: volume, aulas, atraso, distribuição temporal e carga registrada;
  2. Cobertura curricular: previsto versus trabalhado conforme Plano de Ensino Bimestral publicado.

Misturar os dois produziria uma nova dupla SSoT.


2. Fundamentos implementados

2.1 S1 — Read Model Institucional

A PR #529 criou backend/services/content_reporting_projection.py como fundação estritamente read-only.

O read model:

  • compõe content_entries + histórico elegível de learning_objects;
  • exige mantenedora_id explícito;
  • ancora turmas por mantenedora e ano;
  • aceita ano histórico como inteiro ou string;
  • não infere cutover por presença de dados nem por diary_settings.enabled isoladamente;
  • recebe escopos de corte explícitos;
  • permite corte por componente ou class-wide, com precedência do específico;
  • suprime legado posterior ao corte apenas quando o corte é conhecido;
  • faz o canônico prevalecer em sobreposição semântica;
  • rejeita tenant explicitamente divergente;
  • falha fechado para escopos de cutover fora das turmas autorizadas;
  • não executa escrita, migração ou backfill.

S1 foi integrada em main pelo merge da PR #529, SHA 9605fc8fd91d06686ef725466fe104b413db25c9, com CI pós-merge verde e sem deploy.

2.2 S2 — Resolver Canônico de Escopos de Cutover

A PR #530 criou backend/services/content_reporting_cutover_resolver.py.

O resolver:

  • transforma vínculos válidos do Diário por Vínculo em ContentReportingCutoverScope;
  • ancora mantenedora + ano por classes;
  • exige reference_date explícita no mesmo ano letivo;
  • considera somente vínculo não excluído e canonicamente habilitado para Conteúdo;
  • reutiliza o contrato de effective_diary_settings, sem interpretar enabled=true isoladamente;
  • valida tenant, escola, turma e escopo DVD v1;
  • respeita valid_from/valid_until inclusivos;
  • ignora vínculo desabilitado, excluído, futuro ou encerrado na data de referência;
  • permite class-wide e componente específico coexistirem;
  • falha fechado quando vínculos vigentes do mesmo escopo apresentam datas de corte divergentes;
  • não infere corte por presença de content_entries, learning_objects ou primeira ocorrência de dados;
  • permanece estritamente read-only.

S2 foi integrada em main pela PR #530, SHA fdbacaaebde0569038ed79b6d13a6c59f9ca704e. A PR fechou 15/15 workflows com sucesso e o push pós-merge fechou 9/9 workflows com sucesso. production permaneceu em 2c203568d9575b47bd66345695692a88de3a7743; não houve deploy.

2.3 S3 — Executor de Paridade

A PR #531 criou backend/services/content_reporting_parity.py e ampliou o read model S1 apenas com métricas internas das fontes, preservando sua semântica de projeção.

O executor S3:

  • resolve cutovers por S2 e lê as fontes pela S1;
  • não possui router ou endpoint e não altera respostas HTTP existentes;
  • não importa nem monkey-patcha consumidores operacionais;
  • compara a fonte legada com a projeção canônica por consumidor;
  • exige generated_at e code_sha explícitos;
  • gera SHA-256 determinístico do mapa de cutover e do relatório;
  • produz as classificações MATCH, EXPECTED_CANONICAL_GAIN, EXPECTED_POST_CUTOVER_LEGACY_EXCLUSION, HISTORICAL_OVERLAP_SUPPRESSED, PROVENANCE_INCOMPARABLE, SCOPE_ERROR, UNEXPECTED_DIFFERENCE e ERROR;
  • preserva a semântica atual do PMPI para cálculo de atraso (created_at - date, apenas valores não negativos);
  • não fabrica paridade quando a proveniência temporal é incomparável;
  • não grava relatório em Mongo nem executa escrita, migração ou backfill.

Consumidores técnicos reconhecidos por S3:

  • DIARY_DASHBOARD_CONTENT;
  • MONTHLY_REPORT;
  • PMPI_LESSONS;
  • PMPI_WORKLOAD;
  • PMPI_DELAY;
  • ANALYTICS_CONTENT.

S3 foi integrada em main pela PR #531, SHA 4ba3f502995433f7261ababc4fc7b7ebba3b003c. A PR fechou 15/15 workflows com sucesso e o push pós-merge fechou 9/9 workflows com sucesso. production permaneceu em 2c203568d9575b47bd66345695692a88de3a7743; não houve deploy.

Nenhum dos fundamentos S1–S3 está ligado, até aqui, a PMPI, Analytics, Dashboard de Diários, relatório mensal ou Intervenções em produção.


3. Princípio central da Shadow de Paridade

A etapa shadow nunca altera a resposta entregue ao usuário.

Para cada consumidor elegível, o SIGESC deve calcular em paralelo:

resultado legado atualmente exibido
              versus
resultado candidato pelo read model canônico

A comparação deve produzir relatório técnico, nunca substituir silenciosamente a resposta operacional.

O objetivo não é obrigar o novo número a ser igual ao legado em todos os casos. O objetivo é separar:

  • divergência esperada por novos lançamentos canônicos;
  • divergência por histórico/cutover;
  • divergência por diferença de semântica;
  • erro de escopo/tenant;
  • erro real de implementação.

4. Inventário e rota de migração

Consumidor Métrica atual baseada em legado Destino correto Tipo de shadow
Dashboard de Diários — Conteúdo quantidade de registros, aulas e distribuição mensal Read Model Institucional paridade numérica
PMPI — aulas lançadas quantidade de registros numa janela Read Model Institucional paridade numérica
PMPI — atraso de lançamento diferença entre created_at e data da aula Read Model Institucional paridade numérica condicionada à proveniência temporal
PMPI — carga horária soma de number_of_classes Read Model Institucional paridade numérica
Analytics — indicadores derivados de conteúdo agregações sobre registros/aulas Read Model Institucional paridade numérica por escopo
Relatório mensal contagens de lançamentos por escola Read Model Institucional paridade numérica por escola
Detector de Intervenções Curriculares adaptações cobertas por learning_objects Cobertura Curricular F5 substituição semântica, não paridade percentual
Plano de ação / pendências de cobertura adaptações ausentes no legado Cobertura Curricular F5 substituição semântica, não paridade percentual

Fora desta migração

Não devem ser tratados como consumidores a cortar nesta fase:

  • bridges históricos do DVD;
  • leitores/PDFs que já compõem histórico de forma própria e autorizada;
  • scripts forenses, migrações históricas e auditores;
  • índices de banco relacionados ao legado;
  • compatibilidade read-only necessária para dados anteriores ao cutover.

A simples ocorrência textual de learning_objects no repositório não significa que o uso é incorreto.


5. Shadow para Reporting de Conteúdo

5.1 Unidade de comparação

A comparação deve ser reproduzível por:

mantenedora + ano letivo + escola opcional + turma opcional + componente opcional + janela temporal

Todo relatório deve registrar o escopo efetivo e os cortes aplicados.

5.2 Métricas mínimas

Para cada escopo, calcular pelo menos:

  • legacy_record_count;
  • projected_record_count;
  • record_count_delta;
  • legacy_number_of_classes_sum;
  • projected_number_of_classes_sum;
  • number_of_classes_delta;
  • distribuição mensal de registros;
  • distribuição mensal de aulas (number_of_classes);
  • atraso médio de lançamento, quando created_at comparável estiver disponível;
  • quantidade de registros canônicos;
  • quantidade de registros legados mantidos;
  • quantidade de legado suprimido pós-cutover;
  • quantidade de duplicidades semânticas suprimidas;
  • rejeições por tenant incompatível;
  • quantidade e identidade dos escopos de cutover usados.

5.3 Classificações

Cada linha de comparação deve receber uma classificação explícita:

  • MATCH — valores equivalentes;
  • EXPECTED_CANONICAL_GAIN — candidato possui registros novos canônicos que o legado não poderia conter;
  • EXPECTED_POST_CUTOVER_LEGACY_EXCLUSION — legado posterior ao corte foi corretamente excluído;
  • HISTORICAL_OVERLAP_SUPPRESSED — duplicidade legado/canônico foi suprimida;
  • PROVENANCE_INCOMPARABLE — campo necessário para determinada métrica não possui proveniência comparável;
  • SCOPE_ERROR — turma, tenant, ano ou corte inválido;
  • UNEXPECTED_DIFFERENCE — divergência sem explicação prevista;
  • ERROR — falha técnica no cálculo.

MATCH não deve ser considerado a única condição saudável. Depois do cutover de escrita, EXPECTED_CANONICAL_GAIN é uma divergência esperada e positiva.

5.4 Tolerâncias

  • contagens de registros: tolerância 0;
  • soma de aulas: tolerância 0;
  • distribuição mensal: tolerância 0 por mês;
  • atraso médio: tolerância máxima inicial de 0,01 dia apenas para arredondamento;
  • percentuais derivados: comparar primeiro numerador e denominador; o percentual é consequência.

Não usar uma tolerância percentual ampla para esconder diferença estrutural.


6. Shadow para Cobertura e Intervenções

6.1 Regra de semântica

A cobertura antiga e a F5 não possuem o mesmo denominador.

O legado responde, de forma simplificada:

adaptações/habilidades referenciadas em learning_objects
-------------------------------------------------------
adaptações curriculares consideradas ativas

A F5 responde:

itens previstos do Plano de Ensino publicado que foram trabalhados
---------------------------------------------------------------
itens previstos do Plano de Ensino publicado para o escopo

Logo, não existe requisito de igualdade percentual entre as duas métricas.

6.2 Shadow correto para Intervenções

O shadow deve comparar decisões, não exigir igualdade de porcentagem:

  • alerta legado ativo/inativo;
  • cobertura F5 disponível/indisponível;
  • estado F5: previsto trabalhado, previsto pendente, fora do plano, histórico não estruturado, período futuro, plano inexistente;
  • alerta candidato segundo política de intervenção futura;
  • motivo da divergência.

6.3 Regra sem Plano de Ensino publicado

Sem Plano de Ensino publicado:

  • F5 não produz percentual;
  • o shadow não converte isso em 0%;
  • nenhuma nova intervenção curricular deve ser criada por inferência de ausência de plano;
  • o caso deve ser classificado como PLAN_REQUIRED/COVERAGE_UNAVAILABLE até decisão institucional específica.

6.4 Período futuro

Itens de período futuro não entram artificialmente como pendência de cobertura e não podem gerar alerta por atraso curricular.


7. Resolução dos escopos de cutover

A fundação da PR #529 aceita escopos explícitos e a PR #530 implementou o resolver read-only que deriva esses cortes do contrato canônico do Diário por Vínculo, respeitando:

  • vínculo válido;
  • tenant;
  • turma;
  • componente ou class-wide;
  • valid_from;
  • capacidade de conteúdo efetivamente habilitada pelo autorizador canônico;
  • precedência de componente específico sobre class-wide na projeção;
  • ausência de ambiguidades.

É proibido decidir cutover apenas porque existe content_entries, apenas porque diary_settings.enabled=true, ou pela data do primeiro registro encontrado.


8. Relatório Shadow

O executor deve ser read-only e produzir um artefato reproduzível com:

  • timestamp;
  • commit SHA do código;
  • tenant;
  • ano letivo;
  • filtros;
  • mapa/hash dos escopos de cutover;
  • consumidor avaliado;
  • métrica legada;
  • métrica candidata;
  • delta;
  • classificação;
  • contadores internos do read model;
  • erros;
  • resumo por escola, turma e componente quando aplicável.

S3 já implementa o núcleo reproduzível do relatório e seus hashes. S4 deve definir a forma operacional segura de executá-lo sobre dados reais e reter evidência de auditoria sem escrever em coleções operacionais.

Nenhum relatório shadow deve ser gravado em coleções operacionais nesta fase. O artefato pode ser JSON/CSV de CI/auditoria ou resposta técnica protegida, desde que permaneça read-only.


9. Gates para avançar

Gate S1 — Fundação

Concluído pela PR #529.

  • serviço read-only;
  • contrato de merge;
  • fail-closed de tenant/escopo;
  • CI verde;
  • zero consumidor alterado.

Gate S2 — Resolver de cutover

Concluído pela PR #530.

  • testes para vínculo por componente;
  • testes class-wide;
  • sobreposição específico × class-wide;
  • vínculo inativo/encerrado;
  • tenant divergente;
  • ano histórico;
  • ausência de cutover;
  • zero escrita;
  • 15/15 workflows do PR verdes;
  • 9/9 workflows pós-merge em main verdes;
  • zero deploy.

Gate S3 — Executor de paridade

Concluído pela PR #531.

  • comparação por consumidor;
  • classificações determinísticas;
  • relatório reproduzível;
  • nenhuma alteração da resposta HTTP existente;
  • nenhuma escrita em Mongo;
  • testes S1 + S2 + S3 executados juntos;
  • CI/regressões gerais verdes;
  • 15/15 workflows do PR verdes;
  • 9/9 workflows pós-merge em main verdes;
  • zero deploy.

Gate S4 — Shadow em dados reais

Próximo gate. Não iniciado na data desta revisão.

Executar por mantenedora/ano em modo read-only.

Antes de qualquer execução sobre produção, é obrigatório confirmar o mecanismo operacional autorizado para disponibilizar/executar S1–S3 contra a base real, sem criar atalho de deploy, acesso paralelo ou credencial ad hoc.

Para Reporting de Conteúdo, a condição para considerar cutover é:

  • UNEXPECTED_DIFFERENCE = 0 nos escopos certificados;
  • SCOPE_ERROR = 0;
  • ERROR = 0;
  • toda divergência remanescente classificada e explicável;
  • amostras críticas verificadas por turma/componente;
  • nenhum cruzamento de tenant.

Para Cobertura/Intervenções, não usar match-rate percentual. A condição é:

  • todos os casos de plano_inexistente tratados sem fabricar percentual;
  • período futuro não gera falso atraso;
  • divergências de decisão explicadas pela mudança de semântica;
  • política de gatilho para a F5 explicitamente aprovada antes do cutover.

Gate S5 — Cutover por consumidor

Somente depois dos gates anteriores.

O cutover deve ser incremental, um consumidor ou grupo semanticamente homogêneo por PR, preservando rollback simples.

Ordem recomendada:

  1. Dashboard de Diários — Conteúdo;
  2. Relatório mensal;
  3. PMPI — aulas lançadas/carga/atraso;
  4. Analytics de conteúdo;
  5. Intervenções Curriculares, em PR própria e usando F5, não o read model de volume.

10. Regras de rollback

Como o read model é apenas leitura, o rollback de cada consumidor deve consistir em restaurar seu reader anterior enquanto a compatibilidade legada ainda existe.

Não remover learning_objects, não apagar histórico e não executar backfill destrutivo como parte do cutover de reporting.

A remoção futura de compatibilidade legada é uma decisão separada e depende de auditoria de completude histórica.


11. Próxima implementação segura

A próxima etapa é S4 — Shadow em dados reais, ainda sem cutover de consumidor.

O primeiro movimento de S4 deve ser um preflight operacional read-only para localizar e validar o mecanismo já autorizado de execução contra produção. Esse preflight deve responder, antes de qualquer promoção de código:

  1. se existe executor/auditor read-only já homologado capaz de usar o código de main contra a base real sem alterar a aplicação pública;
  2. se S1–S3 precisam ser promovidos para o runtime de produção para que S4 seja tecnicamente possível;
  3. quais gates de release/proveniência precisam ser usados se essa promoção read-only for necessária;
  4. como o relatório S4 será gerado e retido sem escrita em coleções operacionais;
  5. como será garantido o isolamento por mantenedora/ano e a reprodutibilidade pelo SHA exato do código.

É proibido criar mecanismo paralelo de SSH, credencial ad hoc, endpoint público temporário ou deploy fora da governança normal apenas para executar S4.

Somente após esse preflight indicar um caminho canônico e os gates operacionais correspondentes estarem satisfeitos pode ocorrer a execução real do Shadow.


12. Relação com Avaliação e Evidência de Aprendizagem

Este trabalho não é a futura camada de Avaliação/Evidência.

Ele saneia a transição de leitura do domínio de conteúdo e evita que indicadores institucionais continuem presos à coleção legada enquanto o professor escreve no motor canônico.

A cadeia futura permanece:

Plano de Ensino → Registro Docente → Cobertura → Avaliação → Evidência → Intervenção.

Nenhuma estrutura de questão, habilidade avaliada, resposta do estudante, domínio ou evidência individual deve ser criada por inferência a partir deste blueprint.