# As quatro exceções do inventário, lidas

Leitura feita em 28/08/2026. Companheiro escrito à mão de
`inventario-acoes.md`, que é gerado — o gerador classifica por evidência
mecânica; estas quatro precisavam de alguém abrindo o arquivo.

---

## `ConfiguracaoGrupos::novo`, `editar` e `ativarRemover` — MORTA, confirmado

As três são inteiras:

```php
public function novoAction() {
    return $this->notFoundAction()->setTerminal(true);
}
```

**Nunca foram implementadas**, e não é desligamento de algo que existia:

| O que se olhou | O que se viu |
|---|---|
| `CrudController`, a classe-mãe | não define nenhuma das três — é só base de auxiliares |
| `view/is-configuracao/grupos/` | só `index.phtml`; não há `novo` nem `editar` |
| histórico do arquivo | só a importação inicial — nada a datar |
| a própria listagem | **não oferece botão** de novo, editar ou remover |

Ou seja: a tela de grupos de permissão é **de leitura por desenho**, e os três
cotos existem para que a rota curinga não caia em lugar nenhum estranho.

**Como os grupos são administrados então?** Fora do sistema — direto no banco.
São 11 grupos reais e 139 linhas de privilégio, e nada no ERP os edita.

### O susto que não era

A leitura levantou um alarme que vale registrar por ter sido descartado:
**"Gerente geral" tem zero linhas de privilégio e 10 usuários ativos.** Se o
controle de acesso lesse só a tabela `privilegios`, essas dez pessoas não
acessariam nada.

Não é o caso: `grupos.administrador` é o desvio, e **"Gerente geral" é o único
grupo com `administrador = 1`**. Administrador não precisa de linha de
privilégio. Falso alarme, verificado.

### O que isso decide para as Fases 2 e 3

**Não reconstrua as três.** E fica uma pergunta de produto, não de engenharia:
*a nova interface deve permitir administrar grupos de permissão?* Hoje isso é
trabalho de quem tem acesso ao banco. Se a resposta for sim, é
**funcionalidade nova** — não porte —, e é exatamente o tipo de coisa que o
inventário existe para encontrar antes e não durante.

---

## `ConfiguracaoConvenios::atualizarVencimento` — ROTINA órfã

**Esta seção foi reescrita em 28/08/2026**, depois de a regra de negócio ser
informada. A primeira versão tirava a conclusão errada, e o erro fica registrado
porque é exatamente o que a Fase 3 corre o risco de repetir.

```php
public function atualizarVencimentoAction() {
    $convenios = ...->selecionarConvenios();
    if (!empty($convenios)) { $service->atualizarVencimento($convenios); }
    die("FIM");
}
```

Marca convênios cuja data de contrato já passou. É rotina de manutenção, não
tela: sem view, terminando em `die`, alcançável por URL só porque o módulo tem
rota curinga.

**Ninguém a agenda.** Não está nas 25 entradas do crontab de produção, e nada no
sistema a referencia. Mesma classe do **D43**.

### A regra do negócio, que muda a leitura

> O convênio tem data de vencimento, mas **a vigência segue até que alguma parte
> cancele**.

A data é referência comercial, não corte automático.

**Com isso, o sistema está certo.** Eu havia seguido o caminho da venda esperando
encontrar desconto indevido, e escrito que a regra "contrato vencido para o
desconto" nunca fora implementada. Ela não existe — não há o que implementar.
`VendaProdutoService` decide por `status`, tipo do produto e unidade/dia da
semana, e **não** consultar `contratoVencido` é o comportamento correto.

Os **R$ 649,50** concedidos em 36 vendas nos últimos 12 meses por convênios com
data ultrapassada não são vazamento: são desconto legítimo sob contratos em
vigor.

### O defeito que resta é de acompanhamento comercial

| | |
|---|---:|
| Convênios ativos | 616 |
| Com data de contrato ultrapassada | **18** |
| Marcados pela rotina | **0** |
| O mais antigo, ultrapassado há | **1.933 dias** |

O único consumidor do sinalizador é o **filtro da listagem**. Como nada nunca
marca ninguém, filtrar por "contrato vencido" devolve **lista vazia** — e quem
procura contratos a renovar conclui que está tudo em dia, quando há 18 para
revisitar.

Relatório que erra para menos é pior que relatório que não existe: o que não
existe manda perguntar; o que mente responde.

### O risco vai na direção contrária da intuição

**É o achado mais importante desta leitura**, e ele só apareceu depois da
correção.

Olhando só o código, `contratoVencido` parece um controle de validade que alguém
esqueceu de ligar — foi exatamente a minha primeira leitura. **Um desenvolvedor
reconstruindo a tela tende a "consertar" isso**, ligando o sinalizador ao
desconto.

Isso quebraria a regra: cancelaria o desconto de 18 convênios **em vigor**, e de
todos os que passassem da data dali em diante. Sem ninguém decidir, e com
aparência de correção de bug.

**O nome é a armadilha.** `contrato_vencido` lê-se como validade; significa
"passou da data de referência, vale revisitar".

### O que isso decide para as Fases 2 e 3

1. **Não vira tela** — vira rotina agendada, junto com as outras da F1.6.
2. **Renomear** na API e no schema novo: `contrato_a_renovar` ou
   `contrato_data_ultrapassada`. Nome que descreve o estado não convida a ser
   ligado ao preço.
3. **Documentar a regra junto do campo.** A próxima pessoa não deve precisar
   perguntar — e, se precisar e não perguntar, vai "consertar".

Ver **D50**.

---

## Resumo

| Ação | Veredito | Decisão que falta |
|---|---|---|
| `Grupos::novo` | não reconstruir | a nova interface deve administrar grupos? |
| `Grupos::editar` | não reconstruir | idem |
| `Grupos::ativarRemover` | não reconstruir | idem |
| `Convenios::atualizarVencimento` | não vira tela; agendar e **renomear** | nenhuma — a regra está clara: vigência até cancelamento. Ver **D50** |
