# CS-100 no `epic/CS-94` — A MEDIÇÃO, E PORQUE DEVOLVO

Integrador, 04/10/2026. Âmbito: fundir `frente/CS-100` em `epic/CS-94`.
⛔ NÃO toquei no `main` da máquina. ⛔ NÃO abri PR. ⛔ NÃO corri `integrar juntar` — e a razão
está em §5, porque correr o verbo aqui faria **dano medido**.

---

## 0 · A PREMISSA DA TAREFA ESTÁ ERRADA, E MEDI-A ANTES DE A ACREDITAR

A tarefa diz: «o card está `reprovado` com o critério "conflito ao integrar no epic"».

**⛔ FALSO.** Isso foi o veredito **2569**, de 01/10 20:02 — e foi **RESOLVIDO** no dia seguinte.
O veredito que prende o card HOJE é o **2743**, de 02/10 06:44:30:

```
tipo=capturas  quem=rev-qa  resultado=DIVERGE
«Estado 02-folha-por-confirmar NAO BATE: a spec exige, em cada presencas-linha,
 "avatar + NOME DA UPA ESCRITO, nome, CRM tabular" (§4 estado 02; R2.3 linha 324).
 Nas capturas cada linha mostra apenas um avatar circular CINZENTO E VAZIO (sem
 iniciais sequer), nome e CRM — nenhuma UPA escrita em lado nenhum.
 Falta propaga-se a 02,03,04,05,06,07,08,13,16,17,18. Os outros 17 estados batem.»
```

⟹ O que prende o CS-100 ⛔ **não é um conflito de merge**. É uma **divergência de conteúdo**.
A skill manda medir a premissa antes de a acreditar («a premissa da tarefa ⛔ não é prova»), e foi
exactamente aqui que ela falhou.

---

## 1 · ⛔ NÃO HÁ NADA PARA FUNDIR — TRÊS MEDIÇÕES INDEPENDENTES, TODAS A DIZER O MESMO

### (a) o ramo já é ancestral do epic
```
git merge-base --is-ancestor frente/CS-100 epic/CS-94   ⟹ 0 (SIM)
git log --oneline epic/CS-94..frente/CS-100             ⟹ VAZIO (0 commits de fora)
git merge-base epic/CS-94 frente/CS-100                 ⟹ 05a1895d = a PRÓPRIA ponta do card
```

### (b) o merge é um no-op, e a árvore prova-o
```
git merge-tree --write-tree epic/CS-94 frente/CS-100
  exit = 0            ⟹ ⛔ ZERO conflitos
  árvore resultante     ba59937fdff9a2ad50352289f717994dc814bb3c
  árvore de epic/CS-94  ba59937fdff9a2ad50352289f717994dc814bb3c   ⟹ IDÊNTICAS
```
⟹ Fundir ⛔ não mudaria **um único byte** do epic.

### (c) o conteúdo dos 5 caminhos do escopo é byte-a-byte igual
```
git diff --stat frente/CS-100 epic/CS-94 -- \
  frontend/src/app/cursos/ frontend/src/lib/navegacao.ts \
  frontend/e2e/presencas.spec.ts frontend/e2e/navegacao.spec.ts frontend/e2e/alcance.spec.ts
  ⟹ VAZIO
```
E os 11 ficheiros de `frontend/src/app/cursos/` existem no epic, incluindo
`[id]/presencas/page.tsx`, `presencas-api.ts`, `presencas-pecas.tsx`, `presencas-textos.ts`.

### (d) e a casa já o tinha registado
Evento **54726**, 02/10 06:04:06: `integrado {"merge":"74c424b7…","ramo":"epic/CS-94","sha_por":"pai2"}`.
O topo do epic **É** esse merge: `74c424b7` tem pai-2 = `05a1895d` = `frente/CS-100`.
E ⛔ **nunca houve `merge_desfeito` depois dele** — os dois reverts (`dbacfece`, `fd15347b`) são
ANTERIORES, e o segundo foi desfeito por `18bf1d60` («Reapply»), registado no evento 54192.

🩸 **⟹ O CS-100 está FISICAMENTE DENTRO do epic, e registado como `reprovado`.** O código entrou;
o que ⛔ não passou foi a conferência das capturas.

---

## 2 · O EPIC ESTÁ VERDE — MEDIDO, ⛔ NÃO PRESUMIDO

Corrido no topo do epic (`74c424b7`), em worktree próprio, **como `fabrica` e ⛔ nunca como root**:

```
npx tsc --noEmit                                    ⟹ exit 0, ⛔ zero erros
npx playwright test e2e/presencas.spec.ts           ⟹ 16 passed (53.6s)
npx playwright test e2e/navegacao.spec.ts e2e/alcance.spec.ts ⟹ 16 passed (7.9m)
```
⟹ **32/32 verdes.** ⛔ Nenhum teste vermelho. O epic ⛔ não está quebrado.

---

## 3 · A CAUSA RAIZ: UMA SÓ, E ESTÁ **FORA** DO ESCOPO DO CARD

O ecrã ⛔ não escreve a UPA porque **o servidor ⛔ nunca a manda**.

**`backend/src/modules/inscricao/inscricao.servico.ts`** (CS-96, o dono do contrato):
```ts
const COM_MEDICO = {
  medico: { select: { id: true, nome: true, crm: true } },   // ⛔ SEM upa
} satisfies Prisma.InscricaoCursoInclude;

function aoPublico(i) { return { …, medico: { id, nome, crm }, … }; }   // ⛔ SEM upa
```

E **o frontend já está todo ligado para a mostrar** — ⛔ não lhe falta trabalho nenhum:
- `presencas-api.ts:111-158` — `aUpa()` aceita `upa`, `upa.nome` ou `upas[0]`, e devolve `null`
  quando ⛔ não vem. ⛔ Não inventa nome (certo).
- `presencas-pecas.tsx:182` — `<AvatarUpa nome={inscrito.upa} denso nomeEscritoNaLinha />`
- `presencas-pecas.tsx:204` — `{inscrito.upa === null ? null : ` · ${inscrito.upa}`}`

⟹ **O dia em que o servidor mandar a unidade, o nome aparece sem mudar uma linha do frontend.**
O próprio dev mediu isto e deixou-o escrito no cabeçalho do `presencas-api.ts` (divergência «(b)»).

### 🩸 E AQUI ESTÁ O DEFEITO VERDADEIRO — É DE ESPECIFICAÇÃO, ⛔ NÃO DE CÓDIGO

| | promete a UPA? |
|---|---|
| **spec do CS-100** (frontend) R2.3, linha 324 | **SIM**: «O **nome da UPA vai escrito** ao lado do avatar — avatar sozinho ⛔ não identifica unidade nenhuma» |
| **spec do CS-96** (backend, dono do contrato) | **⛔ NÃO** — `grep -i upa CS-96.md` dá só o `@@map("inscricao_curso")` e nomes de relação. **A UPA do médico ⛔ NUNCA FOI PEDIDA AO BACKEND.** |

⟹ Dois cards do MESMO epic foram especificados com **contratos contraditórios**. O CS-100 ⛔ não
pode cumprir a sua própria R2.3, porque:
1. o dado ⛔ não existe no contrato; e
2. o `escopo_paths` do CS-100 é **só frontend** —
   `["frontend/src/app/cursos/", "frontend/src/lib/navegacao.ts", "frontend/e2e/*.spec.ts"]`.
   `backend/src/modules/inscricao/` está **FORA**, e o CS-96 já está `aprovado`.

### E a regra 66 da casa dá razão ao rev-qa, ⛔ não só à spec
«O AVATAR ⛔ NUNCA É O ÚNICO IDENTIFICADOR DA UPA: O NOME DA UNIDADE ESTÁ SEMPRE A UMA LINHA DELE,
**EM TEXTO** … Ecrã que mostre UPA sem o nome escrito = ⛔ NÃO BATE.»
Hoje o ecrã mostra uma bolinha cinzenta e vazia **sem nome visível** ⟹ ⛔ não bate, por regra da casa.
(O nome vai para `md-so-leitor` — `tokens.css:262`, `clip-path: inset(50%)` ⟹ invisível ao olho.
Isso está **certo** quando a UPA é escrita ao lado, em `:204`; mas ela é sempre `null`.)

---

## 4 · PORQUE É QUE ISTO VAI VOLTAR IGUAL — A PROVA DO CARD É CEGA A ESTA FALTA

`frontend/e2e/presencas.spec.ts` tem **2134 linhas** e **⛔ ZERO asserções sobre o nome da UPA**:
- linha 766 — só conta a bolinha: `expect(…'[data-teste="avatar-upa"]').toHaveCount(1)`
- linha 146 — o próprio fixture declara, à letra: «**e sem UPA**»
- linha 54 — e já diz: «(b) ⛔ não há UPA do médico — o `select` é explícito e traz três campos»

🩸 ⟹ **A prova é verde POR CONSTRUÇÃO enquanto o ecrã está errado.** Foi por isso que a falta só
apareceu ao **rev-qa, a olho**, na 7.ª volta — e é por isso que mandar o card de volta ao
especificador/dev **sem tocar no contrato** devolve exactamente o mesmo verde e exactamente a mesma
captura. O que «volta igual» ⛔ não é um conflito: **é esta cegueira da prova somada ao contrato que
⛔ não tem o dado.**

Isto é o travão de não-convergência do achado **#54794** («voltou 7 vezes sem convergir») a dizer
a verdade: 7 voltas, e ⛔ nenhuma delas podia ter resolvido isto, porque a causa está noutro card.

---

## 5 · ⛔ PORQUE É QUE ⛔ NÃO CORRI `integrar juntar CS-100`

Li o verbo (`/srv/fab/bin/integrar`) antes de o chamar. Com o ramo **já ancestral**, ele faria:
1. `git merge --no-ff frente/CS-100` ⟹ *Already up to date*, **⛔ sem criar commit**;
2. procura o merge por **pai-2 = `frente/CS-100`** ⟹ encontra `74c424b7`, **o merge que já existe**;
3. `UPDATE card SET estado='integrado'` e grava evento `integrado` com esse sha.

🩸 ⟹ **Marcaria `reprovado` ⟶ `integrado` sem mover um byte, creditando-se de um merge feito a
02/10, e ENTERRARIA a divergência que o rev-qa mediu.** É o «certificado falso» que a skill nomeia,
agravado: ⛔ não é só um despacho nulo — é **dar por bom um ecrã que ⛔ não bate com a spec nem com a
regra 66**. ⛔ Não o corri, e ⛔ não o deve correr quem vier a seguir **antes de o contrato mudar**.

---

## 6 · ⟹ O QUE DESTRANCA ISTO (⛔ não é trabalho de integrador)

Uma **emenda ao CS-96** (ou um card de backend novo) que ponha a unidade no contrato da folha:
`COM_MEDICO` passa a trazer os vínculos do médico com o nome da UPA, e `aoPublico` devolve-o.
O frontend ⛔ **não precisa de uma linha** — já tolera `upa`, `upa.nome` e `upas[]`.

⚠️ E há **uma pergunta de produto** no caminho, que ⛔ não é minha e ⛔ não se adivinha: um médico
pode estar em **várias** UPAs (regra 44) e os vínculos têm `situacao` (PENDENTE/activo). Logo:
**que unidade(s) mostra a folha de presenças — todas as do médico (a regra 66 diz que três UPAs
carregam três bolinhas), só as activas, ou a unidade relevante ao curso?** Quem emendar o CS-96 tem
de a levantar; o `GrupoDeAvatares` já existe para o caso de várias.

⟹ Em alternativa, e é a outra saída coerente: a spec do CS-100 **deixa de prometer** a UPA — mas
então **a bolinha também tem de sair**, porque a regra 66 proíbe avatar de UPA sem nome escrito.
Qual das duas é **decisão de produto**, ⛔ não de merge.

---

## 7 · RESUMO EM TRÊS LINHAS

1. ⛔ **Não há merge a fazer**: `merge-tree` exit 0, árvore idêntica, card já `integrado` em 02/10.
2. O epic está **verde**: `tsc` 0 erros, **32/32** e2e.
3. O que prende o card é **um contrato que ⛔ nunca foi pedido ao CS-96**, fora do escopo do CS-100
   e invisível à prova dele. ⟹ **Devolvo com a medição**, e ⛔ não forço.
