Recomendações de matérias — v3
GET /public/subjects sem q, code e unit devolve as recomendações do aluno de graduação
logado, no lugar da listagem padrão da unidade. Visitantes recebem 422, como antes, e usuários fora
da graduação ou sem matriz identificada também. Com qualquer filtro, a busca é a comum.
A resposta é a mesma lista de CatalogSubject da busca, com as turmas do semestre da oferta,
ordenada pelo ranking e com recommendation: {reasons} em cada matéria. Score e pontos não são
expostos: os motivos vêm do que mais pesou ao que menos pesou, e o front segue essa ordem. Na busca
comum, recommendation é null. Nos critérios acumulativos, reasons[].value traz a quantidade
medida (semestres, matérias ou horas).
Para quem está logado, toda resposta do /public/subjects (busca ou recomendação) traz kind:
mandatory, optional (inclui complementares) ou free (fora da matriz). Na busca comum, a matriz
é a gravada no usuário, sem ir ao SIGAA; sem login ou sem matriz, kind é null.
A aba de busca exibe as recomendações, seus motivos e turmas para alunos de graduação quando não há
texto ou filtros aplicados. A pontuação não é persistida no cache offline.
O código fica em api/modules/recommendations: ranking.py é puro (sem banco ou rede),
repository.py só lê a matriz e o catálogo, e service.py sincroniza as fontes, carrega histórico
e oferta (pelo ClassroomRepository) e monta o ranking. O public_subjects só anexa o resultado ao
catálogo.
Fontes e inferência
A oferta é o semestre mais recente entre as turmas gravadas, comparado por ano/período. Oclassrooms.csv é mantido com as turmas do semestre corrente; lotação não é em tempo real.
Perfil, lista própria de turmas e menções usam Sync.resolve e as tarefas existentes. Cache ausente
exige sincronização; histórico sincronizado vazio é válido. Só vínculos próprios de aluno com
semestre válido até a oferta entram no histórico. A recomendação é para o próximo semestre: matérias
aprovadas (SS/MS/MM) ou em andamento (inclusive as encerradas cuja menção ainda não foi consolidada)
contam como concluídas, saem da lista e satisfazem pré/correquisitos. Reprovações posteriores não
apagam aprovações. Qualquer tentativa sem menção também impede recomendar a disciplina, mesmo após a
consolidação; vínculos trancados ou indeferidos não contam como tentativa. Uma menção
consolidada já gravada não é apagada quando o relatório deixa de trazê-la. Só MI/II/SR confirmados
permitem repetir, desde que não exista outra aprovação, matrícula em andamento ou tentativa sem
resultado. Para o ranking, toda tentativa sem menção presume aprovação: satisfaz pré/correquisitos e
conta como concluída no fluxo, inclusive após a consolidação. Essa inferência não altera a menção
armazenada.
A matriz é inferida só pelo semestre de entrada do perfil (entry_semester), com curso e turno do
perfil armazenado: vale a vigência mais recente até a entrada; se a entrada preceder todas, a mais
antiga. Revisão do código e ID SIGAA desempatam, e matriz de turno oposto nunca é escolhida. O turno
vem do curso resolvido pelo sync, não de uma confirmação adicional. A inferência roda no sync do
perfil e é gravada em users.curriculum_id só enquanto nula, sem revalidação; trocar de curso a
zera. Sem entrada ou sem matriz elegível, o usuário fica sem matriz e a recomendação responde como
para visitante (422).
O período alvo é a mediana inferior dos períodos obrigatórios em andamento + 1. Sem eles, é o
primeiro período com menos da metade das obrigatórias concluídas; depois, o último com pendências;
se todas foram concluídas, último + 1. Códigos sem detalhes de catálogo também contam no fluxo. Sem
período inferível, permanecem os demais critérios. Atraso é uma obrigatória pendente de período
anterior ao alvo.
Elegibilidade e score
O universo abrange toda a universidade: entra toda matéria com turma no semestre da oferta. As exclusões são contadas uma vez, nesta ordem: aprovada, em andamento, pré-requisitos, correquisitos, matriz indisponível, módulo livre. Fora da matriz é módulo livre; componentes optativos e complementares da matriz não são. Regras são OU de grupos E. Equivalências declaradas no catálogo excluem a candidata quando um grupo inteiro já foi aprovado, está em andamento ou tem resultado desconhecido. Esses mesmos grupos satisfazem pré/correquisitos, presumindo aprovação das tentativas sem menção. A avaliação é direcional e direta, sem inferir reciprocidade ou transitividade, e inclui requisitos fora da matriz. Correquisitos não são projetados como matrícula simultânea. Critérios absolutos:
Critérios acumulativos:
As cadeias só valem para candidatas obrigatórias e usam o grafo de pré-requisitos das obrigatórias
pendentes da matriz (não aprovadas nem em andamento), com ou sem oferta. A cadeia mais longa conta
os semestres que vêm depois da candidata (A → B → C → D vale 30); a mais larga conta todas as
descendentes, diretas ou indiretas. Basta a candidata aparecer em algum grupo de pré-requisito.
Ordenação: score decrescente, obrigatória, menor período positivo e código. Turmas cheias
permanecem; as turmas vêm como na busca comum.
Cache e limitações
As fontes seguem SWR,FRESH/FROZEN e diretivas de entrada Cache-Control. no-cache revalida
fontes não congeladas. A resposta sempre usa Cache-Control: no-store.
Sessão inválida: 401. Sem filtros, visitante, usuário fora da graduação ou sem matriz: 422. Falhas
de fontes seguem os handlers existentes (502/503/504). Sem oferta ou candidatas: lista vazia. O
histórico não inclui todas as dispensas/aproveitamentos. O resultado não é uma grade pronta nem
autorização de matrícula.