product-runner 0.5.0

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.
Files changed (37) hide show
  1. package/README.md +165 -0
  2. package/common/agents/README.md +68 -0
  3. package/common/agents/agente-conceituacao.md +141 -0
  4. package/common/agents/agente-documentacao-funcional.md +107 -0
  5. package/common/agents/agente-gerador-spec.md +106 -0
  6. package/common/agents/agente-kickoff.md +121 -0
  7. package/common/agents/agente-prod-runner.md +107 -0
  8. package/common/agents/agente-review-code.md +97 -0
  9. package/common/agents/agente-review-llm.md +94 -0
  10. package/common/agents/agente-review-product.md +98 -0
  11. package/common/agents/agente-user-review.md +99 -0
  12. package/common/agents/protocolo-de-gates.md +51 -0
  13. package/common/claude-md.template.md +210 -0
  14. package/common/design-principles.md +229 -0
  15. package/common/lessons-learned.md +440 -0
  16. package/common/pipeline.md +143 -0
  17. package/common/spec-guide.md +327 -0
  18. package/common/specs/_open-issues.md +46 -0
  19. package/common/specs/_overview.md +75 -0
  20. package/dist/cli.js +187 -0
  21. package/dist/migrations.js +147 -0
  22. package/dist/scaffold.js +276 -0
  23. package/dist/update.js +400 -0
  24. package/migrations/0.3.0.md +54 -0
  25. package/migrations/0.4.0.md +76 -0
  26. package/migrations/0.5.0.md +55 -0
  27. package/migrations/README.md +68 -0
  28. package/package.json +41 -0
  29. package/profile-cli/README.md +54 -0
  30. package/profile-cli/claude-md.extension.md +102 -0
  31. package/profile-cli/code-patterns.md +363 -0
  32. package/profile-ssr/DESIGN-SYSTEM.md +795 -0
  33. package/profile-ssr/README.md +51 -0
  34. package/profile-ssr/api-patterns.md +70 -0
  35. package/profile-ssr/claude-md.extension.md +113 -0
  36. package/profile-ssr/code-patterns.md +175 -0
  37. package/profile-ssr/ui-patterns.md +97 -0
package/package.json ADDED
@@ -0,0 +1,41 @@
1
+ {
2
+ "name": "product-runner",
3
+ "version": "0.5.0",
4
+ "description": "Scaffold de docs para projetos TypeScript com desenvolvimento assistido por AI: gera CLAUDE.md + docs/ a partir de templates vivos (common + perfil cli/ssr).",
5
+ "type": "module",
6
+ "bin": {
7
+ "product-runner": "dist/cli.js"
8
+ },
9
+ "files": [
10
+ "dist",
11
+ "!dist/**/*.test.js",
12
+ "common",
13
+ "profile-cli",
14
+ "profile-ssr",
15
+ "migrations"
16
+ ],
17
+ "engines": {
18
+ "node": ">=18"
19
+ },
20
+ "scripts": {
21
+ "build": "tsc -p tsconfig.json",
22
+ "dev": "node --experimental-strip-types src/cli.ts",
23
+ "test": "npm run build && node --test dist/*.test.js",
24
+ "prepare": "npm run build",
25
+ "prepack": "npm run build",
26
+ "prepublishOnly": "npm run build"
27
+ },
28
+ "keywords": [
29
+ "scaffold",
30
+ "template",
31
+ "claude",
32
+ "ai-assisted",
33
+ "typescript",
34
+ "docs"
35
+ ],
36
+ "license": "MIT",
37
+ "devDependencies": {
38
+ "@types/node": "^22.0.0",
39
+ "typescript": "^5.6.0"
40
+ }
41
+ }
@@ -0,0 +1,54 @@
1
+ # Perfil: CLI / script Node em loop
2
+
3
+ Use este perfil em projetos que:
4
+
5
+ - Rodam como **script Node terminal** (não servidor HTTP).
6
+ - Têm um **loop principal** (infinito ou periódico).
7
+ - Fazem I/O com **lib externa** (broker, AI API, queue, etc.) que precisa ser isolada.
8
+ - Persistem estado via **arquivos locais** (JSON) ou DB.
9
+ - Não têm UI — observability via logs + arquivos consumidos por
10
+ ferramentas tipo OpenSearch/Kibana.
11
+
12
+ ## Conteúdo
13
+
14
+ | Arquivo | Pra quê |
15
+ |---|---|
16
+ | [code-patterns](./code-patterns.md) | Estrutura de pastas, schemas Zod, port/adapter pra integrações, padrões de erro, persistência |
17
+ | [claude-md.extension](../CLAUDE.md) | Seções específicas pra CLI (comandos `npm run`, configuração `.env`, observability via arquivos) |
18
+
19
+ ## Como combinar com `common/`
20
+
21
+ Use o CLI — ele copia `common/` + este perfil pra `docs/` e gera o
22
+ `CLAUDE.md` raiz (mescla template + extension, substitui `{...}`):
23
+
24
+ ```bash
25
+ npx product-runner --name meu-projeto --profile cli --dir .
26
+ ```
27
+
28
+ Equivalente manual, se preferir sem npm:
29
+
30
+ ```bash
31
+ cp common/*.md meu-projeto/docs/
32
+ cp profile-cli/*.md meu-projeto/docs/
33
+ cat common/claude-md.template.md profile-cli/claude-md.extension.md \
34
+ > meu-projeto/CLAUDE.md
35
+ # Adapta valores entre {} pelos do projeto.
36
+ ```
37
+
38
+ ## Origem
39
+
40
+ Conteúdo extraído de:
41
+ - **tradeBot** (snapshot tradebot-202605, refactor 11 specs)
42
+
43
+ Adaptações feitas pra generalizar:
44
+ - `BrokerClient` virou termo genérico "ExternalAdapter" em alguns
45
+ exemplos.
46
+ - `tradeBot`/`Binance` → `{ProjectName}` / `{ExternalSystem}` quando
47
+ apropriado.
48
+ - Defaults específicos de trade (multipliers, etc.) foram trocados
49
+ por placeholders.
50
+
51
+ ## Anti-pattern: usar este perfil pra projeto SSR
52
+
53
+ Web SSR tem fronteira HTTP, request/response, UI. Estrutura aqui
54
+ não cobre. Use `profile-ssr/` no lugar.
@@ -0,0 +1,102 @@
1
+ <!--
2
+ Extensão do CLAUDE.md — Perfil CLI.
3
+ Este arquivo NÃO é concatenado: cada bloco abaixo declara, via diretiva
4
+ `prod-runner-merge`, como dobra numa seção do template-base (common/claude-md.template.md).
5
+ Modos: replace (troca a seção), append (acrescenta ao fim da seção),
6
+ after (insere logo após a seção). Edite o conteúdo, não as diretivas.
7
+ -->
8
+
9
+ <!-- prod-runner-merge: append section="Stack" -->
10
+
11
+ - **Broker / lib externa:** {ex: `@binance/connector`, `openai`, etc.} —
12
+ abstraído via `BrokerClient` (port/adapter)
13
+ - **Config:** `dotenv` + `.env`
14
+ - **Persistência:** arquivos JSON locais (`actualState.json`, `history/`)
15
+ - **Observability:** arquivos JSON formato Kibana consumidos por OpenSearch
16
+ local (ou similar)
17
+ - **Containerização:** Docker (`docker-compose.yml`) — opcional
18
+
19
+ <!-- prod-runner-merge: replace section="Princípio central" -->
20
+
21
+ ### Princípio central
22
+
23
+ Lógica de domínio (cálculo, decisão, regras) é código TypeScript
24
+ puro, sem acoplamento com lib externa, file system ou env. Acesso
25
+ à lib externa via interface (port). Persistência via funções
26
+ dedicadas. Loop principal é casca fina que orquestra.
27
+
28
+ <!-- prod-runner-merge: replace section="Estrutura de pastas" -->
29
+
30
+ ### Estrutura de pastas
31
+
32
+ ```
33
+ {project}/
34
+ ├── CLAUDE.md
35
+ ├── index.ts ← entrypoint mínimo (loop fino)
36
+ ├── docs/
37
+ ├── specs/
38
+ ├── domain/
39
+ │ ├── {externalAdapter}.ts ← interface (port)
40
+ │ └── errors.ts ← classes de erro de domínio
41
+ ├── services/
42
+ │ ├── {dominio}/ ← lógica pura + schemas
43
+ │ ├── persistence/ ← load/save JSON, mappers
44
+ │ └── integrations/ ← adapters (implementações dos ports)
45
+ ├── tests/
46
+ └── dist/ ← outDir do tsc (gitignored)
47
+ ```
48
+
49
+ <!-- prod-runner-merge: replace section="Comandos úteis" -->
50
+
51
+ ## Comandos úteis
52
+
53
+ ```bash
54
+ npm install # deps
55
+ npm run start # compilar e rodar (loop infinito)
56
+ npm run start:reset # apaga estado e recomeça do zero (se aplicável)
57
+ npm test # testes
58
+ npx tsc --noEmit # typecheck
59
+ docker compose up -d # infra (OpenSearch local, etc.) — opcional
60
+ ```
61
+
62
+ <!-- prod-runner-merge: replace section="Configuração" -->
63
+
64
+ ## Configuração
65
+
66
+ | Arquivo | Conteúdo | Comitado? |
67
+ | ------------------------ | ----------------------------------------- | --------- |
68
+ | `.env` | Segredos da lib externa (API keys, etc.) | ❌ NUNCA |
69
+ | `.env.example` | Mesmas chaves sem valor | ✅ |
70
+ | `global.json` ou similar | Defaults globais | ✅ |
71
+ | `actualState.json` | Estado runtime (auto-gerado) | ❌ |
72
+ | `history/*` | Logs estruturados | ❌ |
73
+
74
+ Hot-reload de configs (se aplicável): a cada N segundos no loop principal
75
+ (definir `configCacheTime`).
76
+
77
+ <!-- prod-runner-merge: append section="Convenções de código" -->
78
+
79
+ ### Comportamento do loop após erro (CLI)
80
+
81
+ O loop principal **NÃO deve morrer silenciosamente**. Erros não
82
+ tratados disparam `console.error` + exit code != 0. Pattern:
83
+
84
+ ```ts
85
+ runTradingLoop({ broker }).catch((error) => {
86
+ console.error("FATAL: bot loop crashed", error);
87
+ process.exit(1);
88
+ });
89
+ ```
90
+
91
+ Loop interno tem `try/catch` por par/tarefa pra continuar processando
92
+ outros, mas erro de orquestração mata o processo.
93
+
94
+ ### Observability (CLI)
95
+
96
+ Status quo recomendado:
97
+
98
+ - Logs estruturados em `history/*.json` formato Kibana (`_index`,
99
+ `_source`, `_id`).
100
+ - OpenSearch local via Docker pra dashboards (ou similar).
101
+ - `console.log` apenas pra orquestração (logger estruturado entra
102
+ em spec dedicada se necessário).
@@ -0,0 +1,363 @@
1
+ # Code patterns
2
+
3
+ Padrões para schemas, tipos, services, broker abstrato,
4
+ erros e persistência neste projeto.
5
+
6
+ Este documento descreve o **alvo arquitetural**. O código atual
7
+ não está todo nesse formato — chegamos lá pelas specs em `specs/`.
8
+ Quando houver divergência entre este doc e o código, este doc
9
+ ganha; o código é o que está sendo refatorado.
10
+
11
+ ---
12
+
13
+ ## Estrutura de pastas (alvo)
14
+
15
+ ```
16
+ tradeBotRefatoring/
17
+ ├── CLAUDE.md
18
+ ├── index.ts ← entrypoint mínimo (loop fino)
19
+ ├── docs/ ← este e outros docs de referência
20
+ ├── specs/ ← specs por domínio
21
+ ├── domain/
22
+ │ ├── broker.ts ← interface BrokerClient
23
+ │ └── errors.ts ← TradeError e subclasses
24
+ ├── services/
25
+ │ ├── waves/
26
+ │ │ ├── schema.ts ← WavesHistorySchema, derivados
27
+ │ │ ├── waves-history.ts ← classe / lógica de detecção
28
+ │ │ └── tendency.ts ← cálculos de tendência
29
+ │ ├── trading/
30
+ │ │ ├── schema.ts ← TradingDataSchema, BuyOrder, SellOrder
31
+ │ │ ├── limits.ts ← recalculateLimits puro
32
+ │ │ ├── decisions.ts ← canBuy / canSell
33
+ │ │ └── loop.ts ← orquestração do loop
34
+ │ ├── persistence/
35
+ │ │ ├── schema.ts ← BotStateSchema (root do estado)
36
+ │ │ ├── load.ts ← reconstrução com schema
37
+ │ │ ├── save.ts ← serialização
38
+ │ │ └── kibana.ts ← mapper toKibana
39
+ │ └── integrations/
40
+ │ └── binance-broker.ts ← adapter @binance/connector → BrokerClient
41
+ └── tests/ ← Vitest (a partir de setup/01)
42
+ ```
43
+
44
+ ---
45
+
46
+ ## Schemas e tipos
47
+
48
+ ### Entity raiz
49
+
50
+ Cada domínio tem `schema.ts` com a entity Zod. Tipos derivam
51
+ sempre via `z.infer`.
52
+
53
+ ```ts
54
+ // services/trading/schema.ts
55
+ import { z } from "zod";
56
+
57
+ export const TradingDataSchema = z.object({
58
+ tradeSymbol: z.string(),
59
+ totalToBuy: z.number().nonnegative(),
60
+ sliceToBuy: z.number().positive(),
61
+ currentSliceToBuy: z.number().positive(),
62
+ buyOrdersWhithoutStack: z.number().int().nonnegative(),
63
+ lastTurnDateTime: z.coerce.date().nullable(),
64
+ lastMaxPrice: z.number().nullable(),
65
+ lastMinPrice: z.number().nullable(),
66
+ smallerBuyNotSelledPrice: z.number().nullable(),
67
+ lastCheckedPrice: z.number().nullable(),
68
+ maxLimitPriceToBuy: z.number().nullable(),
69
+ maxLimitPriceToBuy_calc: z.string().nullable(),
70
+ minLimitPriceToSell: z.number().nullable(),
71
+ brokeUpFlowWaitingLimitPrice: z.number().nullable(),
72
+ brokeDownFlowWaitingLimitPrice: z.number().nullable(),
73
+ });
74
+
75
+ export type TradingData = z.infer<typeof TradingDataSchema>;
76
+ ```
77
+
78
+ ### Regras
79
+
80
+ - Naming: `XxxSchema` pra Zod, `Xxx` pra type inferido.
81
+ - Nullable explícito (`.nullable()`), não `.optional()` por engano.
82
+ - Datas no JSON viram `string`; usar `z.coerce.date()` se quiser `Date` em runtime.
83
+ - Sem `interface` ou `type` paralelo ao schema.
84
+
85
+ ### Derivações
86
+
87
+ ```ts
88
+ // Input com subset + override
89
+ export const CreateBuyOrderInput = BuyOrderSchema.pick({ gotPrice: true, quantity: true, tradeSymbol: true }).extend({
90
+ orderType: z.enum(["LIMIT_MAKER", "MARKET"]),
91
+ });
92
+
93
+ export type CreateBuyOrderInput = z.infer<typeof CreateBuyOrderInput>;
94
+
95
+ // Output sem campos internos
96
+ export const BuyOrderOutput = BuyOrderSchema.omit({ binanceOrderId: true }).extend({ ageMs: z.number() });
97
+ ```
98
+
99
+ ---
100
+
101
+ ## Validação na fronteira
102
+
103
+ Toda entrada do mundo externo passa por `safeParse` ou `parse`
104
+ ANTES de chegar na lógica.
105
+
106
+ ### Boot — leitura de config
107
+
108
+ ```ts
109
+ // services/persistence/load.ts
110
+ import { GlobalConfigSchema } from "../trading/schema";
111
+
112
+ export function loadGlobalConfig(): GlobalConfig {
113
+ const raw = JSON.parse(fs.readFileSync("global.json", "utf-8"));
114
+ const result = GlobalConfigSchema.safeParse(raw);
115
+ if (!result.success) {
116
+ console.error("FATAL: global.json inválido", result.error.format());
117
+ process.exit(1);
118
+ }
119
+ return result.data;
120
+ }
121
+ ```
122
+
123
+ ### Resposta de broker
124
+
125
+ ```ts
126
+ const BinanceTickerResponseSchema = z.object({
127
+ symbol: z.string(),
128
+ price: z.string().regex(/^\d+(\.\d+)?$/),
129
+ });
130
+
131
+ // dentro do BinanceBroker:
132
+ const result = BinanceTickerResponseSchema.parse(response.data);
133
+ return { symbol: result.symbol, priceCents: toCents(result.price) };
134
+ ```
135
+
136
+ ### Reload de estado
137
+
138
+ Substituir `Object.setPrototypeOf` (vindo da spec 00) por
139
+ reconstrução validada (a partir de refactor/05):
140
+
141
+ ```ts
142
+ // services/persistence/load.ts
143
+ export function loadBotState(): BotState | null {
144
+ if (!fs.existsSync("actualTradeEnviroments.json")) return null;
145
+ const raw = JSON.parse(fs.readFileSync("actualTradeEnviroments.json", "utf-8"));
146
+ return BotStateSchema.parse(raw);
147
+ }
148
+ ```
149
+
150
+ ---
151
+
152
+ ## Services
153
+
154
+ ### Estrutura de um domínio
155
+
156
+ ```
157
+ services/{domínio}/
158
+ ├── schema.ts ← entity + derivados
159
+ ├── {lógica}.ts ← funções puras
160
+ └── ...
161
+ ```
162
+
163
+ ### Regras
164
+
165
+ - Funções puras quando possível: input → output, sem side-effects.
166
+ - Side-effects (leitura, escrita, log) ficam em arquivos dedicados:
167
+ `persistence/`, `integrations/`, ou em camada de orquestração.
168
+ - Services podem importar outros services do MESMO nível ou inferiores.
169
+ - Services NUNCA importam `@binance/connector`, `dotenv`, `fs`, `process`.
170
+ - Services NUNCA chamam `console.log`. Logs são responsabilidade
171
+ do orquestrador (loop) ou de logger estruturado.
172
+
173
+ ### Exemplo: lógica pura
174
+
175
+ ```ts
176
+ // services/trading/limits.ts
177
+
178
+ export function recalculateLimits(input: {
179
+ actualPrice: number;
180
+ waves: WavesSnapshot;
181
+ quantityOfBuyOrdersNotSelled: number;
182
+ config: ConfigValues;
183
+ trade: TradingData;
184
+ }): RecalculatedLimits {
185
+ // ...lógica determinística, sem ed.log, sem process, sem fs
186
+ return {
187
+ maxLimitPriceToBuy,
188
+ minLimitPriceToSell,
189
+ brokeUpFlowWaitingLimitPrice,
190
+ brokeDownFlowWaitingLimitPrice,
191
+ maxLimitPriceToBuy_calc,
192
+ };
193
+ }
194
+ ```
195
+
196
+ Função pura é alvo direto de teste unitário: alimentar inputs,
197
+ verificar outputs.
198
+
199
+ ---
200
+
201
+ ## BrokerClient (port)
202
+
203
+ Interface no domínio. Implementação em `services/integrations/`.
204
+
205
+ ```ts
206
+ // domain/broker.ts
207
+ export interface BrokerClient {
208
+ getTickerPrice(symbol: string): Promise<{ symbol: string; price: number }>;
209
+ placeOrder(input: PlaceOrderInput): Promise<PlacedOrder>;
210
+ getAccountState(): Promise<AccountState>;
211
+ }
212
+ ```
213
+
214
+ ```ts
215
+ // services/integrations/binance-broker.ts
216
+ import { Spot } from "@binance/connector";
217
+
218
+ export class BinanceBroker implements BrokerClient {
219
+ constructor(
220
+ private apiKey: string,
221
+ private apiSecret: string
222
+ ) {
223
+ this.client = new Spot(apiKey, apiSecret);
224
+ }
225
+ async getTickerPrice(symbol: string) {
226
+ const { data } = await this.client.tickerPrice(symbol);
227
+ const parsed = BinanceTickerResponseSchema.parse(data);
228
+ return { symbol: parsed.symbol, price: Number(parsed.price) };
229
+ }
230
+ // ...
231
+ }
232
+ ```
233
+
234
+ ### Por quê
235
+
236
+ - Lógica de trade testável com mock de broker (`InMemoryBroker`).
237
+ - Trocar Binance por outra exchange é trocar 1 arquivo.
238
+ - Validação da resposta vive no adapter, não espalhada.
239
+
240
+ ---
241
+
242
+ ## Erros de domínio
243
+
244
+ Lógica nunca lança `Error` puro. Usa classe específica.
245
+
246
+ ```ts
247
+ // domain/errors.ts
248
+ export class TradeError extends Error {
249
+ constructor(
250
+ message: string,
251
+ public code: string
252
+ ) {
253
+ super(message);
254
+ this.name = "TradeError";
255
+ }
256
+ }
257
+
258
+ export class SafeLimitError extends TradeError {
259
+ constructor(message: string) {
260
+ super(message, "SAFE_LIMIT_VIOLATED");
261
+ }
262
+ }
263
+
264
+ export class BrokerError extends TradeError {
265
+ constructor(
266
+ message: string,
267
+ public binanceMsg?: string
268
+ ) {
269
+ super(message, "BROKER_ERROR");
270
+ }
271
+ }
272
+
273
+ export class InvalidConfigError extends TradeError {
274
+ constructor(message: string) {
275
+ super(message, "INVALID_CONFIG");
276
+ }
277
+ }
278
+ ```
279
+
280
+ ### Regras
281
+
282
+ - Mensagens em pt-BR (consistente com logs existentes).
283
+ - `code` em SCREAMING_SNAKE_CASE.
284
+ - Stack trace preservado: `throw error` ou `throw new XxxError(msg, error)` nunca `throw error.message`.
285
+
286
+ ---
287
+
288
+ ## Mapper toKibana
289
+
290
+ Centralizado em `services/persistence/kibana.ts`.
291
+
292
+ ```ts
293
+ export function toKibana<T>(record: T, id: string, index = "tradebot"): KibanaRecord<T> {
294
+ return {
295
+ _index: index,
296
+ _type: "_doc",
297
+ _id: id,
298
+ _score: 1,
299
+ _source: record,
300
+ };
301
+ }
302
+
303
+ export function toKibanaJsonl<T>(records: Array<{ data: T; id: string }>): string {
304
+ return records.map(({ data, id }) => JSON.stringify(toKibana(data, id))).join("\n") + "\n";
305
+ }
306
+ ```
307
+
308
+ Substitui o `formatDocumentToKibana` espalhado no `index.ts` atual.
309
+
310
+ ---
311
+
312
+ ## Persistência
313
+
314
+ ### Save
315
+
316
+ ```ts
317
+ // services/persistence/save.ts
318
+ export function saveBotState(state: BotState) {
319
+ const validated = BotStateSchema.parse(state);
320
+ fs.writeFileSync("actualTradeEnviroments.json", JSON.stringify(validated), "utf-8");
321
+ }
322
+ ```
323
+
324
+ Validação em save protege contra escrever estado corrompido
325
+ (útil na transição da spec 00 pra 05).
326
+
327
+ ### Load
328
+
329
+ Já mostrado em "Validação na fronteira > Reload de estado".
330
+
331
+ ### Substituição do `Object.setPrototypeOf`
332
+
333
+ Spec 00 deixou `Object.setPrototypeOf(item, BotEnviromentData.prototype)`
334
+ como solução temporária. Quando schemas Zod existirem (setup/02),
335
+ refactor/05 substitui por:
336
+
337
+ ```ts
338
+ const state = BotStateSchema.parse(raw);
339
+ // state já é tipado, sem precisar reanexar prototype manualmente
340
+ ```
341
+
342
+ Classes podem virar funções/objetos puros, ou continuar como classes
343
+ com método estático `from(plain): T` que invoca o construtor.
344
+ Decisão fica pra refactor/05.
345
+
346
+ ---
347
+
348
+ ## Convenções de naming
349
+
350
+ | Item | Padrão | Exemplo |
351
+ | --------------------------- | -------------------------- | --------------------------------------- |
352
+ | Schema Zod | `XxxSchema` | `TradingDataSchema` |
353
+ | Type inferido | `Xxx` | `TradingData` |
354
+ | Funções | `camelCase` verbo + objeto | `recalculateLimits`, `loadBotState` |
355
+ | Classes (quando inevitável) | `PascalCase` substantivo | `BinanceBroker`, `WavesHistory` |
356
+ | Arquivos | `kebab-case.ts` | `binance-broker.ts`, `waves-history.ts` |
357
+ | Constantes | `SCREAMING_SNAKE_CASE` | `DEFAULT_TIMER_MS` |
358
+ | Erro | `XxxError` | `SafeLimitError` |
359
+ | Test files | `xxx.test.ts` | `waves-history.test.ts` |
360
+
361
+ Exceção: arquivos do código atual (`BotEnviromentData.ts`, etc.) ficam
362
+ como estão até serem refatorados em suas specs respectivas. Nada de
363
+ renomeação fora do escopo da spec corrente.