O booleano active não diz quem desativou, nem quando¶
Registrado em 2026-09-18, ao derivar o modelo de dados. Não é defeito — nada está errado hoje. É uma divergência de padrão que cobra o preço no dia em que alguém perguntar.
O que existe¶
Duas tabelas guardam "isto está ligado?" como booleano:
| Tabela | Coluna | Onde |
|---|---|---|
tool_credentials |
active |
lib/the_band/sources/tool_credential.ex:33 |
issue_mapping_rules |
active |
priv/repo/migrations/20260811200000_create_issue_mapping_rules.exs:48 |
E nove tabelas guardam a mesma ideia como data mais autor — revoked_at e
revoked_by_user_id —, entre elas as três da feature 066. A máquina delas está em
docs/modelos/estados/declaracao-revogavel.md.
O que o booleano não responde¶
Um booleano responde "está ligado?" e nada mais. As três perguntas que ele perde:
- quem desligou — e numa credencial de ferramenta isso é pergunta de segurança, não de curiosidade;
- quando — sem instante não há linha do tempo, e "a coleta parou em algum momento de agosto" não se investiga;
- se já foi religado antes — o booleano guarda o estado atual e apaga a história. Uma credencial que caiu três vezes conta a mesma coisa que uma que nunca caiu.
É o mesmo argumento que a casa já aplica em issue_promotions, onde o comentário diz que um
booleano "responderia à primeira metade e perderia a segunda"
(lib/the_band/ontology/seon/spo/projects.ex:164).
Por que isto NÃO foi consertado junto com as chaves estrangeiras¶
As duas correções vieram do mesmo levantamento, e só uma entrou no PR das chaves. A diferença é o custo:
| chave estrangeira ausente | booleano active |
|
|---|---|---|
| mudança | ALTER TABLE, aditiva |
migração de dados mais todo leitor |
| leitores a mudar | nenhum | toda consulta que filtra active |
| valor hoje | o banco passa a impedir o que só a aplicação impedia | nenhum, até alguém auditar |
| risco de adiar | cresce com cada caminho de escrita novo | nenhum — o dado atual não se perde |
Trocar booleano por data e autor não recupera o que já foi perdido: as desativações passadas não têm autor nem instante em lugar nenhum, e a migração escreveria nulo nas duas colunas. Ganha-se dali para frente.
O que fazer, quando for a hora¶
- acrescentar
revoked_aterevoked_by_user_id, nulos; - preencher
revoked_atdas linhas comactive = falsecom nulo, não com uma data inventada — e escrever na migração que a ausência é a resposta honesta para o que não foi registrado; - trocar os leitores de
activeporis_nil(revoked_at); - remover
activenuma migração posterior, depois de a suíte passar sem ele.
O passo 4 é o único destrutivo, e por isso fica sozinho.
O gatilho¶
Não é uma data. É a próxima vez que uma dessas duas tabelas for mexida por outro motivo, ou a primeira vez que alguém perguntar "quem desativou esta credencial?" e a plataforma não puder responder.