# Demanda 40 — O NÚCLEO GANHA OS SEUS ESPECIALISTAS · enquadramento

**Epic `CS-101` · 6 cards · 3 backend · 3 frontend.** Cards em `ENQUADRAMENTO-D40.cards.json`.

## A chave ⛔ não foi improvisada
O rastreador deste produto ⛔ não tem espaço de chaves (medido no pedido 35: «2 projectos, 142
questões, zero acertos em Capacita») e **o dono deu a sigla em 25/09: `CS`**. Continua-se a
numeração da casa. ⚠️ **A PRIMEIRA ENTREGA COLIDIU**: entre a minha medição e o `fab enquadrar`,
outros enquadradores tomaram `CS-76` (demanda 33), `CS-82` (35), `CS-88` (36) e `CS-94` (39), e os
cards subiram até `CS-100` — o verbo recusou com `UNIQUE constraint failed: demanda.chave`, que é a
casa a proteger-se. Remedido DEPOIS: máximo em uso `CS-100`, epics em
1·23·27·32·42·53·58·65·70·76·82·88·94 ⟹ **epic `CS-101`, cards `CS-102`..`CS-107`**.
⛔ Nenhuma chave inventada, ⛔ nenhuma reutilizada. 🩸 Quem enquadrar em paralelo nesta casa MEDE O
MÁXIMO NO MOMENTO DA ENTREGA, ⛔ não no início do trabalho.

## Os cards e o grafo
| card | terr. | o que entrega | depois de |
|---|---|---|---|
| CS-102 | backend | `GET /utilizadores?papel=ESPECIALISTA` — a leitura que o frontend JÁ chama e o servidor ⛔ não tem | — |
| CS-103 | backend | `model EspecialistaNucleo` + atribuir e tirar (só a secretaria) | — |
| CS-104 | backend | as duas leituras da ligação, de qualquer sessão activa | CS-103 |
| CS-105 | frontend | o painel LÊ, dentro de `/secretaria/nucleos` — os seis estados | CS-104 |
| CS-106 | frontend | os dois actos: atribuir dos 7, tirar com diálogo | CS-105, CS-102 |
| CS-107 | frontend | a lista degradada MORRE nos dois ecrãs de aula | CS-102 |

Dois caminhos independentes desde o início (CS-102 e CS-103), profundidade máxima 4. 0 ciclos,
0 órfãos, 0 cercas largas (nenhuma é `backend/src` nem `frontend/src`).

## As três medições que mudaram o enquadramento
1. `utilizadores` dá **1 ocorrência** em `backend/src` e é um **comentário**
   (`cadastro.servico.ts:98`). Os 12 `@Controller` do produto ⛔ não expõem gente. ⟹ a leitura
   entra como card próprio (CS-102) e é o pai de DOIS ramos de frontend.
2. `FRASE_LISTA_DEGRADADA`/`FRASE_ERRO_DOS_ESPECIALISTAS` vivem só em
   `src/app/secretaria/aulas/` (3 ficheiros) — **mas `e2e/aulas.spec.ts` AFIRMA a degradação**
   (`aulas-lista-degradada` visível em `:1081` e `:1149`). ⟹ esse `.spec` ENTRA na cerca do CS-107,
   e os **títulos** dos três testes ⛔ não se mexem (o ficheiro avisa, `:10-12`, que são contrato
   chamado por `-g`).
3. `src/app/secretaria/nucleos/` ⛔ não tem um único hex, `shimmer`, `<progress>` nem `blur(`, e
   ⛔ não tem `artigo`, `chefe` nem `perfil`. ⟹ as cercas do critério (8) são greps a zero que se
   podem impor sem mentir.

## O que eu decidi sozinho, por ser reversível — nomeado para o dono corrigir no aceite
1. **Quem LÊ o rol de especialistas: só a SECRETARIA** (`@Papeis(SECRETARIA)` no CS-102). A regra 122
   fixa quem ESCREVE a ligação (a secretaria) e o quadro fixou que LER A LIGAÇÃO é de qualquer
   sessão (CS-104, e isso ⛔ não muda). Sobre **o rol** ⛔ nada foi decidido: os três consumidores
   são ecrãs dela, e alargar depois é aditivo. ⟹ ⛔ Não gastei a fila (está em 7; o alvo são 3).
2. **A rota do rol serve SÓ `papel=ESPECIALISTA`**; sem `papel` ou com outro valor ⟹ 400. É o que a
   impede de virar uma lista telefonica por acrescento silencioso.
3. **`tirar` grava-se em `retiradoEm`/`retiradoPorId`**, e ⛔ não num enum de situação — porque
   ⛔ não há PENDENTE neste caminho (regra 122) e um enum convidava-o a voltar.
4. **O critério (4) parte-se em dois sítios**: «ler é de qualquer sessão activa» prova-se na ROTA
   (CS-104: médico, coordenador e especialista levam 200); «quem chega ao painel sem direito vê SEM
   PERMISSÃO» prova-se no ECRÃ (CS-105), porque o painel vive em `/secretaria/nucleos`, que é dela.
   ⛔ Nenhum ecrã virado ao médico nasce aqui — isso é a demanda 32.
5. **O painel abre NA LINHA do núcleo**, ⛔ sem rota nova (`! test -d 'nucleos/[id]'` é aceite) —
   decisão 8 do quadro, e mantém `e2e/alcance.spec.ts` verde sem declarar órfã nenhuma.

## OBSERVAÇÕES (⛔ não são achados — ⛔ nada disto me impediu de continuar)
- **`fab enquadrar --help` rebenta** com `ValueError: invalid literal for int()`
  (`fabdono.py:30` faz `int(a[0])` antes de olhar para o argumento). Custou um traceback, ⛔ não um
  bloqueio: a forma está no `fab` sem argumentos.
- **O pedido 97 da fila do dono já está respondido** (resposta 86, 30/09, opção «A» ⟹ regra 122, que
  é a razão desta demanda). Fecha-se com «A» e ⛔ não custa decisão nenhuma — a fila cai de 7 para 6.
- **O critério (6) prova-se pela POSITIVA no CS-103**: cadastrar aula de Pediatria com especialista
  que ⛔ não é referência de Pediatria continua a dar **201**. Se o dono quiser o portão, ele entra
  como card novo — ⛔ não se emenda estes.
