sentry-test 1.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- sentry_test-1.0.0/LICENSE +21 -0
- sentry_test-1.0.0/PKG-INFO +265 -0
- sentry_test-1.0.0/README.md +233 -0
- sentry_test-1.0.0/pyproject.toml +21 -0
- sentry_test-1.0.0/setup.cfg +4 -0
- sentry_test-1.0.0/src/sentry_test.egg-info/PKG-INFO +265 -0
- sentry_test-1.0.0/src/sentry_test.egg-info/SOURCES.txt +50 -0
- sentry_test-1.0.0/src/sentry_test.egg-info/dependency_links.txt +1 -0
- sentry_test-1.0.0/src/sentry_test.egg-info/entry_points.txt +2 -0
- sentry_test-1.0.0/src/sentry_test.egg-info/top_level.txt +1 -0
- sentry_test-1.0.0/src/sentrytest/__init__.py +3 -0
- sentry_test-1.0.0/src/sentrytest/adapters/__init__.py +1 -0
- sentry_test-1.0.0/src/sentrytest/adapters/case_specs.py +244 -0
- sentry_test-1.0.0/src/sentrytest/adapters/local_tools.py +320 -0
- sentry_test-1.0.0/src/sentrytest/adapters/toml_config.py +9 -0
- sentry_test-1.0.0/src/sentrytest/application/__init__.py +0 -0
- sentry_test-1.0.0/src/sentrytest/application/analyze.py +190 -0
- sentry_test-1.0.0/src/sentrytest/application/cases.py +115 -0
- sentry_test-1.0.0/src/sentrytest/application/coverage_context.py +13 -0
- sentry_test-1.0.0/src/sentrytest/application/dimensions.py +91 -0
- sentry_test-1.0.0/src/sentrytest/application/error_paths.py +139 -0
- sentry_test-1.0.0/src/sentrytest/application/impact.py +70 -0
- sentry_test-1.0.0/src/sentrytest/application/reporting.py +208 -0
- sentry_test-1.0.0/src/sentrytest/application/traceability.py +159 -0
- sentry_test-1.0.0/src/sentrytest/cli.py +206 -0
- sentry_test-1.0.0/src/sentrytest/domain/__init__.py +1 -0
- sentry_test-1.0.0/src/sentrytest/domain/catalog.py +78 -0
- sentry_test-1.0.0/src/sentrytest/domain/models.py +100 -0
- sentry_test-1.0.0/src/sentrytest/domain/rules.py +62 -0
- sentry_test-1.0.0/src/sentrytest/init_project.py +89 -0
- sentry_test-1.0.0/src/sentrytest/ports/__init__.py +1 -0
- sentry_test-1.0.0/src/sentrytest/ports/inputs.py +32 -0
- sentry_test-1.0.0/src/sentrytest/skills.py +211 -0
- sentry_test-1.0.0/tests/test_analyze.py +302 -0
- sentry_test-1.0.0/tests/test_case_specs.py +146 -0
- sentry_test-1.0.0/tests/test_cases_application.py +116 -0
- sentry_test-1.0.0/tests/test_changed_coverage.py +166 -0
- sentry_test-1.0.0/tests/test_cli.py +115 -0
- sentry_test-1.0.0/tests/test_contextual_reporting.py +83 -0
- sentry_test-1.0.0/tests/test_dimensions.py +86 -0
- sentry_test-1.0.0/tests/test_domain_models.py +19 -0
- sentry_test-1.0.0/tests/test_error_paths.py +114 -0
- sentry_test-1.0.0/tests/test_execution_evidence.py +108 -0
- sentry_test-1.0.0/tests/test_git_context.py +144 -0
- sentry_test-1.0.0/tests/test_history_cli.py +121 -0
- sentry_test-1.0.0/tests/test_impact.py +74 -0
- sentry_test-1.0.0/tests/test_init_project.py +70 -0
- sentry_test-1.0.0/tests/test_input_adapters.py +6 -0
- sentry_test-1.0.0/tests/test_reporting.py +41 -0
- sentry_test-1.0.0/tests/test_rules.py +88 -0
- sentry_test-1.0.0/tests/test_toml_config.py +43 -0
- sentry_test-1.0.0/tests/test_traceability.py +155 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Lucas Nicolau Ferreira
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALING IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: sentry-test
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Test quality intelligence for change-oriented reviews
|
|
5
|
+
Author: Lucas Nicolau Ferreira
|
|
6
|
+
License: MIT License
|
|
7
|
+
|
|
8
|
+
Copyright (c) 2026 Lucas Nicolau Ferreira
|
|
9
|
+
|
|
10
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
11
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
12
|
+
in the Software without restriction, including without limitation the rights
|
|
13
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
14
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
15
|
+
furnished to do so, subject to the following conditions:
|
|
16
|
+
|
|
17
|
+
The above copyright notice and this permission notice shall be included in all
|
|
18
|
+
copies or substantial portions of the Software.
|
|
19
|
+
|
|
20
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
21
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
22
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
23
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
24
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
25
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALING IN THE
|
|
26
|
+
SOFTWARE.
|
|
27
|
+
|
|
28
|
+
Requires-Python: >=3.11
|
|
29
|
+
Description-Content-Type: text/markdown
|
|
30
|
+
License-File: LICENSE
|
|
31
|
+
Dynamic: license-file
|
|
32
|
+
|
|
33
|
+
# Sentry
|
|
34
|
+
|
|
35
|
+
CLI de qualidade de teste orientada a mudança. O `sentry` cria a pasta da spec, valida a matriz de casos em markdown, roda a suíte, lê o diff e a cobertura, e emite um veredito auditável — e deixa o fluxo escrito para o agente de IA que for implementar a mudança.
|
|
36
|
+
|
|
37
|
+
Markdown é a fonte da intenção: a CLI parseia e valida `CASES.md` e `PROMPT.md` — ela nunca os escreve. O agente de IA faz a redação; o Sentry garante estrutura, rastreabilidade e veredito.
|
|
38
|
+
|
|
39
|
+
> Não confundir com o [Sentry da getsentry](https://sentry.io) (monitoramento de erros). Este projeto é distribuído como `sentry-test`.
|
|
40
|
+
|
|
41
|
+
## A divisão de responsabilidade
|
|
42
|
+
|
|
43
|
+
- **O agente de IA declara intenção** — escreve o `CASES.md`: requisito, camada, tipo, prioridade, entrada, resultado esperado.
|
|
44
|
+
- **O Sentry mede a realidade** — decide status, teste associado, evidência e veredito.
|
|
45
|
+
|
|
46
|
+
O agente nunca escreve status. O Sentry nunca chama um modelo. É isso que torna o veredito auditável e reproduzível.
|
|
47
|
+
|
|
48
|
+
## Instalação
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
pip install sentry-test
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Requer Python 3.11+. Confira com `sentry --version` (imprime a versão do pacote).
|
|
55
|
+
|
|
56
|
+
Se faltar `pytest` ou `coverage`, o `init` avisa. Para instalar junto:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
sentry init --install
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## Setup
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
cd seu-projeto
|
|
66
|
+
sentry init
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Cria `.sentry/` (specs, execuções, relatórios e banco), o `sentry.toml`, as entradas do `.gitignore`, e escreve o fluxo em dois lugares:
|
|
70
|
+
|
|
71
|
+
- **Skill `sentry-cases`** em `.claude/skills/sentry-cases/SKILL.md` — carregada automaticamente pelo Claude Code e por agentes que seguem essa convenção.
|
|
72
|
+
- **`AGENT-SENTRY.md`** na raiz do projeto — o mesmo fluxo em markdown puro, sem depender de convenção de nenhuma ferramenta.
|
|
73
|
+
|
|
74
|
+
Para outros agentes (Cursor, Windsurf, Codex, opencode), aponte-os para o `AGENT-SENTRY.md` no arquivo de regras que cada um já usa — por exemplo, uma linha em `.cursor/rules` ou `AGENTS.md`:
|
|
75
|
+
|
|
76
|
+
```markdown
|
|
77
|
+
Para escrever ou revisar casos de teste, siga AGENT-SENTRY.md.
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
`init` é idempotente: não apaga histórico, não sobrescreve configuração existente, não duplica estruturas.
|
|
81
|
+
|
|
82
|
+
## O fluxo
|
|
83
|
+
|
|
84
|
+
1. `sentry new "cadastro de cliente"` — cria `.sentry/specs/cadastro-de-cliente/` com `PROMPT.md` (pedido preservado) e `CASES.md` em branco
|
|
85
|
+
2. **`sentry-cases`** — seu agente pergunta o que estiver ambíguo e preenche o `CASES.md` seguindo o template
|
|
86
|
+
3. `sentry check cadastro-de-cliente` — estrutura válida? classes de equivalência do catálogo cobertas?
|
|
87
|
+
4. seu agente liga cada caso ao teste real com o marcador `# cenario: <nome exato do caso>`
|
|
88
|
+
5. `sentry run --spec cadastro-de-cliente --run-tests` — roda a suíte, lê diff e cobertura, aplica as regras, persiste
|
|
89
|
+
6. `sentry report` / `sentry history` — releitura e comparação entre execuções
|
|
90
|
+
|
|
91
|
+
Todo passo também funciona sem agente, pelos comandos abaixo.
|
|
92
|
+
|
|
93
|
+
## Comandos
|
|
94
|
+
|
|
95
|
+
Código de saída `0` em sucesso; veja a tabela de códigos adiante.
|
|
96
|
+
|
|
97
|
+
| Comando | O que faz |
|
|
98
|
+
| --- | --- |
|
|
99
|
+
| `sentry init [--install]` | Prepara o repositório: `.sentry/`, `sentry.toml`, `.gitignore`, guia de agente e skills. Com `--install`, instala as dependências ausentes. |
|
|
100
|
+
| `sentry new <nome> [--prompt "..."] [--json]` | Cria a pasta da spec com slug derivado do nome. `--json` emite template, vocabulário aceito e classes cobradas, para o agente consumir. |
|
|
101
|
+
| `sentry check [<slug>\|all]` | Valida `CASES.md`: estrutura, vocabulário e cobrança de classes de equivalência. `all` valida todas as specs juntas. |
|
|
102
|
+
| `sentry run [--spec <slug>\|all] [--run-tests]` | Executa a análise e persiste. Sem `--run-tests` não há cobertura, e o veredito tende a `inconclusivo`. |
|
|
103
|
+
| `sentry report` | Exibe o último relatório (`.sentry/reports/latest.md`). |
|
|
104
|
+
| `sentry history` | Lista execuções e compara as duas últimas: cobertura, testes, achados novos, resolvidos e persistentes. |
|
|
105
|
+
| `sentry clear [--keep-last N] [--yes]` | Poda execuções e relatórios antigos. Sem `--yes` apenas mostra o que sairia — apagar histórico é irreversível. Nunca toca em `.sentry/specs/`. |
|
|
106
|
+
|
|
107
|
+
## Códigos de saída
|
|
108
|
+
|
|
109
|
+
Quatro estados distinguíveis, para separar "código mal testado" de "meu ambiente quebrou":
|
|
110
|
+
|
|
111
|
+
| Código | Significado |
|
|
112
|
+
| --- | --- |
|
|
113
|
+
| `0` | aprovado |
|
|
114
|
+
| `1` | aprovado com ressalvas |
|
|
115
|
+
| `2` | reprovado |
|
|
116
|
+
| `3` | inconclusivo ou erro de infraestrutura |
|
|
117
|
+
|
|
118
|
+
Erro de infraestrutura nunca produz veredito aprovado: uma suíte que não conseguiu rodar é diferente de uma suíte que reprovou.
|
|
119
|
+
|
|
120
|
+
`sentry check` mantém semântica própria: `0` estrutura válida, `1` erros estruturais, `2` não foi possível resolver a spec.
|
|
121
|
+
|
|
122
|
+
## Skills
|
|
123
|
+
|
|
124
|
+
Geradas para cada agente configurado; o `AGENT-SENTRY.md` cobre os demais.
|
|
125
|
+
|
|
126
|
+
| Workflow | O que o agente faz |
|
|
127
|
+
| --- | --- |
|
|
128
|
+
| `sentry-cases` | Recebe o pedido em texto livre, cria a spec, **pergunta antes de escrever** toda ambiguidade que mude um caso, preenche o `CASES.md`, liga cada caso ao teste com `# cenario:` e roda `check` até fechar limpo. Nunca escreve status. |
|
|
129
|
+
|
|
130
|
+
## Regras determinísticas
|
|
131
|
+
|
|
132
|
+
Dez regras, com severidade configurável por projeto.
|
|
133
|
+
|
|
134
|
+
| Regra | Severidade padrão | Dispara quando |
|
|
135
|
+
| --- | --- | --- |
|
|
136
|
+
| `test-failing` | crítica | a suíte tem teste falhando |
|
|
137
|
+
| `case-spec-invalid` | crítica | o `CASES.md` tem erro estrutural |
|
|
138
|
+
| `changed-code-uncovered` | alta | cobertura do código alterado é zero |
|
|
139
|
+
| `scenario-without-test` | alta | caso declarado sem teste associado |
|
|
140
|
+
| `error-path-without-test` | alta | `raise`/`throw` em linha alterada que nenhum teste executou |
|
|
141
|
+
| `missing-equivalence-class` | alta | classe exigida pelo catálogo que nenhum caso cobre |
|
|
142
|
+
| `coverage-below-threshold` | alta | cobertura do código alterado abaixo do limiar declarado |
|
|
143
|
+
| `requirement-without-scenario` | média | requisito sem cenário correspondente |
|
|
144
|
+
| `coverage-missing` | média | não foi possível calcular a cobertura do código alterado |
|
|
145
|
+
| `global-coverage-below-threshold` | média | cobertura global abaixo do limiar declarado |
|
|
146
|
+
|
|
147
|
+
Sem limiar declarado, o Sentry não inventa um mínimo. Quem define "quanto basta" é o projeto, e o relatório registra o número aplicado.
|
|
148
|
+
|
|
149
|
+
## Catálogo de classes de equivalência
|
|
150
|
+
|
|
151
|
+
Tabela fixa de situações que precisam de teste, **por tipo de campo**. Não gera casos: cobra os que o agente deixou de declarar.
|
|
152
|
+
|
|
153
|
+
Tipos conhecidos: `cpf`, `cnpj`, `email`, `senha`, `data`, `telefone`, `cep`, `inteiro`, `decimal`, `texto`, `rota`.
|
|
154
|
+
|
|
155
|
+
Uma classe que não faz sentido para o campo pode ser dispensada **com justificativa**, em vez de virar caso artificial ou cobrança eterna:
|
|
156
|
+
|
|
157
|
+
```markdown
|
|
158
|
+
## Classes não aplicáveis
|
|
159
|
+
|
|
160
|
+
- **exclude/tamanho-maximo-excedido**: é parâmetro de configuração, não campo de formulário
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
A dispensa remove o achado, mas fica registrada no relatório — nada some em silêncio.
|
|
164
|
+
|
|
165
|
+
## Dimensões de cobertura
|
|
166
|
+
|
|
167
|
+
Cada uma reporta `coberta`, `parcial`, `não coberta` ou `não aplicável`, com evidência.
|
|
168
|
+
|
|
169
|
+
| Dimensão | De onde tira a evidência |
|
|
170
|
+
| --- | --- |
|
|
171
|
+
| requisitos e regras de negócio | cenários da spec com teste associado |
|
|
172
|
+
| APIs, persistência, transações e integrações | casos de tipo `contrato`/`integração` e camada `integração` |
|
|
173
|
+
| exceções, resiliência e recuperação | caminhos de erro alterados executados por algum teste |
|
|
174
|
+
| segurança e autorização | campos de tipo `rota` com todas as classes de acesso cobertas |
|
|
175
|
+
|
|
176
|
+
`não aplicável` é distinto de `não coberta`: um projeto sem rotas não é punido na dimensão de segurança.
|
|
177
|
+
|
|
178
|
+
## Configuração
|
|
179
|
+
|
|
180
|
+
`sentry.toml` na raiz, versionável, sem segredos. Tudo é opcional além do que o `init` já escreve.
|
|
181
|
+
|
|
182
|
+
```toml
|
|
183
|
+
[project]
|
|
184
|
+
name = "meu-projeto"
|
|
185
|
+
|
|
186
|
+
[specs]
|
|
187
|
+
path = ".sentry/specs"
|
|
188
|
+
|
|
189
|
+
[test] # qualquer executor que exporte JUnit XML
|
|
190
|
+
command = "npx jest"
|
|
191
|
+
junit_xml = "reports/junit.xml" # sem isto, o Sentry injeta --junitxml (pytest)
|
|
192
|
+
|
|
193
|
+
[tests] # onde procurar testes
|
|
194
|
+
paths = ["tests"] # padrão: tests, test, spec, __tests__
|
|
195
|
+
|
|
196
|
+
[coverage] # relatório gerado pela suíte do próprio projeto
|
|
197
|
+
path = "coverage/lcov.info"
|
|
198
|
+
format = "lcov" # opcional: detectado pelo conteúdo quando omitido
|
|
199
|
+
|
|
200
|
+
[analysis]
|
|
201
|
+
run_tests_by_default = false
|
|
202
|
+
timeout_seconds = 300
|
|
203
|
+
exclude = ["frontend/"] # diretórios fora do escopo da análise
|
|
204
|
+
|
|
205
|
+
[policy.thresholds] # sem isto, nenhum mínimo é cobrado
|
|
206
|
+
changed_coverage = 85
|
|
207
|
+
global_coverage = 90
|
|
208
|
+
|
|
209
|
+
[policy.severities] # sobrescreve a severidade de qualquer regra
|
|
210
|
+
coverage-missing = "alta"
|
|
211
|
+
|
|
212
|
+
[catalog.fields] # tipos de campo do seu domínio
|
|
213
|
+
matricula = ["vazio", "formato-invalido", "valida"]
|
|
214
|
+
|
|
215
|
+
[dimensions] # eixos que não se aplicam ao projeto
|
|
216
|
+
disabled = []
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
`.sentry/` guarda specs, execuções, relatórios e o banco. Fica fora do Git, com uma exceção deliberada: `.sentry/reports/latest.md` é versionado, para o veredito aparecer no diff da PR sem que o revisor precise rodar o Sentry.
|
|
220
|
+
|
|
221
|
+
O histórico é mantido indefinidamente, e cresce a cada execução. Para podar:
|
|
222
|
+
|
|
223
|
+
```bash
|
|
224
|
+
sentry clear --keep-last 10 # mostra o que sairia
|
|
225
|
+
sentry clear --keep-last 10 --yes # remove
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
As specs nunca são removidas: são intenção declarada, não evidência gerada.
|
|
229
|
+
|
|
230
|
+
## Stacks suportadas
|
|
231
|
+
|
|
232
|
+
A **derivação** — do pedido à matriz de casos — é agnóstica de linguagem: o `CASES.md` é markdown e o catálogo raciocina sobre tipo de dado, não sobre código.
|
|
233
|
+
|
|
234
|
+
A **verificação** depende do formato de intercâmbio que sua suíte exporta, não da ferramenta:
|
|
235
|
+
|
|
236
|
+
| Capacidade | Suporte |
|
|
237
|
+
| --- | --- |
|
|
238
|
+
| Execução da suíte | qualquer comando que exporte **JUnit XML** — pytest, Jest, Vitest, `go test` (gotestsum), Surefire, `dotnet test`, RSpec, PHPUnit |
|
|
239
|
+
| Cobertura | **lcov** (nyc, c8, Jest, simplecov), **Cobertura XML** (JaCoCo, coverlet), **coverage.py** (JSON) — detectados pelo conteúdo |
|
|
240
|
+
| Rastreabilidade caso↔teste | `.py`, `.js`/`.jsx`/`.ts`/`.tsx`, `.go`, `.java`/`.kt`, `.cs`, `.rb`, `.php`, `.rs` — e o marcador `cenario:` funciona em qualquer comentário |
|
|
241
|
+
| Caminhos de erro | por AST em Python; por padrão sintático (`throw`, `catch`, `panic`, `rescue`, `panic!`) nas demais |
|
|
242
|
+
| Análise de impacto | 12 extensões de código-fonte |
|
|
243
|
+
|
|
244
|
+
A detecção de caminho de erro fora de Python é menos precisa que AST, e o relatório registra essa diferença como limitação — nunca a esconde.
|
|
245
|
+
|
|
246
|
+
Camada `frontend` é recusada de propósito: sem adaptador que a verifique, um caso declarado ficaria preso em `não coberto` para sempre.
|
|
247
|
+
|
|
248
|
+
## Local-first
|
|
249
|
+
|
|
250
|
+
Nenhuma telemetria, nenhuma chamada externa, nenhum envio de código ou diff. Todo o histórico permanece na máquina.
|
|
251
|
+
|
|
252
|
+
## Desenvolvimento
|
|
253
|
+
|
|
254
|
+
```bash
|
|
255
|
+
python -m pip install -e .
|
|
256
|
+
python -m pytest
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
O Sentry se analisa: `sentry run --spec all --run-tests` na raiz do repositório
|
|
260
|
+
casa os casos declarados em `.sentry/specs/` com as funções de teste reais e
|
|
261
|
+
reporta as quatro dimensões.
|
|
262
|
+
|
|
263
|
+
## Licença
|
|
264
|
+
|
|
265
|
+
MIT
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
# Sentry
|
|
2
|
+
|
|
3
|
+
CLI de qualidade de teste orientada a mudança. O `sentry` cria a pasta da spec, valida a matriz de casos em markdown, roda a suíte, lê o diff e a cobertura, e emite um veredito auditável — e deixa o fluxo escrito para o agente de IA que for implementar a mudança.
|
|
4
|
+
|
|
5
|
+
Markdown é a fonte da intenção: a CLI parseia e valida `CASES.md` e `PROMPT.md` — ela nunca os escreve. O agente de IA faz a redação; o Sentry garante estrutura, rastreabilidade e veredito.
|
|
6
|
+
|
|
7
|
+
> Não confundir com o [Sentry da getsentry](https://sentry.io) (monitoramento de erros). Este projeto é distribuído como `sentry-test`.
|
|
8
|
+
|
|
9
|
+
## A divisão de responsabilidade
|
|
10
|
+
|
|
11
|
+
- **O agente de IA declara intenção** — escreve o `CASES.md`: requisito, camada, tipo, prioridade, entrada, resultado esperado.
|
|
12
|
+
- **O Sentry mede a realidade** — decide status, teste associado, evidência e veredito.
|
|
13
|
+
|
|
14
|
+
O agente nunca escreve status. O Sentry nunca chama um modelo. É isso que torna o veredito auditável e reproduzível.
|
|
15
|
+
|
|
16
|
+
## Instalação
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
pip install sentry-test
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Requer Python 3.11+. Confira com `sentry --version` (imprime a versão do pacote).
|
|
23
|
+
|
|
24
|
+
Se faltar `pytest` ou `coverage`, o `init` avisa. Para instalar junto:
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
sentry init --install
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Setup
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
cd seu-projeto
|
|
34
|
+
sentry init
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Cria `.sentry/` (specs, execuções, relatórios e banco), o `sentry.toml`, as entradas do `.gitignore`, e escreve o fluxo em dois lugares:
|
|
38
|
+
|
|
39
|
+
- **Skill `sentry-cases`** em `.claude/skills/sentry-cases/SKILL.md` — carregada automaticamente pelo Claude Code e por agentes que seguem essa convenção.
|
|
40
|
+
- **`AGENT-SENTRY.md`** na raiz do projeto — o mesmo fluxo em markdown puro, sem depender de convenção de nenhuma ferramenta.
|
|
41
|
+
|
|
42
|
+
Para outros agentes (Cursor, Windsurf, Codex, opencode), aponte-os para o `AGENT-SENTRY.md` no arquivo de regras que cada um já usa — por exemplo, uma linha em `.cursor/rules` ou `AGENTS.md`:
|
|
43
|
+
|
|
44
|
+
```markdown
|
|
45
|
+
Para escrever ou revisar casos de teste, siga AGENT-SENTRY.md.
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
`init` é idempotente: não apaga histórico, não sobrescreve configuração existente, não duplica estruturas.
|
|
49
|
+
|
|
50
|
+
## O fluxo
|
|
51
|
+
|
|
52
|
+
1. `sentry new "cadastro de cliente"` — cria `.sentry/specs/cadastro-de-cliente/` com `PROMPT.md` (pedido preservado) e `CASES.md` em branco
|
|
53
|
+
2. **`sentry-cases`** — seu agente pergunta o que estiver ambíguo e preenche o `CASES.md` seguindo o template
|
|
54
|
+
3. `sentry check cadastro-de-cliente` — estrutura válida? classes de equivalência do catálogo cobertas?
|
|
55
|
+
4. seu agente liga cada caso ao teste real com o marcador `# cenario: <nome exato do caso>`
|
|
56
|
+
5. `sentry run --spec cadastro-de-cliente --run-tests` — roda a suíte, lê diff e cobertura, aplica as regras, persiste
|
|
57
|
+
6. `sentry report` / `sentry history` — releitura e comparação entre execuções
|
|
58
|
+
|
|
59
|
+
Todo passo também funciona sem agente, pelos comandos abaixo.
|
|
60
|
+
|
|
61
|
+
## Comandos
|
|
62
|
+
|
|
63
|
+
Código de saída `0` em sucesso; veja a tabela de códigos adiante.
|
|
64
|
+
|
|
65
|
+
| Comando | O que faz |
|
|
66
|
+
| --- | --- |
|
|
67
|
+
| `sentry init [--install]` | Prepara o repositório: `.sentry/`, `sentry.toml`, `.gitignore`, guia de agente e skills. Com `--install`, instala as dependências ausentes. |
|
|
68
|
+
| `sentry new <nome> [--prompt "..."] [--json]` | Cria a pasta da spec com slug derivado do nome. `--json` emite template, vocabulário aceito e classes cobradas, para o agente consumir. |
|
|
69
|
+
| `sentry check [<slug>\|all]` | Valida `CASES.md`: estrutura, vocabulário e cobrança de classes de equivalência. `all` valida todas as specs juntas. |
|
|
70
|
+
| `sentry run [--spec <slug>\|all] [--run-tests]` | Executa a análise e persiste. Sem `--run-tests` não há cobertura, e o veredito tende a `inconclusivo`. |
|
|
71
|
+
| `sentry report` | Exibe o último relatório (`.sentry/reports/latest.md`). |
|
|
72
|
+
| `sentry history` | Lista execuções e compara as duas últimas: cobertura, testes, achados novos, resolvidos e persistentes. |
|
|
73
|
+
| `sentry clear [--keep-last N] [--yes]` | Poda execuções e relatórios antigos. Sem `--yes` apenas mostra o que sairia — apagar histórico é irreversível. Nunca toca em `.sentry/specs/`. |
|
|
74
|
+
|
|
75
|
+
## Códigos de saída
|
|
76
|
+
|
|
77
|
+
Quatro estados distinguíveis, para separar "código mal testado" de "meu ambiente quebrou":
|
|
78
|
+
|
|
79
|
+
| Código | Significado |
|
|
80
|
+
| --- | --- |
|
|
81
|
+
| `0` | aprovado |
|
|
82
|
+
| `1` | aprovado com ressalvas |
|
|
83
|
+
| `2` | reprovado |
|
|
84
|
+
| `3` | inconclusivo ou erro de infraestrutura |
|
|
85
|
+
|
|
86
|
+
Erro de infraestrutura nunca produz veredito aprovado: uma suíte que não conseguiu rodar é diferente de uma suíte que reprovou.
|
|
87
|
+
|
|
88
|
+
`sentry check` mantém semântica própria: `0` estrutura válida, `1` erros estruturais, `2` não foi possível resolver a spec.
|
|
89
|
+
|
|
90
|
+
## Skills
|
|
91
|
+
|
|
92
|
+
Geradas para cada agente configurado; o `AGENT-SENTRY.md` cobre os demais.
|
|
93
|
+
|
|
94
|
+
| Workflow | O que o agente faz |
|
|
95
|
+
| --- | --- |
|
|
96
|
+
| `sentry-cases` | Recebe o pedido em texto livre, cria a spec, **pergunta antes de escrever** toda ambiguidade que mude um caso, preenche o `CASES.md`, liga cada caso ao teste com `# cenario:` e roda `check` até fechar limpo. Nunca escreve status. |
|
|
97
|
+
|
|
98
|
+
## Regras determinísticas
|
|
99
|
+
|
|
100
|
+
Dez regras, com severidade configurável por projeto.
|
|
101
|
+
|
|
102
|
+
| Regra | Severidade padrão | Dispara quando |
|
|
103
|
+
| --- | --- | --- |
|
|
104
|
+
| `test-failing` | crítica | a suíte tem teste falhando |
|
|
105
|
+
| `case-spec-invalid` | crítica | o `CASES.md` tem erro estrutural |
|
|
106
|
+
| `changed-code-uncovered` | alta | cobertura do código alterado é zero |
|
|
107
|
+
| `scenario-without-test` | alta | caso declarado sem teste associado |
|
|
108
|
+
| `error-path-without-test` | alta | `raise`/`throw` em linha alterada que nenhum teste executou |
|
|
109
|
+
| `missing-equivalence-class` | alta | classe exigida pelo catálogo que nenhum caso cobre |
|
|
110
|
+
| `coverage-below-threshold` | alta | cobertura do código alterado abaixo do limiar declarado |
|
|
111
|
+
| `requirement-without-scenario` | média | requisito sem cenário correspondente |
|
|
112
|
+
| `coverage-missing` | média | não foi possível calcular a cobertura do código alterado |
|
|
113
|
+
| `global-coverage-below-threshold` | média | cobertura global abaixo do limiar declarado |
|
|
114
|
+
|
|
115
|
+
Sem limiar declarado, o Sentry não inventa um mínimo. Quem define "quanto basta" é o projeto, e o relatório registra o número aplicado.
|
|
116
|
+
|
|
117
|
+
## Catálogo de classes de equivalência
|
|
118
|
+
|
|
119
|
+
Tabela fixa de situações que precisam de teste, **por tipo de campo**. Não gera casos: cobra os que o agente deixou de declarar.
|
|
120
|
+
|
|
121
|
+
Tipos conhecidos: `cpf`, `cnpj`, `email`, `senha`, `data`, `telefone`, `cep`, `inteiro`, `decimal`, `texto`, `rota`.
|
|
122
|
+
|
|
123
|
+
Uma classe que não faz sentido para o campo pode ser dispensada **com justificativa**, em vez de virar caso artificial ou cobrança eterna:
|
|
124
|
+
|
|
125
|
+
```markdown
|
|
126
|
+
## Classes não aplicáveis
|
|
127
|
+
|
|
128
|
+
- **exclude/tamanho-maximo-excedido**: é parâmetro de configuração, não campo de formulário
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
A dispensa remove o achado, mas fica registrada no relatório — nada some em silêncio.
|
|
132
|
+
|
|
133
|
+
## Dimensões de cobertura
|
|
134
|
+
|
|
135
|
+
Cada uma reporta `coberta`, `parcial`, `não coberta` ou `não aplicável`, com evidência.
|
|
136
|
+
|
|
137
|
+
| Dimensão | De onde tira a evidência |
|
|
138
|
+
| --- | --- |
|
|
139
|
+
| requisitos e regras de negócio | cenários da spec com teste associado |
|
|
140
|
+
| APIs, persistência, transações e integrações | casos de tipo `contrato`/`integração` e camada `integração` |
|
|
141
|
+
| exceções, resiliência e recuperação | caminhos de erro alterados executados por algum teste |
|
|
142
|
+
| segurança e autorização | campos de tipo `rota` com todas as classes de acesso cobertas |
|
|
143
|
+
|
|
144
|
+
`não aplicável` é distinto de `não coberta`: um projeto sem rotas não é punido na dimensão de segurança.
|
|
145
|
+
|
|
146
|
+
## Configuração
|
|
147
|
+
|
|
148
|
+
`sentry.toml` na raiz, versionável, sem segredos. Tudo é opcional além do que o `init` já escreve.
|
|
149
|
+
|
|
150
|
+
```toml
|
|
151
|
+
[project]
|
|
152
|
+
name = "meu-projeto"
|
|
153
|
+
|
|
154
|
+
[specs]
|
|
155
|
+
path = ".sentry/specs"
|
|
156
|
+
|
|
157
|
+
[test] # qualquer executor que exporte JUnit XML
|
|
158
|
+
command = "npx jest"
|
|
159
|
+
junit_xml = "reports/junit.xml" # sem isto, o Sentry injeta --junitxml (pytest)
|
|
160
|
+
|
|
161
|
+
[tests] # onde procurar testes
|
|
162
|
+
paths = ["tests"] # padrão: tests, test, spec, __tests__
|
|
163
|
+
|
|
164
|
+
[coverage] # relatório gerado pela suíte do próprio projeto
|
|
165
|
+
path = "coverage/lcov.info"
|
|
166
|
+
format = "lcov" # opcional: detectado pelo conteúdo quando omitido
|
|
167
|
+
|
|
168
|
+
[analysis]
|
|
169
|
+
run_tests_by_default = false
|
|
170
|
+
timeout_seconds = 300
|
|
171
|
+
exclude = ["frontend/"] # diretórios fora do escopo da análise
|
|
172
|
+
|
|
173
|
+
[policy.thresholds] # sem isto, nenhum mínimo é cobrado
|
|
174
|
+
changed_coverage = 85
|
|
175
|
+
global_coverage = 90
|
|
176
|
+
|
|
177
|
+
[policy.severities] # sobrescreve a severidade de qualquer regra
|
|
178
|
+
coverage-missing = "alta"
|
|
179
|
+
|
|
180
|
+
[catalog.fields] # tipos de campo do seu domínio
|
|
181
|
+
matricula = ["vazio", "formato-invalido", "valida"]
|
|
182
|
+
|
|
183
|
+
[dimensions] # eixos que não se aplicam ao projeto
|
|
184
|
+
disabled = []
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
`.sentry/` guarda specs, execuções, relatórios e o banco. Fica fora do Git, com uma exceção deliberada: `.sentry/reports/latest.md` é versionado, para o veredito aparecer no diff da PR sem que o revisor precise rodar o Sentry.
|
|
188
|
+
|
|
189
|
+
O histórico é mantido indefinidamente, e cresce a cada execução. Para podar:
|
|
190
|
+
|
|
191
|
+
```bash
|
|
192
|
+
sentry clear --keep-last 10 # mostra o que sairia
|
|
193
|
+
sentry clear --keep-last 10 --yes # remove
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
As specs nunca são removidas: são intenção declarada, não evidência gerada.
|
|
197
|
+
|
|
198
|
+
## Stacks suportadas
|
|
199
|
+
|
|
200
|
+
A **derivação** — do pedido à matriz de casos — é agnóstica de linguagem: o `CASES.md` é markdown e o catálogo raciocina sobre tipo de dado, não sobre código.
|
|
201
|
+
|
|
202
|
+
A **verificação** depende do formato de intercâmbio que sua suíte exporta, não da ferramenta:
|
|
203
|
+
|
|
204
|
+
| Capacidade | Suporte |
|
|
205
|
+
| --- | --- |
|
|
206
|
+
| Execução da suíte | qualquer comando que exporte **JUnit XML** — pytest, Jest, Vitest, `go test` (gotestsum), Surefire, `dotnet test`, RSpec, PHPUnit |
|
|
207
|
+
| Cobertura | **lcov** (nyc, c8, Jest, simplecov), **Cobertura XML** (JaCoCo, coverlet), **coverage.py** (JSON) — detectados pelo conteúdo |
|
|
208
|
+
| Rastreabilidade caso↔teste | `.py`, `.js`/`.jsx`/`.ts`/`.tsx`, `.go`, `.java`/`.kt`, `.cs`, `.rb`, `.php`, `.rs` — e o marcador `cenario:` funciona em qualquer comentário |
|
|
209
|
+
| Caminhos de erro | por AST em Python; por padrão sintático (`throw`, `catch`, `panic`, `rescue`, `panic!`) nas demais |
|
|
210
|
+
| Análise de impacto | 12 extensões de código-fonte |
|
|
211
|
+
|
|
212
|
+
A detecção de caminho de erro fora de Python é menos precisa que AST, e o relatório registra essa diferença como limitação — nunca a esconde.
|
|
213
|
+
|
|
214
|
+
Camada `frontend` é recusada de propósito: sem adaptador que a verifique, um caso declarado ficaria preso em `não coberto` para sempre.
|
|
215
|
+
|
|
216
|
+
## Local-first
|
|
217
|
+
|
|
218
|
+
Nenhuma telemetria, nenhuma chamada externa, nenhum envio de código ou diff. Todo o histórico permanece na máquina.
|
|
219
|
+
|
|
220
|
+
## Desenvolvimento
|
|
221
|
+
|
|
222
|
+
```bash
|
|
223
|
+
python -m pip install -e .
|
|
224
|
+
python -m pytest
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
O Sentry se analisa: `sentry run --spec all --run-tests` na raiz do repositório
|
|
228
|
+
casa os casos declarados em `.sentry/specs/` com as funções de teste reais e
|
|
229
|
+
reporta as quatro dimensões.
|
|
230
|
+
|
|
231
|
+
## Licença
|
|
232
|
+
|
|
233
|
+
MIT
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=68"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "sentry-test"
|
|
7
|
+
version = "1.0.0"
|
|
8
|
+
description = "Test quality intelligence for change-oriented reviews"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.11"
|
|
11
|
+
license = { file = "LICENSE" }
|
|
12
|
+
authors = [{ name = "Lucas Nicolau Ferreira" }]
|
|
13
|
+
|
|
14
|
+
[project.scripts]
|
|
15
|
+
sentry = "sentrytest.cli:main"
|
|
16
|
+
|
|
17
|
+
[tool.setuptools.packages.find]
|
|
18
|
+
where = ["src"]
|
|
19
|
+
|
|
20
|
+
[tool.pytest.ini_options]
|
|
21
|
+
testpaths = ["tests"]
|