# Demanda 14 — enquadramento da FATIA 1 (base + aula ao vivo)

> ## ✅ ENTREGUE EM 25/09 — ⛔ NÃO REENQUADRE, ⛔ NÃO REMEÇA, ⛔ NÃO ENTREGUE OUTRA VEZ.
> O dono respondeu ao **pedido 35** em 25/09 01:38, literal: **«CS»**. O 8.º enquadrador trocou
> `SIGLA-` por `CS-` e entregou:
> **`fab enquadrar 14 --chave CS-1` → demanda 14 em `a_aprovar` · 21 cards (CS-2..CS-22) · pedido 47
> na fila do dono.** O aviso SAIU (texto 3 311 bytes, medido ANTES contra o tecto do Telegram que
> engoliu o aviso da demanda 13 — `fabdono.py` ⛔ não imprimiu «O DONO ⛔ NÃO FOI AVISADO»).
>
> O que o 8.º remediu por si, com comandos e ⛔ não por leitura do que os outros escreveram:
> 21 chaves únicas · 0 órfãos · 0 ciclos · 0 cercas largas · papel para `infra`, `backend` e
> `frontend` em `/srv/fab/papeis/` · 0 resíduo da direcção morta (ladrilho/junta/Alegreya/FNV) ·
> **96 aceites corridos um a um na base: 96 falham, 0 passam.**
>
> ⏭️ O QUE SE SEGUE: o dono aprova o pedido 47 e os cards nascem. ⛔ Nada mais há a fazer aqui.
>
> ⚠️ OBSERVAÇÃO PARA QUEM ESPECIFICAR O `CS-22`: o **pedido 44** está ABERTO na fila do dono e é
> sobre a cara do produto (cor oficial da Secretaria · cor por UPA no avatar · de onde vêm as
> fotografias). ⛔ Não bloqueia o enquadramento e ⛔ não bloqueia card nenhum de backend: as regras
> 80, 83 e 86 já fixam o caso conservador (azul #0F61A4 · todas as UPAs em secondaryContainer ·
> a estrutura degrada sem foto). Se ele responder, troca-se a cor-fonte e a paleta regenera-se
> sozinha — ⛔ não se refaz ecrã nenhum.


**21 cards · 1 infra · 10 backend · 10 frontend.** Cards em `ENQUADRAMENTO-D14.cards.json`.
Escrito por um 1.º enquadrador, corrigido pelo 2.º, conferido pelo 3.º, e o 4.º acrescentou o `-22`
(a cara do produto, aprovada DEPOIS destes cards nascerem) — ver a secção final.
Re-verificado e CORRIGIDO em 24/09 por um segundo enquadrador, contra a máquina a correr.

✅ **O prefixo `SIGLA-` já foi trocado.** O rastreador ⛔ não tinha espaço de chaves para este
produto (medido no pedido 35: 2 projectos, 142 questões, zero acertos em «Capacita»), e a sigla
⛔ não se improvisa (precedente: regra 3 do maisSaúde). O dono deu-a em 25/09 — **CS** — e os
cards entregues são `CS-2..CS-22` sob o epic `CS-1`. ⚠️ Criar o projecto no Jira é acto no espaço
dele e ⛔ a fábrica ⛔ não o cria: quando ele o criar, as chaves já estão nesta forma.

## O chão técnico ⛔ NÃO foi escolhido por gosto — está MEDIDO
`/srv/fab/bin/instanciadeclara.py:131-139` **crava** a forma de um produto desta casa a correr:

| lado | o que a casa executa | saúde |
|---|---|---|
| `backend/` | `npx prisma migrate deploy && npm run build && node dist/main` | `GET /api/v1/health` → 200 |
| `frontend/` | `npm run dev -- -H 0.0.0.0 -p <porta>` | `GET /` → 200 |

⟹ backend **Nest + Prisma**, frontend **Next**, prefixo **`/api/v1`**. Fora disto o epic ⛔ não tem
instância, e sem instância ⛔ nenhum dos seis factos do critério se exerce.

### AS QUATRO CORRECÇÕES desta revisão (cada uma medida hoje, nesta máquina)

**1 · ⛔ NÃO se versiona `backend/.env` — e isto protege a regra 42.**
`bin/obra:175` chama `bin/banco criar` **se e só se** `backend/.env` existir. E `bin/banco:31-41`
é **SQL Server puro**: procura `sqlcmd` e, se não o achar, escolhe *qualquer contentor cujo nome ou
imagem contenha «sql»* — nesta máquina isso é **`maissaude-sqlserver`**. Um `.env` de Postgres no
Capacita levaria a fábrica a apontar o banco deste produto ao contentor do maisSaúde, que é
exactamente o que a regra 42 do dono proíbe («bancos diferentes, máquinas diferentes»).
⟹ O produto ⛔ não traz `.env`; traz `.env.example`. Sem `.env`, `bin/portao:274` dá **P3b verde**
(«produto sem migrações a conferir») e ⛔ nada se parte. O aceite 4 do `SIGLA-3` impõe-o.

**2 · O isolamento de banco por card é do PRODUTO, porque o da casa ⛔ não serve Postgres.**
Consequência da nº 1: `bin/banco` (um banco por card, contra vizinho a escrever por cima) ⛔ não
funciona aqui. ⟹ `SIGLA-2` entrega `scripts/banco-teste.sh <nome>`, idempotente, que cria o banco
e **imprime o `DATABASE_URL`**; `SIGLA-3` entrega `backend/test/ambiente.ts` (globalSetup do jest)
que deriva o nome do banco **do worktree onde corre** e aplica `migrate deploy` antes dos testes.
Assim dois cards em paralelo ⛔ nunca se pisam, e ⛔ nenhum aceite precisa de `DATABASE_URL` no
ambiente — que é o defeito #1605, ainda ABERTO, do portão.
**MEDIDO AGORA, e não deduzido:** `postgres:16-alpine` sobe em contentor com a porta publicada em
`127.0.0.1:55432` (⛔ não em 0.0.0.0, que o classificador barra), o host alcança-a por TCP, e
`CREATE DATABASE` responde. A medição foi desmontada sem deixar vestígio.

**3 · `@playwright/test` fica PRESO em `1.60.0`.** É a versão cujo chromium (build **1223**) está
em `/root/.cache/ms-playwright`. Qualquer outra manda o dev descarregar um browser. Aceite 2 do
`SIGLA-13` mede-o no `package.json`.

**4 · ⛔ `npm install` NÃO entra em aceite de card que não seja alicerce.** O P5 corre cada aceite
**na base** com tecto de **600 s** (`portaop5.py`) e trata estouro como **MUDO** — que ⛔ não conta
como prova e reprova o card. Instalar é trabalho do dev no seu worktree, ⛔ não aceite.

## Os seis factos do critério → onde se exercem

| facto do critério de pronto | cards que o fecham |
|---|---|
| (1) 3 UPAs · link · CRM · 2 de 3 UPAs | `-5` `-6` · ecrãs `-14` `-15` |
| (2) pendente ⟹ 0 aulas, 0 calendário | `-4` `-8` · ecrã `-17` |
| (3) só o coordenador da UPA escolhida aceita/tira; o da UPA C ⛔ não | `-7` · ecrã `-16` |
| (4) aula 80 min · S1 escreve 4 questões · troca para S2 · as 4 ficam | `-8` `-9` · ecrãs `-18` `-19` |
| (5) 60 min validados · 3·X · +2·Y · bloco mudo = 0 · errar ⛔ não tira | `-10` `-11` · ecrã `-20` |
| (6) dias=7 abre ao 7.º e ⛔ não ao 8.º · barra ⛔ não avança · aba sem foco ⟹ pára | `-12` · ecrã `-21` |

⚠️ **O 7.º/8.º dia prova-se com DATAS SEMEADAS, ⛔ não com relógio injectável nem `sleep`.**
A aula fica com o fim 7 (ou 8) dias no passado e o teste lê a janela. Assim ⛔ não se abre porta de
tempo falso no código de produção — e o aceite 5 do `SIGLA-12` reprova se aparecer `setTimeout`.

## O que cada teste dirigido TEM de afirmar (para o especificador)
Os títulos citados nos aceites `-t`/`-g` **são contrato**: o aceite só passa se existir um teste com
aquele título e ele passar.

- **`-3` alicerce** — build → `dist/main.js`; `/api/v1/health` = 200; o banco do worktree é só dele.
- **`-4` identidade** — os quatro papéis (regra 55); médico nasce `pendente`; papel de fora ⟹ 403.
- **`-5` UPA** — só a **secretaria** cria/edita/tira (coordenador e médico ⟹ 403); cada UPA tem
  **um** coordenador e **um** token de link só dela.
- **`-6` cadastro** — link válido ⟹ médico com CRM e **N UPAs** em `pendente`; link inválido ⟹ 404;
  ⛔ zero consulta a cadastro de fora (regra 42: o CRM é **declarado**, conferido por pessoa).
- **`-7` vínculo** — o da UPA A aceita e tira; o da UPA C ⟹ **403** nas duas acções.
- **`-8` aula** — só a secretaria cadastra e troca; `duracao_min / 20` = nº de blocos (80 ⟹ 4);
  calendário: médico `ativo` vê, `pendente` vê **0**. A aula guarda só um **link** de transmissão
  que a secretaria escreve — ⛔ nenhuma integração com ferramenta de vídeo nesta fatia.
- **`-9` questões** — só o responsável escreve; o nº **segue a duração** (40 min recusa a 3.ª);
  depois da troca S1→S2 as questões têm **o mesmo id e o mesmo texto**.
- **`-10` parâmetros** — a secretaria muda X, Y, `dias_gravacao` e o multiplicador **sem reiniciar**;
  coordenador e médico ⟹ 403; há omissões gravadas.
- **`-11` participação** — responder valida **retroactivamente** os 20 min do bloco; 3 de 4 ⟹ **60**
  minutos; bloco mudo ⟹ **0** minutos e **0** pontos; respondeu ⟹ X, acertou ⟹ X+Y; **errar fica
  com X** e ⛔ não perde nada; mudar X no `-10` **muda o ponto** (prova de que é parâmetro); e os
  minutos validados **ficam guardados e legíveis depois da aula** — é o que o ranking vai somar.
- **`-12` gravação** — dias **por aula** com omissão global; com 7 abre ao 7.º, ⛔ não ao 8.º;
  pendente ⛔ não abre. A gravada **⛔ não pontua nesta fatia** (decisões 3 e 4 do quadro precisam da
  tabela de pontos do ranking, que é outra fatia): aqui só **abre** ou **⛔ não abre**.
- **`-20` sala** — a pergunta do bloco aparece e fecha; o fim mostra **60 min** contáveis.
- **`-21` leitor** — arrastar a barra à frente ⛔ não muda o tempo; `visibilitychange: hidden`
  **pára** o relógio; ao 8.º dia ⛔ não abre.

## Porque é que a cerca do backend leva `backend/prisma/` e `app.module.ts`
O Prisma tem **um** `schema.prisma` e o Nest **um** `app.module.ts`: card que traz tabela nova ⛔ não
existe sem lhes tocar. A cerca continua estreita — `backend/src/modules/<x>/` **mais dois ficheiros
nomeados**, ⛔ nunca `backend/src`. ⚠️ Cada card **acrescenta** os seus modelos no FIM do
`schema.prisma` e traz a **sua** migração com data própria; ramos irmãos que colidam resolvem-se
trazendo o epic para dentro, que é o que o P1 já exige.

## O que ⛔ NÃO é card, e porquê
- **Endereço para o dono ver** (`*.dev.caedr.ai`): a regra 59 mede que escrever em
  `/etc/caddy/fabrica/*.caddy` é **barrado ao agente**. Card que ⛔ não pode passar ⛔ não nasce;
  é ida ao humano, uma linha, quando houver o que mostrar.
- **Pontuação da gravada, ranking, decaimento**: outra fatia (regras 43, 50).

## FORA desta fatia, de propósito
Gravadas permanentes · artigos em destaque · protocolos municipais · cursos presenciais ·
certificados · **o ranking** · qualquer ligação ao maisSaúde (regra 42).

## O que espera, e por quem
1. **Pedido 35 (dono)** — a sigla. Sem ela ⛔ não há `fab enquadrar`. Bloqueia os 20.
2. **Pedido 39 (dono)** — as três direcções de design. `_produto/design/design.md` está em
   `status: por_definir`, e `bin/motordesign.py:59-63` **trava os 9 cards de frontend** até
   `aprovado`. ⛔ Não é defeito: é a trava a funcionar. Os 11 de infra+backend ⛔ não dependem dela.

---

## CONFERÊNCIA DO 3.º ENQUADRADOR — 24/09, e ⛔ NÃO se repete uma quarta vez

⚠️ **⛔ NÃO reescrevi os 20 cards.** Li-os, medi-os e **passam**. Enquadrar de novo o que já está
enquadrado é o «procedimento que cada agente reinventa e cada agente paga outra vez». O que faltava
⛔ não era trabalho de enquadrador — era **uma palavra do dono**. Fica aqui o que medi, para que o
próximo ⛔ não gaste sessão a remedir.

### 1 · O JSON dos 20 cards está estruturalmente válido (medido, ⛔ não lido)
| o que se mediu | resultado |
|---|---|
| 20 chaves, todas únicas | ✅ |
| territórios: 1 infra · 10 backend · 9 frontend | ✅ |
| **papel existe para cada território** (`/srv/fab/papeis/<t>-dev.md`) — é o que `fabdono.py:38` exige | ✅ infra · backend · frontend |
| dependências órfãs (apontam a card que ⛔ não existe) | ✅ **zero** |
| ciclo no grafo de dependências | ✅ **nenhum** |
| cerca larga (`backend/src`, `frontend/src`, `backend`, `frontend`) | ✅ **nenhuma** |
| aceite que seja **frase** e ⛔ não comando | ✅ **nenhum** — os 84 são executáveis |
| um card = um território | ✅ (backend e frontend são **sempre** cards separados, com dependência declarada) |

### 2 · 🩸 O MEDO DO «ACEITE DE REGRESSÃO» É INFUNDADO — medido no código do portão
Cada card traz, no fim, um aceite que **recorre o spec do pai** (ex.: `-11` corre
`test/questao.e2e-spec.ts`, que é do `-9`). Isso **parece** violar «aceite que não falha hoje não
mede nada», porque o pai já está na base quando o filho nasce. **⛔ Não viola.**
`portaop5.py:60-78`, lido hoje: o P5 divide os aceites em **sensível · vácuo · MUDO** e só reprova
**se `not sensiveis`** — ou seja, basta **UM** aceite que falhe na base. E a mensagem do verde diz
textualmente *«os outros N são de regressão, e isso é legítimo»*.
⟹ Os aceites de regressão destes cards são **legítimos e desejados**. ⛔ Ninguém os tire para
«cumprir a regra»: cada card tem 2 a 6 aceites próprios que falham na base sem ele.

### 3 · Os dois `escopo_paths` partilhados são inevitáveis, e o P1 já os resolve
`backend/prisma/` e `backend/src/app.module.ts` estão na cerca dos 10 cards de backend — o Prisma tem
**um** schema e o Nest **um** módulo raiz. Medido: são os **únicos** dois paths partilhados; todo o
resto é `modules/<x>/` exclusivo. ⚠️ `-8` e `-10` (ambos filhos de `-4`) podem correr **em paralelo**
e colidir nesses dois ficheiros: resolve-se trazendo o epic para dentro, que é o que o P1 já exige.

### 4 · O rastreador: medido OUTRA VEZ, por outra porta, e dá o mesmo
Jira `mais-saude-salvador` → `GET /rest/api/3/myself` devolve **401**. A rede alcança; **esta sessão
⛔ não tem credencial** e ⛔ não há ficheiro de credencial em `/root` nem em `/srv/fab`. Somando à
varredura das 142 questões do pedido 35 (**zero** acertos a «Capacita»): ⛔ **não existe espaço de
chaves para este produto, e ⛔ nenhum agente desta casa o pode criar.**
⟹ `fab enquadrar` aceita qualquer `--chave` (⛔ não valida contra rastreador nenhum, `fabdono.py:32`).
**É precisamente por isso que ⛔ não se improvisa**: o verbo ⛔ não me impede — a regra impede.

### 5 · As duas travas estão **ambas** na fila dele, e ⛔ nenhuma é defeito
- **Pedido 35** (21:02) — a sigla. Trava os **20**.
- **Pedido 39** (22:52) — as três direcções de design. `design.md` está em `status: por_definir` e
  `motordesign.py:59-63` trava os **9 de frontend** até `aprovado`. Os 11 de infra+backend ⛔ não.
⟹ ⛔ Nenhuma é `fab achado`: o mecanismo ⛔ não está quebrado, está a **funcionar** — são decisões
do dono a caminho. ⛔ Não voltei a perguntar nem uma nem outra: duplicar pedido é sujar a fila dele,
que é a medida de saúde desta casa.

### 6 · ⚠️ O pedido 34 está VENCIDO e ainda ocupa a fila
O 34 pergunta «o que entra na primeira versão». A **regra 58** já responde — *«concordo com base +
ao vivo primeiro»*, dito por ele às 21:4x, **depois** do pedido 34 (20:14). ⟹ O 34 ⛔ não precisa de
resposta; está respondido por regra posterior. ⛔ Não há verbo de agente para o fechar — quem puder,
feche-o, para ele ⛔ não gastar atenção a responder ao que já respondeu.

### 7 · Entregar, quando a palavra chegar — UM comando
```
bash /srv/produtos/capacitasalvador/escopo/ENTREGAR-D14.sh <SIGLA>
```
Conferido hoje: valida a sigla, troca `SIGLA-` pela dele, valida o JSON e chama
`fab enquadrar 14 --chave <SIGLA>-1`. ⛔ Sem argumento ⛔ não faz nada. É o caminho certo.

---

## 4.º ENQUADRADOR — 24/09: ⛔ NÃO reescrevi nada. ACRESCENTEI UM CARD, e digo porquê.

⚠️ **Os 20 cards continuam de pé.** Re-medi-os sozinho (⛔ não li o veredito do 3.º antes de medir):
21 chaves únicas · zero órfãos · zero ciclos · zero cercas largas · papel existe para os três
territórios · ⛔ nenhum aceite é frase. **Passam.** ⛔ Não os toquei.

### O que MUDOU desde o 3.º enquadrador, e obrigava a mexer
**O pedido 39 foi RESPONDIDO.** `_produto/design/design.md` está agora em `status: aprovado`,
`versao: 1`, direcção **B — LADRILHO** (regra 62), e daí nasceram as **regras 63 a 68**. ⟹ A trava
do `motordesign.py:59-63` sobre os 9 cards de frontend **CAIU**. Os 20 cards foram escritos às
**22:44**; o design foi aprovado às **~23:02**. ⟹ Foram escritos **antes de a cara existir**.

**MEDIDO, ⛔ não deduzido:** `grep -ci ladrilho ENQUADRAMENTO-D14.cards.json` → **0**.
A palavra «ladrilho» ⛔ **não aparece uma única vez** nos 20 cards. Nem «token», nem «azulejo», nem
«junta», nem «Archivo». ⟹ **⛔ Nenhum card era dono da cara do produto.**

### Porque é que isso ⛔ NÃO podia ficar assim
A regra 67 põe **A MARCA DA UPA** na página de cadastro, em **cada linha de médico**, em cada dia
com aula do calendário e no cabeçalho de todo o ecrã filtrado por UPA — ou seja, **em 8 dos 9 ecrãs**.
E exige que seja **determinística**: «a mesma UPA dá SEMPRE o mesmo ladrilho». Sem um card que a
possua, **8 devs de frontend inventam 8 ladrilhos diferentes** e a promessa morre. Pior: a regra 67e
diz «ecrã que mostre UPA sem a marca = ⛔ NÃO BATE» e a 63.1 diz «⛔ nenhum hex solto» — ⟹ os 8 ecrãs
iam ao `rev-design` **reprovar um a um**. Uma volta de QA agora custa menos do que oito reprovações.

### O card do sistema de interface — REESCRITO em 25/09 (5.ª passagem)
🩸 **O `-22` que aqui estava era da direcção MORTA.** Medido, e ⛔ não deduzido: o 4.º enquadrador
escreveu-o às **23:55** sobre a direcção B («ladrilho» — seis tokens, junta de 2px, virada,
marca-ladrilho 4x4); a **regra 79** matou essa direcção às **00:35:41**, com a palavra literal do
dono — «substitui». O card sobreviveu **40 minutos** à direcção que o justificava.

⚠️ E ⛔ não era só o título: **dois aceites dele PROIBIAM o que as regras novas EXIGEM** —
`! grep -rniE 'border-radius|box-shadow'` contra a regra 81, que manda **cartão 12dp, botão pilula
e cinco níveis de sombra do M3**; e a contagem `= 6` de `--cor-*` contra a regra 80, que tem **~25
papéis de cor calculados** pela `@material/material-color-utilities`. Entregue assim, os 8 ecrãs
nasciam contra a cara aprovada e o `rev-design` reprovava-os **um a um**.

**`SIGLA-22` [frontend] — O sistema de interface: Material 3 com Inter, os tokens calculados, os
SEIS ESTADOS, a fita dos blocos de 20 min e o chip+avatar da UPA (regras 79 a 86).**
Depende de `SIGLA-13`; os **8 ecrãs** (`-14`…`-21`) continuam a depender de **`-22`**. Total:
**21 cards** · 1 infra · 10 backend · 10 frontend. ⛔ Nenhum outro card foi tocado no conteúdo.

O que mudou dentro dele, linha a linha e cada uma com regra atrás:
- **cerca** `frontend/src/componentes/ladrilho/` → `frontend/src/componentes/base/`; `e2e/ladrilho.spec.ts`
  → `e2e/sistema.spec.ts`. O ladrilho ⛔ não existe (regra 83b: aparecer num ecrã = ⛔ NÃO BATE).
- **cor** — os 6 planos da direcção B saem; entram os hexes **calculados** que a regra 80 fixa, e o
  aceite mede três deles: `#0F61A4` (primary), `#006C52` (validado), `#7C5800` (espera). ⛔ Nenhum
  agente escreveu um hex: saíram da biblioteca oficial do M3.
- **forma** — cai o `! grep 'border-radius|box-shadow'`. Nesta direcção **quase tudo arredonda e há
  sombra** (regra 81).
- **tipografia** — `Inter` e `tabular-nums` passam a ser aceite. O produto é uma coluna de números a
  ser comparada (regras 48 e 50), e a regra 85 põe o tabular como **obrigatório sem excepção**.
- **os SEIS ESTADOS** e a **fita dos 20 minutos** entram como aceite executável (regra 84), com o
  **bloco perdido VAZADO e sem a cor de erro** — errar ⛔ não tira pontos (regra 56), e ⛔ não há
  castigo na cara deste produto. E `! grep '<progress|LinearProgress'`: **uma barra lisa mente ao
  médico**.
- **a UPA** — a marca-ladrilho 4x4 sai; entra o **monograma derivado dos dados** (regra 83),
  `UPA San Martin` → `SM`, e **UPA por carregar fica sem letras** — ⛔ não se inventa monograma.
- **movimento** — `prefers-reduced-motion: reduce` continua aceite, agora com **o mesmo pixel** no
  estado final, que é o que a regra 82 exige.

⚠️ **A cerca do `-13` foi estreitada de passagem**: tinha `frontend/src/componentes/` **inteiro**,
que é cerca larga e **colidia** com a do `-22`. Passou a `frontend/src/componentes/casca/`. Uma
cerca larga ⛔ não protege ninguém.

### Os 96 aceites dos 21 cards foram corridos NA BASE, e os 96 falham
🩸 A armadilha real é o aceite **negativo**: `! grep ...` num repo **vazio** **PASSA** — ⛔ não mede
nada, e é exactamente o que o portão reprova. Por isso **cada** verificação negativa leva à frente
uma **guarda positiva** (`test -f .../tokens.css && ...`), que ⛔ não existe na base. Corrido hoje
no repo (1 commit, 0 ficheiros): **96 de 96 falham**. ✅ E o grafo foi conferido: ⛔ sem ciclo, ⛔ sem
pai inexistente, ⛔ sem cerca larga, e os 3 territórios têm papel em `/srv/fab/papeis/`.

⚠️ **A trava do design CAIU, e ⛔ não é notícia velha:** `_produto/design/design.md` está em
`status: aprovado` (v2, «LearnUp» + Material 3, regra 79). ⟹ `motordesign.py` ⛔ já **não** trava
os 10 cards de frontend. Quando a sigla chegar, nascem os 21 sem nenhuma trava de design.

### O que espera, e ⛔ é UMA coisa só
**Pedido 35 (dono) — A SIGLA.** ⛔ Continua ABERTO. Medido **outra vez, hoje, por mim**: a rede desta
máquina está boa (`api.github.com` → **200**), mas o Jira `mais-saude-salvador` **estoura o tempo**
(`curl` exit **124**) e ⛔ não há credencial nesta sessão. `fab enquadrar` aceita **qualquer**
`--chave` (`fabdono.py:32` ⛔ não valida contra rastreador nenhum) — **é precisamente por isso que
⛔ não se improvisa: o verbo ⛔ não me impede, a regra impede.**

⛔ **⛔ NÃO abri pedido novo** (o 35 já pergunta isto — duplicar suja a fila dele) e ⛔ **não abri
`fab achado`** (⛔ nada está partido: é uma decisão dele a caminho, e o mecanismo está a funcionar).
Usei `fab avisar`, que informa e ⛔ não pede.

### Entregar, quando a palavra chegar — UM comando, e já conferido com 21 cards
```
bash /srv/produtos/capacitasalvador/escopo/ENTREGAR-D14.sh <SIGLA>
```

---

## 6.º ENQUADRADOR — 25/09: ⛔ NÃO TOQUEI EM NADA. Medi, e acrescento UM facto novo.

⚠️ **⛔ Não reescrevi, ⛔ não reenquadrei, ⛔ não acrescentei card.** Os 21 passam. Enquadrar de
novo o que já está enquadrado é o defeito que esta casa mede — e já foi pago cinco vezes.
Fica aqui o que **corri**, para o 7.º ⛔ não gastar sessão a remedir.

### O que medi sozinho (comandos, ⛔ não leitura do veredito anterior)
| medição | resultado |
|---|---|
| 21 chaves únicas · 1 infra · 10 backend · 10 frontend | ✅ |
| papel em `/srv/fab/papeis/<t>-dev.md` para os 3 territórios | ✅ |
| dependências órfãs · ciclos no grafo | ✅ **zero** · **zero** |
| cerca larga (`backend/src`, `frontend/src`, `backend`, `frontend`, `src`, `.`) | ✅ **zero** |
| `escopo_paths` partilhados | **2**, e só: `backend/prisma/` e `backend/src/app.module.ts` |
| **os 96 aceites corridos NA BASE** (repo a 1 commit, 0 ficheiros) | 🩸 **0 passaram · 96 falham** |
| resíduo da direcção MORTA (`ladrilho\|azulejo\|junta\|Archivo\|Alegreya\|FNV`) | ✅ **0 acertos** |
| direcção VIVA presente no `-22` (Material 3 · Inter · tabular · monograma · `#0F61A4` · reduced-motion) | ✅ os 6 |
| `_produto/design/design.md` | `status: aprovado`, `versao: 2` ⟹ **a trava do `motordesign` CAIU** |
| `ENTREGAR-D14.sh` sem argumento / com sigla inválida | ✅ recusa nos dois casos |

### 🩸 O FACTO NOVO, que as cinco passagens anteriores ⛔ não tinham
Mediram o Jira **do maisSaúde**. Eu medi também **um site próprio** para este produto:

```
api.github.com                                    -> 200   (a rede está boa)
mais-saude-salvador.atlassian.net/rest/api/3/myself -> 401  (existe; esta sessão ⛔ não tem credencial)
capacitasalvador.atlassian.net/rest/api/3/myself    -> 404  (⛔ NÃO existe site próprio)
```
⟹ O 404 **fecha a última hipótese** de haver espaço de chaves em algum lado: ⛔ não há, nem no
projecto do maisSaúde (142 questões varridas, zero acertos a «Capacita» — pedido 35) nem num site
dedicado. ⟹ A sigla ⛔ **não é** coisa que um agente possa medir, descobrir ou deduzir: é **acto no
espaço do dono**. `fab enquadrar` aceitava qualquer `--chave` (`fabdono.py:32` ⛔ não valida contra
rastreador) — **o verbo ⛔ não me impede; a regra impede.**

### ⛔ O que ⛔ NÃO fiz, e porquê
- **⛔ Não abri pedido.** O **35** já pergunta exactamente isto, aberto desde 24/09 21:02. Duplicar
  suja a fila dele, que é a medida de saúde desta casa.
- **⛔ Não abri `fab achado`.** ⛔ Nada da fábrica está partido: o portão corre, o verbo aceita, a
  trava do design caiu sozinha quando o dono respondeu. Isto é **uma decisão dele a caminho**, ⛔ não
  um defeito de mecanismo — e 91% dos achados desta casa foram escritos por quem ⛔ não estava
  bloqueado pelo mecanismo.
- **⛔ Não improvisei a chave**, que era a única forma de «entregar hoje» e a única que estragava
  para sempre — a sigla fica nas chaves, no ramo e em cada commit.
- Usei **`fab avisar`** (informa, ⛔ não entra na fila de decisão: `fabdono.py:146-155`).

### ⚠️ OBSERVAÇÕES para quem vier (⛔ não são achados: ⛔ nada disto me impediu)
1. **O pedido 35 diz «os 20 cards»; são 21** desde a 5.ª passagem (`-22`, o sistema de interface).
   ⛔ Não se edita pedido já na fila; fica dito aqui e foi dito por aviso.
2. **O pedido 34 continua VENCIDO na fila** — respondido pela regra 58 posterior. ⛔ Não há verbo de
   agente para o fechar. Quem puder, feche-o.
3. **O pedido 44 (a cara: cor da Secretaria, cor por UPA, de onde vêm as fotos) ⛔ NÃO trava esta
   demanda** — di-lo ele próprio, e a regra 86 trava 3 manda o cartão degradar sem foto. ⟹ A v1 sai
   sem uma única fotografia, e o `-22` ⛔ não espera por ele.
4. **Sujidade minha, registada em vez de escondida:** às 01:06 saiu um `aviso` com o texto `--help`
   — fui eu a descobrir a assinatura do verbo. ⛔ `fab avisar --help` ⛔ não imprime ajuda: **avisa**,
   e notifica o dono. Quem vier, leia `fabdono.py:146` em vez de perguntar ao verbo.
