Registro BRB
Os achados BRB-NNN são levantados e priorizados no vault do mantenedor
(07-backlog/Backlog de Melhorias (Brabo)), que guarda os 33 com prioridade,
esforço, origem, proposta e um "pronto quando". Aquele registro é a fonte do
que um achado é e de se ele está fechado.
Este arquivo é a parte que o repositório consegue verificar. Criado pela FASE 29, sessão 1 (fase-29-instalacao-de-uma-linha.md).
Critério de cobertura
Todo id de BRB-001 a BRB-033 tem exatamente uma linha, em ordem
numérica. Até 2026-09-27 a página listava só os achados que o código podia
provar ou refutar — 11 de 33 — e o resto era invisível aqui, inclusive seis que
o vault já tinha medido como corrigidos (AT-186). Uma linha por id não custa
nada e torna a ausência de evidência visível em vez de silenciosa. Cada linha
traz:
- estado no vault — copiado do registro do vault em 2026-09-27. É decisão do mantenedor e nunca é decidido aqui.
- medido aqui — o que o repositório mostra, medido contra a
devem34c1c83bdcem 2026-09-27, salvo quando a evidência data de outro modo. - evidência — o
arquivo:linha, PR ou execução por trás dessa medição.
Um achado cujo assunto mora fora deste repositório (as próprias notas do vault,
uma decisão de produto, uma credencial paga) ainda ganha linha, marcada
não verificável aqui, com o motivo. Um id sem informação nenhuma levaria um
TODO(humano) — nenhum leva hoje. Um BRB-NNN novo no vault ganha a linha
dele aqui na mesma mudança que o mencionar pela primeira vez.
Por que este arquivo existe
BRB-018 é a cara da segunda regra abaixo na prática. Quando este arquivo
nasceu nada nele tinha mudado no código — nenhuma reprojeção tinha sido
escrita —, mas o repositório ganhou a capacidade de dizer por que ele seguia
aberto e quanto custava enquanto seguia, então a linha existiu antes da
correção. O comando agora existe (RN-569); a linha fica porque a prova no
cluster não existe.
Dois ids — BRB-005 e BRB-031 — eram citados em cinco documentos daqui, em
prosa, sem estado que alguém pudesse conferir. Os outros ids eram
completamente invisíveis a este repositório: uma busca no disco inteiro
devolveu só esses dois.
O custo foi medido, não imaginado. O planejamento da FASE 29 listou seis itens
BRB como pré-requisitos ou riscos; conferir cada um contra a dev mostrou que
dois descrevem defeitos já corrigidos aqui, e que um terceiro tinha sido
mal lido só pelo id — ver BRB-004 abaixo, que não é sobre a tag que todo
mundo supõe.
Daí duas regras:
- Estado se sustenta em
arquivo:linha, medido, nunca lembrado. - O vault é dono do achado; o repositório é dono da evidência. Onde os dois discordam sobre se algo ainda acontece, o repositório vence — ele é a coisa descrita. Se um item está formalmente fechado continua sendo decisão do mantenedor, no vault.
O registro
| id | título (do vault) | prio | estado no vault | medido aqui | evidência |
|---|---|---|---|---|---|
| BRB-001 | Teto para o auto-rebaixamento pela REMOÇÃO de uma associação de projeto | P1 | fechado 2026-09-12 (PR #531) | defeito não reproduz mais | RemoveProjectMemberUseCase.execute recebia (projectId, userId) — sem ator — e o controller o chamava com os dois parâmetros da rota, então um maintainer cuja autoridade vinha da linha de projeto (viewer no workspace) podia remover a própria linha e cair para viewer de forma irreversível; o caso estava fixado num teste cujo próprio nome dizia que estava aberto. O ADR 0127 tinha declarado a lacuna por escrito, com estimativa de custo. Fechado pelo ADR 0156 / RN-556: o ator agora chega ao caso de uso, remocaoEhAutoRebaixamento delega à regra do teto 2 existente com o papel de workspace como o pedido, e o teste da lacuna foi INVERTIDO em vez de apagado. O teto do owner de workspace de propósito não ganha par — a remoção só pode elevar um owner |
| BRB-002 | Teto para o auto-movimento no upsert de membro de WORKSPACE | P2 | fechado 2026-09-12 (PR #533) | defeito não reproduz mais | AddWorkspaceMemberUseCase.execute recebia (workspaceId, userId, role) e chamava workspaces.addMember — sem ator — enquanto o controller (@Post(':workspaceId/members'), @RequireRole('owner')) passava o corpo cru sem @CurrentUser(). Um owner podia se gravar viewer e perder o workspace inteiro: nada acima segura a queda, e o WorkspacesController não tem @Delete de membro (medido), então desfazer é essa mesma rota, que exige o owner recém-abandonado. O ADR 0127 o nomeou por escrito ("mesma classe de defeito, um escopo acima") e o ADR 0156 o deixou como decisão à parte. Fechado pelo ADR 0157 / RN-557: o ator chega ao caso de uso e mudar o próprio papel é 403 nos dois sentidos. O teto não conta owners (a cláusula já garante que um workspace nunca chega a zero, já que remover o último owner exigiria esse owner), e o teto 1 não ganha par aqui — @RequireRole('owner') já proíbe a inversão de hierarquia que ele existe para impedir, e acrescentá-lo faria de owner um estado absorvente sem saída por HTTP. O mesmo ADR fecha a auto-promoção nas duas rotas de associação, revisando as Consequências do ADR 0127: é a única metade do movimento que escala privilégio |
| BRB-003 | Corrigir as três descrições de OpenAPI que prometem "o maior dos dois" (RN-471) | P2 | fechado 2026-09-27 (AT-136) | defeito não reproduz mais | grep -rn "higher of the two" apps/api/src vem vazio. apps/api/src/interfaces/http/iam/dto/add-member.dto.ts:29 e projects.controller.ts:190,239 dizem que o papel de projeto SOBREPÕE o de workspace nos dois sentidos — o texto chegou com o ADR 0127 / RN-472 (PR #445). Medido pela primeira vez em 2026-09-11 (AT-017) |
| BRB-004 | Pinar imagens de terceiros (neo4j, pgvector, ollama) por digest | P2 | aberto | defeito não reproduz mais | Era: toda imagem de terceiro pinada por tag, não por digest. O pin por tag tinha fechado uma lacuna diferente (PRs #401/#419) e esta linha se lia como se aquilo fosse a correção — o motivo de a distinção entre id e descrição, abaixo, valer o que custa. Fechado pelo ADR 0159: as 37 referências a terceiros vão por digest de índice com a tag num comentário ao fim, e scripts/ci/imagens-pinadas.ts reprova o job lint numa referência mutável, num digest sem comentário de tag e na mesma tag com dois digests diferentes. A contagem é 37 e não a lista do próprio achado, porque três lugares inteiros estavam fora dela: as linhas FROM dos Dockerfiles (a base das quatro imagens que publicamos e assinamos) e as imagens de services: de ci.yml/golden-set-rag.yml — o runner de CI que a regra irmã já protege, alcançado pela outra porta. As cinco imagens que o produto publica deliberadamente não são cobertas (quatro quando a linha foi escrita; a quinta, o broker, veio com o ADR 0162): nenhum terceiro pode movê-las, brabo-api:prod é uma tag local cujo digest não existe antes do build, e onde elas cruzam um registry o ADR 0119 já as resolve — o overlay guarda um marcador de propósito, então um literal ali reprovaria o estado correto. Declarado e não corrigido, porque é o preço do pin: um digest não recebe atualização de segurança até alguém subi-lo à mão, e o ecossistema docker do Dependabot fica desligado — decisão à parte. Também descoberto, e dito: otel-collector-values.yaml, onde image: abre um mapa cuja tag o chart do Helm escolhe |
| BRB-005 | Assinar as imagens do GHCR e os binários do runner | P2 | aberto | implementado, ainda não exercitado | Era: nenhum cosign/sigstore/attestation em lugar nenhum, release.yml sem id-token: write, nenhum checksums.txt. Agora: release.yml assina as cinco imagens por digest (quatro quando foi escrito; o ADR 0162 acrescentou o broker) e as verifica na mesma execução; build-runner-binaries.yml ganhou um job checksums que publica um manifesto assinado para os cinco alvos (ADR 0149, RN-524); procedimento de verificação no runbook. Não exercitado: a assinatura só roda numa tag final de verdade, então nada aqui a prova de ponta a ponta ainda. Ainda descoberto, e item à parte: a assinatura de código do SO para os binários (notarização/Authenticode). A sessão 3 fez o proxy de download GET /runner-releases/binary verificar — mas só o sha256 contra o checksums.txt da release, nunca a assinatura do manifesto (RN-525): isso é integridade, não procedência, e quem consegue reescrever a Release reescreve os dois arquivos. Os dois jeitos de a api conferir a assinatura foram medidos e recusados: cosign na imagem são 155 MB (quase dobrando uma imagem de runtime Alpine+Node), e @sigstore/verify+@sigstore/tuf é barato (2,5 MB) mas faz uma rota @Public() depender de um segundo host de terceiro (tuf-repo-cdn.sigstore.dev) para verificar algo que nenhuma Release carrega ainda — improvável, e os ADRs 0041/0042 proíbem declarar uma capacidade não provada. O consumidor da assinatura é o install.sh (sessão 4/7), que tem um cosign pinado de verdade. Então a metade de procedência do proxy segue aberta, e a recusa já tem nome ali: uma Release sem checksums.txt é recusada, não servida com aviso |
| BRB-006 | Automatizar a atualização dos SHAs pinados (Dependabot/Renovate) | P3 | aberto | defeito não reproduz mais | .github/dependabot.yml:35 declara o ecossistema github-actions (e npm, :55/:61), todos com target-branch: dev; .github/workflows/dependabot-para-dev.yml encaminha as atualizações de segurança para a dev, e scripts/ci/dependabot-justifica-pin.ts (AT-094) escreve a linha docs-not-needed: num bump só de pin. Não medido aqui: o "pronto quando" pede uma PR de bump real passando em actions-pinadas.ts sem passo manual — nenhuma PR foi listada para esta linha |
| BRB-007 | Rodar o golden-set do Automation-QA em CI | P2 | entregue 2026-09-27 (PR #687, #689), não marcado como fechado | defeito não reproduz mais | .github/workflows/golden-set-qa.yml:39 o roda semanalmente (cron: '17 1 * * 6') mais workflow_dispatch, nunca em pull_request (ADR 0168). O instrumento volta a medir sob a RN-502: o seed sobe o container por container_start (AT-076), e as execuções de prova marcaram 3/6 contra um piso de 1/6. O piso em apps/engine/test/fixtures/golden_set_qa/floor.json ainda é o de 2026-08-30 — só um humano o escreve |
| BRB-008 | Trocar (ou justificar) o modelo padrão do seed do golden-set | P2 | aberto | ainda reproduz | apps/api/scripts/seed-golden-set-qa.ts:119 ainda usa por padrão qwen2.5-coder:latest, cujo piso em apps/engine/test/fixtures/golden_set_qa/floor.json é 1/6 (contra 4/6 do gpt-oss:20b). Nenhuma decisão registrada |
| BRB-009 | Agendar as três provas de propriedade (test-restore, rollout-test, hpa-test) | P2 | aberto | aberto — agendado agora; a mutação do restore é pega, a última execução boa é artefato de workflow e ainda não métrica | Era: os três alvos (Makefile:41-48) só rodavam quando alguém digitava make, e nenhum workflow subia um cluster (grep -rn "k3d|kind" .github/workflows/ vinha vazio). Agora .github/workflows/propriedades.yml roda semanalmente e em workflow_dispatch: instala k3d/helm/kubectl por checksum pinado, roda o mesmo deploy/k8s/bootstrap.sh que um humano roda, depois make smoke-k8s, make hpa-test, make rollout-test e make test-restore, cada um cronometrado no resumo da execução; um alvo que falha abre uma issue com o nome dele, e uma falha repetida comenta na aberta em vez de abrir outra. Não é gate nem check obrigatório. A primeira execução já se pagou: o bootstrap morreu criando o cluster CNPG, porque o imageName só com digest que o ADR 0159 escreveu é recusado pelo webhook do operador — o kubeconform não roda webhook, então o job de manifestos tinha ficado verde. Vieram mais nove, todos corrigidos na mesma mudança (listados no runbook), um deles fora do cluster local: o brabo-restore morria em COMMENT ON EXTENSION vector em qualquer Postgres onde o papel da aplicação não é superusuário. A primeira execução toda verde é a 34784563928 (2026-09-13, 12 min 56 s), verde de novo numa segunda tentativa. A prova de rollout acusou uma sessão órfã numa de quatro execuções que chegaram a ela, e isso está declarado, não corrigido. A AT-126 fechou a primeira das duas cláusulas restantes: make test-restore-mutacao quebra o restore de propósito (uma tabela na origem que o dump não tem) e a execução agendada falha, e abre a própria issue, se o restore não a recusar nomeando essa tabela; uma execução em que o restore foi cegado de propósito falhou nesse passo. Ainda aberto, e não cabe a este repositório fechar pela CI: a última execução bem-sucedida agora é datada pelo workflow (o artefato restore-ultima-execucao-boa, escrito só quando o restore e a quebra deliberada passaram) mas não é uma métrica ao lado dos alertas de backup nem uma linha de backupRuns — isso exige código em apps/api. Durações medidas e cadência: runbook, Provas de propriedade agendadas |
| BRB-010 | Exercitar a rotação da CREDENTIALS_MASTER_KEY com script e teste | P2 | fechado 2026-09-27 (AT-136) | defeito não reproduz mais | Fechado pela PR #551, ADR 0158 / RN-562: apps/api/src/scripts/rewrap-deks.ts exporta o núcleo (reenvelopar) e apps/api/test/scripts/rewrap-deks.spec.ts é a verificação nomeada, contra um Postgres de verdade e as duas tabelas de envelope; o runbook o roda (docs/runbook.md:2770). O nome do comando difere da proposta do achado (credenciais:reenvelopar); o "pronto quando" — uma verificação nomeada — está cumprido. Desde a AT-146 a rotação tem também um ensaio no cluster: ela nunca tinha rodado num ambiente real (mantenedor, 2026-09-27), e make test-rotacao-chave-mestra-k8s roda os três passos do runbook semanalmente no propriedades.yml — com o ExternalSecret, um restart da api e o rewrap-deks.js da imagem (primeira execução verde 36502355798) |
| BRB-011 | Cobrir o ponto único de falha dos alertas (Grafana sem Alertmanager) | P2 | aberto | ainda reproduz | deploy/k8s/observability/alerts/brabo-alerts.yaml:8 ainda diz que não há Alertmanager nem receiver; nada em deploy/k8s avisa quando o próprio Grafana para de avaliar (medido pela AT-121, 2026-09-19) |
| BRB-012 | Provar os providers de LLM nunca exercitados contra uma credencial real | P3 | aberto | não verificável aqui | A execução exige chaves pagas que este repositório não tem. O que o repositório registra: a tabela de chat em docs/explanation/aceite-providers.md:108-115 (estado de 2026-08-07) tem o OpenRouter rodado de verdade e Together, DeepInfra, NVIDIA NIM, Bitdeer e Vultr skipped por falta de *_TEST_KEY; a tabela de embeddings acima dela (:83-93) prova só o Ollama |
| BRB-013 | Limpar as sobras do degrau rc (enum e lista de branches protegidas) | P3 | aberto | reproduz em parte — a metade do repositório é decisão | apps/api/src/domain/actions/protected-branches.ts:12 mantém rc e apps/api/src/db/schema/git.ts:24 mantém create_rc_branch — de propósito: a lista decide o que o teto de merge recusa, e repositórios bootstrapados por versões antigas ainda têm a branch (CLAUDE.md, Convenções). A outra metade — duas notas do vault ainda listando rc como protegida — mora no vault |
| BRB-014 | Migrar o resto de api-types.ts para tipos gerados | P3 | aberto | ainda reproduz | apps/web/src/lib/api-types.ts tem 1.852 linhas com 185 exports (o achado dizia ~1.600), ao lado do api-types.generated.ts gerado |
| BRB-015 | Seguir decompondo SessionPage.tsx | P3 | aberto | defeito não reproduz mais | apps/web/src/routes/SessionPage.tsx tem 834 linhas (eram 2.637 na dev em 018b8cd24c; o achado dizia 2.479, em pages/), depois das dez PRs mecânicas do ADR 0176 (AT-138). O "pronto quando" é abaixo de 1.000, e agora está travado: apps/web/src/routes/SessionPage.teto.test.ts reprova o arquivo com 1.000 linhas ou mais, provado por mutação. Subir o teto exige ADR novo |
| BRB-016 | Gravar o id da chave no wrapped_dek para simplificar a rotação | P3 | fechado 2026-09-27 (AT-136) | defeito não reproduz mais | Fechado pela PR #551, ADR 0158 / RN-563: key_id (a impressão digital da chave mestra) em apps/api/src/db/schema/llm.ts:275 e git.ts:76, então "quantas credenciais ainda estão na chave anterior?" é uma consulta (IS DISTINCT FROM, contando as linhas sem rótulo como pendentes). O rótulo nunca decide se um envelope abre — quem decide é o GCM |
| BRB-017 | Cumprir a obrigação da GPL das ferramentas embutidas na imagem publicada do engine | P1 | aberto | defeito não reproduz mais | Era: nada em docker/engine/ mencionava licenças, obrigação que ficou real quando o ADR 0119 passou a publicar no GHCR a cada tag final. A oferta existia e era boa — THIRD_PARTY_NOTICES.md na raiz, nomeando cada componente, a versão exata e a licença — só não viajava. Agora viaja: docker/engine/Dockerfile.prod:190-192 o copia para /usr/share/doc/brabo/, antes do USER e como root, então ele vai dentro de toda imagem publicada do engine (PR #532). Remedido em 2026-10-01 (AT-120): por decisão do mantenedor o mesmo COPY, na mesma forma, está nos outros quatro Dockerfiles de produção (api, web, broker, backup), e a Release do runner leva o arquivo como asset dentro do checksums.txt assinado — nenhum artefato é declarado isento. Travado por scripts/ci/oferta-de-fonte-na-imagem.spec.ts (o estágio final de cada Dockerfile, o asset da Release, casos de mutação), e o job de imagem do ci.yml lê o arquivo de volta de dentro de cada uma das cinco imagens que constrói. Achado no caminho: a cópia do engine era ilegível para o usuário não-root da imagem (o BuildKit aplicou --chmod=0644 ao diretório que criou), então a conferência documentada docker run … cat falhava com "Permission denied"; o diretório agora é criado 0755 antes. Duas coisas seguem abertas, e nenhuma é defeito: o sidecar (caminho 3) ainda é uma escolha de arquitetura não feita, e se a obrigação está cumprida é um juízo jurídico que este repositório não pode afirmar — ele só pode dizer que a imagem leva a oferta. Achado no caminho: o documento afirmava o contrário do que o repositório faz ("nenhuma imagem é publicada hoje", superado pelo ADR 0119), e o TODO(humano) dele para decidir "antes do primeiro push" expirou sem ser lido |
| BRB-018 | Escrever e testar a reconstrução da projeção do Neo4j a partir do event log | P2 | aberto | implementado e provado no cluster local (agendado); sem medição de tempo em log grande | Era: nenhum comando de reprojeção em lugar nenhum (grep reprojet/reproject/graph:repro em apps/ e scripts/ não devolvia nada), enquanto a decisão 4 do ADR 0152 já tinha recusado o backup de neo4j_data com o argumento de que a reprojeção é a resposta. Agora: apps/api/src/scripts/reprojetar-grafo.ts (pnpm --filter api grafo:reprojetar, node scripts/reprojetar-grafo.js na imagem) percorre session_events e as sessions fechadas por cursor, em lotes, e entrega cada fonte ao GraphEventTranslator — a mesma tradução que o GraphProjector de avanço agora chama, extraída dele em vez de escrita duas vezes (RN-569). Idempotente (MERGE, nunca apaga), log inteiro ou --project, não toca a outbox onde o projetor vivo guarda o progresso, e falha nomeado quando o Neo4j está fora ou o projeto não existe. O procedimento está no runbook (Perda do grafo). A prova é make test-reprojecao (apps/api/test/scripts/reprojetar-grafo.spec.ts): projeta um cenário para frente, apaga o subgrafo dele, reprojeta, compara contagens de nós e arestas e a lista de chaves, reprojeta de novo — verde contra o Neo4j do compose de desenvolvimento, e pula onde não há Neo4j, o que inclui o job da api na CI. A prova no cluster (AT-127): make test-reprojecao-k8s (deploy/k8s/test-reprojecao.sh) é o quarto alvo do propriedades.yml — num projeto que ele cria (uma sessão fechada, dois eventos) roda node scripts/reprojetar-grafo.js --project dentro do pod da api, apaga esse subgrafo no Neo4j do cluster, reprojeta e exige as mesmas contagens (5 nós, 4 arestas), depois reprojeta de novo; verde na execução 35471428634 em 16 s, depois de duas execuções que falharam no próprio script (35469877869, 35470685598). Desde a AT-191 o cenário tem quatro eventos — uma hipótese do Psicólogo e um perfil da Anamnese além da mensagem e do handoff —, então exercita todo caminho do tradutor, e as contagens são 9 nós e 6 arestas (execução 36498776825, 18 s). Não depende do test-restore nem do estado dos outros alvos. Ainda não fechado: não há medição de tempo num event log grande (a única execução real é o compose de dev, 98 eventos, 2,5 s), e PromptTemplate/PromptVersion não estão no event log — voltam por scripts/dev/seed-prompts.ts |
| BRB-019 | Parar de rodar api e web como root em desenvolvimento | P3 | fechado 2026-08-28 (PR #406) | defeito não reproduz mais | docker/api/Dockerfile:52 e docker/web/Dockerfile:23 rodam como USER ${DEV_UID}:${DEV_GID} (PR #406, fechada antes de o achado ser levantado) |
| BRB-020 | Dar severidade a todo alerta de brabo-alerts.yaml | P3 | aberto | defeito não reproduz mais | Os cinco alertas têm severity: (deploy/k8s/observability/alerts/brabo-alerts.yaml:29,59,87,123,160). Não medido aqui: o "pronto quando" também pede que o painel operacional filtre por ela |
| BRB-021 | Preencher as lacunas do runbook: rollout e incidente de custo | P3 | aberto | defeito não reproduz mais | docs/runbook.md:1671 ## Engine rollout {#rollout-do-engine} e :2899 ## Cost incident {#incidente-de-custo}, os dois alcançados pela tabela de triagem (:21, :30) |
| BRB-022 | Corrigir as contagens em prosa que o repositório já sabia estarem erradas | P2 | fechado 2026-09-27 (AT-136) | defeito não reproduz mais | Fechado pela PR #530: CONTRIBUTING.md:11 (contagem de ADRs) é conferido por pnpm docs:check, e a contagem de schemas de artefato do glossário é derivada de Engine.Harness.ArtifactSchemas (scripts/docs/generate.mjs:623-624), exercitada por mutação nos dois sentidos |
| BRB-023 | Atualizar o vault: ADR 0127, RN-471/472 e a contagem divergente de ADRs | P2 | aberto | não verificável aqui | O achado é sobre as próprias notas do vault. O repositório só pode dar os números que o vault deveria copiar — docs/adr/ e os arquivos de RN são a fonte |
| BRB-024 | Remover referências a pastas e caminhos que não existem mais | P3 | aberto | metade do repositório não reproduz mais; metade do vault não verificável aqui | README.md:296 e docs/getting-started.md:274 dizem apps/api/src/db/schema/<aggregate>.ts, e as duas frases são ancoradas no código por verificarFrasesAncoradasNoCodigo; design_handoff_brabo/ só aparece em prosa histórica. As notas que o achado nomeia (UX Designer, Desenvolvimento Local, Comandos) moram no vault |
| BRB-025 | Incluir apps/api/scripts/ e e2e/ no inventário de ambiente gerado | P3 | aberto | defeito não reproduz mais | scripts/docs/fontes-de-env.mjs:49-52 varre os dois, e um process.env.X novo ali reprova o docs:check (AT-124, PR #638, medido por mutação). A metade que ficou aberta — depois do docs:generate o ⚠️ não reprovava, e HUGGINGFACE_API_TOKEN/HUGGINGFACE_HUB_URL foram commitadas assim — fechou na AT-211 (2026-09-27): o docs:check reprova qualquer ⚠️ no inventário de ambiente, nas duas espécies de fonte (scripts/docs/inventario-de-env.mjs, provado por mutação em inventario-de-env.spec.ts), e as duas variáveis estão descritas em configuration.md |
| BRB-026 | Reorganizar docs/adr/index.md — tudo desde o 0044 está sob "Phase 12" | P3 | aberto | ainda reproduz | docs/adr/index.md:143 ## Phase 12 — Post-dogfooding operability ainda guarda todo ADR posterior, e o índice não tem bloco gerado |
| BRB-027 | Registrar a metodologia por trás da tabela de "Escala" | P3 | aberto | ainda reproduz | Não há scripts/docs/escala.mjs e docs/architecture.md não tem bloco de escala gerado; a tabela em si mora no vault |
| BRB-028 | Dar um gatilho ao momento de appsec (threat_model) | P2 | fechado 2026-09-27 (AT-136) | defeito não reproduz mais | Era: SecOpsAgentServer.run_design/2 não tinha chamador de produção, e docs/fluxo.yml nomeava assess_implementability como o gatilho natural enquanto o declarava fora de escopo. Mergeado na dev pela PR #514 (RN-539 — renumerada da 522, já tomada dois dias antes): dev_lead_tools.ex:333-338 o dispara a partir de assess_implementability, exatamente onde a lacuna dizia que ele cabia, por Dispatcher.run_appsec_design/2 (dispatcher.ex:112); docs/fluxo.yml:188-196 agora diz status: active sem lacuna declarada. O gatilho é guardado por idempotência e isso não é zelo: o desfecho :sem_plano pede ao modelo que chame assess_implementability de novo, e cada nova chamada gastaria outra rodada de LLM de appsec e mais três handoffs na mesma história. Um limite fica declarado no código: artifact.threat_model é emitido na sessão da HISTÓRIA enquanto a guarda lê a sessão do DEV LEAD — a mesma sessão no caminho comum, e uma rodada de LLM repetida, nunca dado errado, quando diferem |
| BRB-029 | Decidir o destino do Psicólogo e da Anamnese (pausados desde 2026-08-10) | P2 | aberto | não verificável aqui — decisão de produto | A pausa está declarada como decisão de produto aberta no CLAUDE.md e ficou reversível com a RN-540; nenhum ADR registra mantê-la desligada por um período definido |
| BRB-030 | Reconciliar a navegação de abas duplicada (trilho × sidebar) | P3 | aberto | não verificável aqui — decisão de produto | O CLAUDE.md lista a duplicação (LinhaDeAba, RN-196) como lacuna aceita e decisão de produto à parte, não tomada no ADR 0126 |
| BRB-031 | Remover o chmod +x manual da configuração do runner pelo navegador | P3 | fechado 2026-10-01 (AT-014) | defeito não reproduz mais | Era: a File System Access API não preserva o bit de execução (docs/adr/0118-configuracao-automatica-do-runner-pelo-navegador.md:134-140), então o fluxo pelo navegador do ADR 0118 terminava num chmod +x manual. Metade fechou antes por outro caminho: o install.sh instala o binário com install -m 0755 (RN-531) e pareia a máquina pelo terminal (RN-547). A outra metade fechou pela decisão do dono (01/10) de aposentar o fluxo pelo navegador: o ADR 0203 / RN-687 removeu apps/web/src/lib/runner-bootstrap.ts e POST /projects/:projectId/runner-device-keys, e o RunnerOnboardingPanel agora manda as pessoas ao comando do instalador. grep -rn "chmod +x" apps/web/src acha só o docblock do painel contando por que o passo saiu. Chaves de projeto registradas pelo navegador antes disso seguem valendo e revogáveis. A cobertura e2e do download que o achado também pedia perdeu o objeto: não sobrou download pelo navegador a cobrir |
| BRB-032 | O broker nunca subia no compose local | P1 | fechado 2026-09-27 só na metade medida (AT-136) | defeito não reproduz mais em duas de três metades; a terceira não exercitada | Fechado no vault só na metade medida. Medido: o broker saiu de profiles: — os únicos profiles do compose de dev são local-llm (docker/docker-compose.yml:86,126); a causa raiz — corepack como root no build sem registry em runtime — foi corrigida preparando COREPACK_HOME no build e acrescentando um healthcheck (PR #503, RN-512), sem dar rede ao broker; e o .env.example não se contradiz mais (2026-09-11). Ainda aberto: "container_start num projeto container alcança o daemon" nunca foi exercitado — exige uma imagem decidida pelo Arquiteto (RN-105), que nenhuma instância medida tinha |
| BRB-033 | O reset-total.sh derrubava o engine e o seed morria junto | P2 | fechado 2026-09-27 (AT-136) | defeito não reproduz mais | 718b859e2 — "o reset total sobrevive a si mesmo e para de mentir no fim", mergeado na dev via c230e91af (PR #507). O script agora sonda o /health dos três serviços e qualquer falha sai nomeando o passo |
Em 2026-09-27 o vault registra 10 fechados (BRB-032 só na metade
medida), 1 entregue e ainda não marcado como fechado (BRB-007) e
22 abertos. Um estado aberto no vault ao lado de "defeito não reproduz mais"
não é contradição: é um fechamento que o mantenedor ainda não fez.
O que as palavras de "medido aqui" querem dizer
São palavras diferentes de propósito. Corrigido seria o juízo do mantenedor, registrado no vault. Defeito não reproduz mais é tudo o que este repositório pode afirmar com honestidade: o comportamento que o achado descreve não é o que o código faz hoje, medido na data da linha. Implementado, ainda não exercitado é mais fraco: o código existe e os testes que podem rodar passam, mas o caminho só executa num lugar que este repositório não alcança — uma tag de release de verdade, na CI. Chamar isso de "corrigido" seria alegar uma prova que ninguém tem. Ainda reproduz e reproduz em parte dizem que o comportamento do achado ainda está lá, no todo ou em parte. Não verificável aqui diz que o achado é sobre algo que este repositório não guarda. Fechar o item — e decidir se a correção cobre tudo o que o achado pediu — fica onde o achado foi levantado.
BRB-004 é o motivo de a distinção valer o que custa. Lido pelo id, ele
parecia o pin de ollama:latest que fechou na #419. Lido no vault, ele pedia
digests, que nenhuma imagem tinha. Um id não é uma descrição — e a leitura
errada foi o que o manteve aberto enquanto uma regra irmã para uses: já tinha
mecanismo desde a #419.
Mudando uma linha
O id, o título e a prioridade são copiados do vault ao pé da letra, e o estado no vault também; o estado "medido aqui" e a evidência são medidos aqui. Uma linha muda quando o vault muda o estado dela ou quando uma mudança neste repositório muda o que pode ser provado — nunca para inventar um achado.