@statedelta-actions/rules 0.5.1 → 0.5.2

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 (3) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/README.md +316 -316
  3. package/package.json +3 -3
package/README.md CHANGED
@@ -1,135 +1,135 @@
1
1
  # @statedelta-actions/rules
2
2
 
3
- > Rule Engine — superset layer on top of ActionEngine.
4
- > Conditional trigger execution by priority.
3
+ > Rule Engine — camada superset sobre o ActionEngine.
4
+ > Execução condicional de triggers por prioridade.
5
5
  >
6
- > Rule = trigger. Events are a separate package (`@statedelta-actions/events`).
6
+ > Rule = trigger. Eventos são um package separado (`@statedelta-actions/events`).
7
7
 
8
8
  ---
9
9
 
10
- ## Table of Contents
11
-
12
- 1. [Philosophy](#philosophy)
13
- 2. [Architecture Overview](#architecture-overview)
14
- 3. [Installation & Setup](#installation--setup)
15
- 4. [Quick Start](#quick-start)
16
- 5. [Rule Definition](#rule-definition)
17
- 6. [Registration](#registration)
18
- 7. [Trigger Evaluation](#trigger-evaluation)
19
- 8. [Sub-rules (Conditional Cascade)](#sub-rules-conditional-cascade)
20
- 9. [Hooks (Governance)](#hooks-governance)
21
- 10. [Middleware (Params Enrichment)](#middleware-params-enrichment)
22
- 11. [JIT Compilation](#jit-compilation)
23
- 12. [Batch Operations](#batch-operations)
24
- 13. [Async Support](#async-support)
10
+ ## Índice
11
+
12
+ 1. [Filosofia](#filosofia)
13
+ 2. [Visão Geral da Arquitetura](#visão-geral-da-arquitetura)
14
+ 3. [Instalação & Setup](#instalação--setup)
15
+ 4. [Início Rápido](#início-rápido)
16
+ 5. [Definição de Rule](#definição-de-rule)
17
+ 6. [Registro](#registro)
18
+ 7. [Avaliação de Triggers](#avaliação-de-triggers)
19
+ 8. [Sub-rules (Cascata Condicional)](#sub-rules-cascata-condicional)
20
+ 9. [Hooks (Governança)](#hooks-governança)
21
+ 10. [Middleware (Enriquecimento de Params)](#middleware-enriquecimento-de-params)
22
+ 11. [Compilação JIT](#compilação-jit)
23
+ 12. [Operações em Batch](#operações-em-batch)
24
+ 13. [Suporte Async](#suporte-async)
25
25
  14. [Modo Interactive](#modo-interactive)
26
- 15. [Error Handling](#error-handling)
26
+ 15. [Tratamento de Erros](#tratamento-de-erros)
27
27
  16. [HALT_HANDLER](#halt_handler)
28
28
  17. [createInvokerMiddleware](#createinvokermiddleware)
29
- 18. [Full API Reference](#full-api-reference)
30
- 19. [Use Case: RPG Combat Tick](#use-case-rpg-combat-tick)
31
- 20. [Use Case: E-commerce Order Pipeline](#use-case-e-commerce-order-pipeline)
32
- 21. [Use Case: Deployment Approval Workflow](#use-case-deployment-approval-workflow)
33
- 22. [Performance Spectrum](#performance-spectrum)
34
- 23. [Internal Design Notes](#internal-design-notes)
29
+ 18. [Referência Completa da API](#referência-completa-da-api)
30
+ 19. [Caso de Uso: Tick de Combate RPG](#caso-de-uso-tick-de-combate-rpg)
31
+ 20. [Caso de Uso: Pipeline de Pedido E-commerce](#caso-de-uso-pipeline-de-pedido-e-commerce)
32
+ 21. [Caso de Uso: Workflow de Aprovação de Deploy](#caso-de-uso-workflow-de-aprovação-de-deploy)
33
+ 22. [Espectro de Performance](#espectro-de-performance)
34
+ 23. [Notas de Design Interno](#notas-de-design-interno)
35
35
 
36
36
 
37
37
  ---
38
38
 
39
- ## Philosophy
39
+ ## Filosofia
40
40
 
41
41
  ### Rule = Trigger
42
42
 
43
- A rule is not an executor. A rule is an **invoker** — a conditional trigger that, when matched, invokes an action through the ActionEngine. The RuleEngine does not execute directives. It normalizes rules into hidden actions at registration time, then delegates all execution to the ActionEngine.
43
+ Uma rule não é um executor. Uma rule é um **invocador** — um trigger condicional que, quando matched, invoca uma action através do ActionEngine. O RuleEngine não executa diretivas. Ele normaliza rules em hidden actions no momento do registro e depois delega toda a execução ao ActionEngine.
44
44
 
45
45
  ```
46
- Registration:
46
+ Registro:
47
47
  rule { id: "combat-heal", when: ..., then: [...] }
48
48
  -> actionEngine.register([{ id: "rule:combat-heal", directives: [...] }])
49
49
 
50
- Evaluation:
50
+ Avaliação:
51
51
  when(ctx) === true
52
52
  -> actionEngine.invoke("rule:combat-heal", params)
53
53
  ```
54
54
 
55
- After registration, the RuleEngine is a **loop of `when() -> invoke()`**.
55
+ Após o registro, o RuleEngine é um **loop de `when() -> invoke()`**.
56
56
 
57
- ### RuleEngine receives, does not create
57
+ ### RuleEngine recebe, não cria
58
58
 
59
- The RuleEngine receives an `IActionEngine<TCtx>` already instantiated and configured. It does not inject handlers, does not manipulate the access manifest, does not create the ActionEngine. The consumer is responsible for:
59
+ O RuleEngine recebe um `IActionEngine<TCtx>` instanciado e configurado. Não injeta handlers, não manipula o access manifest, não cria o ActionEngine. O consumer é responsável por:
60
60
 
61
- - Registering handlers (`dispatch`, `emit`, `halt`, custom)
62
- - Setting limits, JIT mode
63
- - Configuring the ActionAnalyzer separately if static analysis is needed
61
+ - Registrar handlers (`dispatch`, `emit`, `halt`, customizados)
62
+ - Definir limites, modo JIT
63
+ - Configurar o ActionAnalyzer separadamente se análise estática for necessária
64
64
 
65
- This separation means the same ActionEngine can serve both direct action invocations and rule-driven invocations.
65
+ Essa separação significa que o mesmo ActionEngine pode servir tanto invocações diretas de action quanto invocações dirigidas por rules.
66
66
 
67
- ### Hooks = governance, handlers = flow control
67
+ ### Hooks = governança, handlers = controle de fluxo
68
68
 
69
- Hooks (`beforeRule`, `afterRule`) govern the rule loop: guards, observation, abort decisions. Flow control **inside** an action (halt, state locking, error abort) belongs to handlers in the ActionEngine. Two different layers with different responsibilities.
69
+ Hooks (`beforeRule`, `afterRule`) governam o loop de rules: guards, observação, decisões de abort. Controle de fluxo **dentro** de uma action (halt, state locking, abort por erro) pertence aos handlers no ActionEngine. Duas camadas diferentes com responsabilidades diferentes.
70
70
 
71
- ### Middleware = params enrichment, not ctx transformation
71
+ ### Middleware = enriquecimento de params, não transformação de ctx
72
72
 
73
- Middleware enriches the `params` envelope (execution scope), not the domain `ctx`. The `ctx` (TCtx) is domain state owned by the consumer — read-only for middleware.
73
+ Middleware enriquece o envelope `params` (scope de execução), não o `ctx` de domínio. O `ctx` (TCtx) é estado de domínio owned pelo consumer — read-only para middleware.
74
74
 
75
- ### Never throws during evaluation
75
+ ### Nunca lança durante a avaliação
76
76
 
77
- The engine never throws to the consumer during `evaluate()`. All runtime errors are collected in `RuleEvaluationResult.errors`. The only exception is a programmer error: calling `evaluate()` when `isAsync === true`.
77
+ O engine nunca lança exceções para o consumer durante `evaluate()`. Todos os erros de runtime são coletados em `RuleEvaluationResult.errors`. A única exceção é um erro de programação: chamar `evaluate()` quando `isAsync === true`.
78
78
 
79
- `register()` is differentstructural errors at boot time (missing handler for a directive type) throw an `Error` and abort the registration atomically. See [Registration](#registration).
79
+ `register()` é diferenteerros estruturais em boot-time (handler ausente para um tipo de diretiva) lançam um `Error` e abortam o registro atomicamente. Ver [Registro](#registro).
80
80
 
81
- ### Feature not used = zero overhead
81
+ ### Feature não usada = zero overhead
82
82
 
83
- When hooks are not registered, hook code is never executed not as dead branches, but as absent code paths. The JIT compiler conditionally emits code only for features that are actually configured. Zero middleware means no middleware variables, no pipeline calls, no params allocation.
83
+ Quando hooks não são registrados, o código de hook nunca é executadonão como branches mortos, mas como código ausente. O compilador JIT emite condicionalmente apenas o código das features que de fato estão configuradas. Zero middleware significa nenhuma variável de middleware, nenhuma chamada de pipeline, nenhuma alocação de params.
84
84
 
85
85
  ---
86
86
 
87
- ## Architecture Overview
87
+ ## Visão Geral da Arquitetura
88
88
 
89
- ### Monorepo Position
89
+ ### Posição no Monorepo
90
90
 
91
91
  ```
92
- @statedelta-actions/core <- shared types, slots, frame
92
+ @statedelta-actions/core <- tipos compartilhados, slots, frame
93
93
  |
94
- @statedelta-actions/actions <- ActionEngine — runtime puro (directives, handlers, JIT)
94
+ @statedelta-actions/actions <- ActionEngine — runtime puro (diretivas, handlers, JIT)
95
95
  |
96
- @statedelta-actions/rules <- RuleEngine (this package)
97
- @statedelta-actions/events <- EventProcessor (separate package)
96
+ @statedelta-actions/rules <- RuleEngine (este package)
97
+ @statedelta-actions/events <- EventProcessor (package separado)
98
98
 
99
- @statedelta-actions/graph <- dependency graph (consumed by analyzer, not by actions/rules)
100
- @statedelta-actions/analyzer <- ActionAnalyzer — static analysis, capabilities (opt-in)
99
+ @statedelta-actions/graph <- grafo de dependências (consumido pelo analyzer, não pelo actions/rules)
100
+ @statedelta-actions/analyzer <- ActionAnalyzer — análise estática, capabilities (opt-in)
101
101
 
102
- (future) tick-runner / realm <- PPP: evaluate -> drain events -> repeat
102
+ (futuro) tick-runner / realm <- PPP: evaluate -> drain events -> repeat
103
103
  ```
104
104
 
105
- ### Composition Model
105
+ ### Modelo de Composição
106
106
 
107
107
  ```
108
- Consumer (tick-runner, game loop, business layer)
108
+ Consumer (tick-runner, game loop, camada de negócio)
109
109
  |
110
- +-- configures ActionEngine (handlers, limits)
111
- +-- creates RuleEngine(actionEngine, middleware, hooks)
112
- +-- registers rules
113
- +-- calls evaluate(ctx)
110
+ +-- configura o ActionEngine (handlers, limites)
111
+ +-- cria o RuleEngine(actionEngine, middleware, hooks)
112
+ +-- registra as rules
113
+ +-- chama evaluate(ctx)
114
114
  ```
115
115
 
116
- ### Module Structure
116
+ ### Estrutura de Módulos
117
117
 
118
118
  ```
119
119
  src/
120
- +-- types.ts <- All types and interfaces + RuleEvaluatorFn
121
- +-- engine.ts <- RuleEngineImpl + createRuleEngine + registry helpers (~470 lines)
120
+ +-- types.ts <- Todos os tipos e interfaces + RuleEvaluatorFn
121
+ +-- engine.ts <- RuleEngineImpl + createRuleEngine + helpers de registry (~470 linhas)
122
122
  +-- validate.ts <- validateRule, validateSubRule
123
123
  +-- handlers.ts <- HALT_HANDLER
124
- +-- middleware.ts <- createInvokerMiddleware (public) + runMiddleware (internal)
125
- +-- index.ts <- Public re-exports
126
- +-- eval/ <- Evaluation runtime
127
- | +-- interpreter.ts <- Rule evaluation interpreter sync/async + result builders
128
- | +-- jit.ts <- buildRuleExecutor + emitReturn codegen
124
+ +-- middleware.ts <- createInvokerMiddleware (público) + runMiddleware (interno)
125
+ +-- index.ts <- Re-exports públicos
126
+ +-- eval/ <- Runtime de avaliação
127
+ | +-- interpreter.ts <- Interpretador de avaliação de rules sync/async + builders de result
128
+ | +-- jit.ts <- buildRuleExecutor + codegen do emitReturn
129
129
  | +-- sub-rules.ts <- evaluateSubRulesSync/Async
130
130
  ```
131
131
 
132
- ### Public Exports
132
+ ### Exports Públicos
133
133
 
134
134
  ```typescript
135
135
  // Factory
@@ -141,7 +141,7 @@ export { HALT_HANDLER } from "./handlers";
141
141
  // Middleware
142
142
  export { createInvokerMiddleware } from "./middleware";
143
143
 
144
- // Types
144
+ // Tipos
145
145
  export type {
146
146
  SubRuleDefinition,
147
147
  RuleDefinition,
@@ -158,7 +158,7 @@ export type {
158
158
 
159
159
  ---
160
160
 
161
- ## Installation & Setup
161
+ ## Instalação & Setup
162
162
 
163
163
  ```typescript
164
164
  import { createActionEngine } from "@statedelta-actions/actions";
@@ -168,7 +168,7 @@ import {
168
168
  createInvokerMiddleware,
169
169
  } from "@statedelta-actions/rules";
170
170
 
171
- // 1. Configure ActionEngine with your handlers
171
+ // 1. Configure o ActionEngine com seus handlers
172
172
  const actionEngine = createActionEngine<MyCtx>({
173
173
  handlers: {
174
174
  dispatch: myDispatchHandler,
@@ -177,13 +177,13 @@ const actionEngine = createActionEngine<MyCtx>({
177
177
  },
178
178
  });
179
179
 
180
- // 2. Create RuleEngine, passing the ActionEngine
180
+ // 2. Crie o RuleEngine, passando o ActionEngine
181
181
  const ruleEngine = createRuleEngine<MyCtx>({
182
182
  actionEngine,
183
- middleware: [createInvokerMiddleware()], // optional
184
- ruleHooks: { // optional
183
+ middleware: [createInvokerMiddleware()], // opcional
184
+ ruleHooks: { // opcional
185
185
  beforeRule: (rule, evalCtx) => { /* guard */ },
186
- afterRule: (rule, result, evalCtx) => { /* observe */ },
186
+ afterRule: (rule, result, evalCtx) => { /* observa */ },
187
187
  onRulesComplete: (result) => { /* cleanup */ },
188
188
  },
189
189
  maxSubRuleDepth: 10, // default
@@ -194,10 +194,10 @@ const ruleEngine = createRuleEngine<MyCtx>({
194
194
 
195
195
  ---
196
196
 
197
- ## Quick Start
197
+ ## Início Rápido
198
198
 
199
199
  ```typescript
200
- // Register rules
200
+ // Registra as rules
201
201
  ruleEngine.register([
202
202
  {
203
203
  id: "heal-when-low",
@@ -217,28 +217,28 @@ ruleEngine.register([
217
217
  },
218
218
  ]);
219
219
 
220
- // Evaluate all trigger rules against current state
220
+ // Avalia todas as rules de trigger contra o estado atual
221
221
  const result = ruleEngine.evaluate(ctx);
222
222
 
223
- // result.success -> true if completed without abort
224
- // result.matched -> ["heal-when-low", "regen-mp"] rule IDs
223
+ // result.success -> true se completou sem abort
224
+ // result.matched -> ["heal-when-low", "regen-mp"] (IDs das rules)
225
225
  // result.counters -> { rulesEvaluated: 2, rulesMatched: 2, ... }
226
226
  ```
227
227
 
228
228
  ---
229
229
 
230
- ## Rule Definition
230
+ ## Definição de Rule
231
231
 
232
232
  ### SubRuleDefinition
233
233
 
234
- Base type for sub-rules. No `priority` — sub-rules execute in **declaration order**.
234
+ Tipo base para sub-rules. Sem `priority` — sub-rules executam em **ordem de declaração**.
235
235
 
236
236
  ```typescript
237
237
  interface SubRuleDefinition<TCtx> {
238
- readonly id: string; // unique identifier
239
- readonly when?: (ctx: TCtx) => boolean; // trigger condition
240
- readonly then?: readonly Directive<TCtx>[]; // action directives
241
- readonly rules?: readonly SubRuleDefinition<TCtx>[]; // nested sub-rules
238
+ readonly id: string; // identificador único
239
+ readonly when?: (ctx: TCtx) => boolean; // condição de trigger
240
+ readonly then?: readonly Directive<TCtx>[]; // diretivas da action
241
+ readonly rules?: readonly SubRuleDefinition<TCtx>[]; // sub-rules aninhadas
242
242
  readonly tags?: readonly string[];
243
243
  readonly effects?: readonly string[];
244
244
  readonly declarations?: Record<string, unknown>;
@@ -248,65 +248,65 @@ interface SubRuleDefinition<TCtx> {
248
248
 
249
249
  ### RuleDefinition
250
250
 
251
- Top-level rules extend `SubRuleDefinition` with mandatory `priority`.
251
+ Rules top-level estendem `SubRuleDefinition` com `priority` obrigatória.
252
252
 
253
253
  ```typescript
254
254
  interface RuleDefinition<TCtx> extends SubRuleDefinition<TCtx> {
255
- readonly priority: number; // higher = first (desc order)
256
- readonly rules?: readonly SubRuleDefinition<TCtx>[]; // sub-rules (no priority)
255
+ readonly priority: number; // maior = primeiro (ordem desc)
256
+ readonly rules?: readonly SubRuleDefinition<TCtx>[]; // sub-rules (sem priority)
257
257
  }
258
258
  ```
259
259
 
260
- A rule **must** have `when` (trigger condition).
260
+ Uma rule **precisa** ter `when` (condição de trigger).
261
261
 
262
- A rule **must** have `then` or `rules` (or both). A rule with only `rules` and no `then` is a **group gate** — a pure conditional container.
262
+ Uma rule **precisa** ter `then` ou `rules` (ou ambos). Uma rule com `rules` e sem `then` é um **group gate** — um container puramente condicional.
263
263
 
264
264
  ### Priority
265
265
 
266
- Higher number = executes first (like z-index). Rules are sorted by priority descending at registration time. Sub-rules execute in **declaration order** — they don't have `priority`.
266
+ Número maior = executa primeiro (como z-index). As rules são ordenadas por priority descendente no momento do registro. Sub-rules executam em **ordem de declaração** — elas não têm `priority`.
267
267
 
268
- ### Validation
268
+ ### Validação
269
269
 
270
- | Check | Error Code |
270
+ | Check | Código de Erro |
271
271
  |-------|-----------|
272
- | `id` must be a non-empty string | `INVALID_RULE` |
273
- | `priority` must be a number | `INVALID_RULE` |
274
- | Must have `when` function | `INVALID_RULE` |
275
- | Must have `then` or `rules` (or both) | `INVALID_RULE` |
276
- | Duplicate ID | `DUPLICATE_ID` |
272
+ | `id` precisa ser uma string não vazia | `INVALID_RULE` |
273
+ | `priority` precisa ser um number | `INVALID_RULE` |
274
+ | Precisa ter função `when` | `INVALID_RULE` |
275
+ | Precisa ter `then` ou `rules` (ou ambos) | `INVALID_RULE` |
276
+ | ID duplicado | `DUPLICATE_ID` |
277
277
 
278
- Sub-rule validation:
278
+ Validação de sub-rule:
279
279
 
280
- | Check | Error Code |
280
+ | Check | Código de Erro |
281
281
  |-------|-----------|
282
- | `id` must be a non-empty string | `INVALID_RULE` |
283
- | Must have `then` or `rules` (or both) | `INVALID_RULE` |
282
+ | `id` precisa ser uma string não vazia | `INVALID_RULE` |
283
+ | Precisa ter `then` ou `rules` (ou ambos) | `INVALID_RULE` |
284
284
 
285
285
  ---
286
286
 
287
- ## Registration
287
+ ## Registro
288
288
 
289
289
  ```typescript
290
290
  const result = ruleEngine.register([rule1, rule2, ...]);
291
291
  ```
292
292
 
293
- ### Registration pipeline
293
+ ### Pipeline de registro
294
294
 
295
- Three phases. Local registries are only mutated after the ActionEngine accepts every hidden action — `register()` is atomic.
295
+ Três fases. Os registries locais são mutados depois que o ActionEngine aceita todas as hidden actions — `register()` é atômico.
296
296
 
297
- 1. **Build** — validate each rule (id, priority, when, then/rules), collect sub-rules recursively, build hidden action definitions (`rule:{id}` for top-level, dot-separated for sub-rules). Soft validation errors (duplicate id, missing required field) accumulate in `errors[]`. No local indexing yet.
298
- 2. **Delegate to ActionEngine** — `actionEngine.register(hiddenActions)`. Structural errors propagate as throw (handler missing for a directive type). Soft errors from the ActionEngine are mapped back to rule ids and added to `errors[]`.
299
- 3. **Index** — only reached when phase 2 returns. Insert each rule into `_ruleRegistry` and `_rules` (sorted by priority desc), refresh per-rule `isAsync`/`isInteractive` flags from the mini-graph.
297
+ 1. **Build** — valida cada rule (id, priority, when, then/rules), coleta sub-rules recursivamente, monta as definitions das hidden actions (`rule:{id}` para top-level, separadas por ponto para sub-rules). Erros de validação soft (id duplicado, campo obrigatório ausente) acumulam em `errors[]`. Ainda sem indexação local.
298
+ 2. **Delegar ao ActionEngine** — `actionEngine.register(hiddenActions)`. Erros estruturais propagam como throw (handler ausente para um tipo de diretiva). Erros soft do ActionEngine são mapeados de volta para ids de rule e adicionados a `errors[]`.
299
+ 3. **Indexar** — é alcançado quando a fase 2 retorna. Insere cada rule em `_ruleRegistry` e `_rules` (ordenado por priority desc), refresca as flags `isAsync`/`isInteractive` per-rule a partir do mini-graph.
300
300
 
301
- ### Throw vs collected errors
301
+ ### Throw vs erros coletados
302
302
 
303
- | Error | Behavior |
303
+ | Erro | Comportamento |
304
304
  |-------|----------|
305
- | Missing handler for a directive type in `then` (any depth, including sub-rules and `catch`) | **Throws `Error`** in `register()`. No local state mutated. Consumer wraps in try/catch if needed. |
306
- | Duplicate rule id, missing `when`, missing `then`/`rules`, invalid priority | Collected in `errors[]`. Other valid rules in the same call still register. |
307
- | `validate()` from a handler returns invalid or throws | Collected in `errors[]`. |
305
+ | Handler ausente para um tipo de diretiva em `then` (qualquer profundidade, incluindo sub-rules e `catch`) | **Lança `Error`** em `register()`. Nenhum estado local mutado. O consumer envolve em try/catch se precisar. |
306
+ | Id de rule duplicado, `when` ausente, `then`/`rules` ausentes, priority inválida | Coletado em `errors[]`. Outras rules válidas no mesmo call ainda registram. |
307
+ | `validate()` de um handler retorna invalid ou lança | Coletado em `errors[]`. |
308
308
 
309
- The throw path is reserved for boot-time structural errors that cannot become valid at runtime — typos, forgotten handler registration, refactor leftovers. Soft errors are domain-level and worth surveying.
309
+ O caminho de throw é reservado para erros estruturais de boot-time que não podem virar válidos em runtime — typos, handler esquecido no registro, resíduo de refactor. Erros soft são domain-level e merecem inspeção.
310
310
 
311
311
  ### RuleRegisterResult
312
312
 
@@ -321,36 +321,36 @@ interface RuleRegisterResult {
321
321
  ### Unregister
322
322
 
323
323
  ```typescript
324
- const removed = ruleEngine.unregister("rule-id"); // true if found and removed
324
+ const removed = ruleEngine.unregister("rule-id"); // true se encontrado e removido
325
325
  ```
326
326
 
327
- Removes the rule from all internal registries, unregisters the hidden action from ActionEngine, and recursively cleans up sub-rules.
327
+ Remove a rule de todos os registries internos, desregistra a hidden action do ActionEngine e limpa as sub-rules recursivamente.
328
328
 
329
329
  ---
330
330
 
331
- ## Trigger Evaluation
331
+ ## Avaliação de Triggers
332
332
 
333
333
  ```typescript
334
334
  const result = ruleEngine.evaluate(ctx);
335
335
  ```
336
336
 
337
- Processes all rules in priority descending order:
337
+ Processa todas as rules em ordem de priority descendente:
338
338
 
339
339
  ```
340
340
  evaluate(ctx)
341
341
  |
342
342
  actionEngine.setContext(ctx)
343
343
  |
344
- for each rule (priority desc):
344
+ para cada rule (priority desc):
345
345
  |
346
- +-- beforeRule hook -> "skip" -> skipped | "abort" -> return | void -> continue
347
- +-- when(ctx) -> false -> notMatched | error -> collect, notMatched
346
+ +-- hook beforeRule -> "skip" -> skipped | "abort" -> return | void -> continua
347
+ +-- when(ctx) -> false -> notMatched | erro -> coleta, notMatched
348
348
  +-- matched
349
- +-- Middleware pipeline -> params (or error -> collect, skip invoke)
350
- +-- Invoke action (if has then) -> DirectiveResult
351
- +-- afterRule hook -> "abort" -> return | void -> continue
352
- +-- Halt check -> aborted -> return
353
- +-- Sub-rules cascade -> aborted -> return
349
+ +-- Pipeline de middleware -> params (ou erro -> coleta, pula invoke)
350
+ +-- Invoca a action (se tem then) -> DirectiveResult
351
+ +-- hook afterRule -> "abort" -> return | void -> continua
352
+ +-- Check de halt -> aborted -> return
353
+ +-- Cascata de sub-rules -> aborted -> return
354
354
  |
355
355
  onRulesComplete(result)
356
356
  return result
@@ -360,20 +360,20 @@ evaluate(ctx)
360
360
 
361
361
  ```typescript
362
362
  interface RuleEvaluationResult {
363
- readonly success: boolean; // true if completed without abort
364
- readonly aborted: boolean; // true if stopped early
363
+ readonly success: boolean; // true se completou sem abort
364
+ readonly aborted: boolean; // true se parou cedo
365
365
  readonly abortedBy?: string; // "beforeRule" | "afterRule" | "sub-rule" | "halt" | handler
366
- readonly matched: readonly string[]; // IDs of matched rules
367
- readonly skipped: readonly string[]; // IDs skipped by beforeRule
366
+ readonly matched: readonly string[]; // IDs das rules matched
367
+ readonly skipped: readonly string[]; // IDs skipados pelo beforeRule
368
368
  readonly notMatched: readonly string[];
369
369
  readonly errors: readonly RuleError[];
370
- readonly processedCount: number; // rules processed (< totalCount on abort)
370
+ readonly processedCount: number; // rules processadas (< totalCount em abort)
371
371
  readonly totalCount: number;
372
- readonly counters: FrameCounters; // accumulated across all nesting
372
+ readonly counters: FrameCounters; // acumulado em todo o aninhamento
373
373
  }
374
374
  ```
375
375
 
376
- ### Example
376
+ ### Exemplo
377
377
 
378
378
  ```typescript
379
379
  const ruleEngine = createRuleEngine({ actionEngine });
@@ -396,7 +396,7 @@ ruleEngine.register([
396
396
  const ctx = { inCombat: true, hp: 30, defense: 0 };
397
397
  const result = ruleEngine.evaluate(ctx);
398
398
 
399
- // shield (200) executes first, then heal (100)
399
+ // shield (200) executa primeiro, depois heal (100)
400
400
  // ctx.defense === 10, ctx.hp === 50
401
401
  // result.matched === ["shield", "heal"]
402
402
  // result.counters.rulesMatched === 2
@@ -404,42 +404,42 @@ const result = ruleEngine.evaluate(ctx);
404
404
 
405
405
  ---
406
406
 
407
- ## Sub-rules (Conditional Cascade)
407
+ ## Sub-rules (Cascata Condicional)
408
408
 
409
- Sub-rules enable conditional branching within a rule. After the parent's `then` execute, each sub-rule's `when()` is evaluated in **declaration order**. Sub-rules can nest to arbitrary depth (bounded by `maxSubRuleDepth`, default 10).
409
+ Sub-rules permitem branching condicional dentro de uma rule. Depois que o `then` do pai executa, o `when()` de cada sub-rule é avaliado em **ordem de declaração**. Sub-rules podem aninhar em profundidade arbitrária (limitada por `maxSubRuleDepth`, default 10).
410
410
 
411
- ### Registration
411
+ ### Registro
412
412
 
413
- Sub-rules are registered recursively as hidden actions with dot-separated IDs:
413
+ Sub-rules são registradas recursivamente como hidden actions com IDs separados por ponto:
414
414
 
415
415
  ```
416
- rule:combat-heal <- parent
416
+ rule:combat-heal <- pai
417
417
  rule:combat-heal.low-hp <- sub-rule
418
- rule:combat-heal.low-hp.crit <- nested sub-rule
418
+ rule:combat-heal.low-hp.crit <- sub-rule aninhada
419
419
  ```
420
420
 
421
- Group gates (no `then`) register no action — `actionId = ""`.
421
+ Group gates (sem `then`) não registram action — `actionId = ""`.
422
422
 
423
- ### Evaluation
423
+ ### Avaliação
424
424
 
425
425
  ```
426
- After parent invoke (or directly for group gate):
427
- for each sub-rule (declaration order):
428
- +-- when(ctx) -> false -> skip | undefined -> unconditional
429
- +-- Invoke (if has then) -> aborted -> propagate up
430
- +-- Recurse (if has sub-rules) -> aborted -> propagate up
426
+ Depois do invoke do pai (ou direto, para group gate):
427
+ para cada sub-rule (ordem de declaração):
428
+ +-- when(ctx) -> false -> skip | undefined -> incondicional
429
+ +-- Invoke (se tem then) -> aborted -> propaga pra cima
430
+ +-- Recursa (se tem sub-rules) -> aborted -> propaga pra cima
431
431
  ```
432
432
 
433
433
  ### Group gates
434
434
 
435
- A group gate is a rule with `rules` but no `then`. It acts as a pure conditional container:
435
+ Um group gate é uma rule com `rules` mas sem `then`. Funciona como um container puramente condicional:
436
436
 
437
437
  ```typescript
438
438
  {
439
439
  id: "combat-group",
440
440
  priority: 100,
441
441
  when: (ctx) => ctx.zone === "combat",
442
- // no `then` — this is a gate
442
+ // sem `then` — isto é um gate
443
443
  rules: [
444
444
  { id: "heal", when: (ctx) => ctx.hp < 50, then: [...] },
445
445
  { id: "buff", when: (ctx) => ctx.mp > 0, then: [...] },
@@ -447,19 +447,19 @@ A group gate is a rule with `rules` but no `then`. It acts as a pure conditional
447
447
  }
448
448
  ```
449
449
 
450
- The gate evaluates `when()`. If true, children are evaluated. No action is invoked for the gate itself.
450
+ O gate avalia `when()`. Se true, os filhos são avaliados. Nenhuma action é invocada para o gate em si.
451
451
 
452
- ### Design decisions
452
+ ### Decisões de design
453
453
 
454
- | Decision | Rationale |
454
+ | Decisão | Racional |
455
455
  |----------|-----------|
456
- | Declaration order, not priority | Sub-rules are a cascade within one rule — order matters semantically |
457
- | Hooks do NOT apply to sub-rules | Hooks govern the main loop, not internal branching |
458
- | Middleware params inherited | Parent's middleware-enriched `params` propagate as-is |
459
- | Abort propagates upward | Sub-rule halt -> parent aborts -> main loop stops |
460
- | Depth limited | Default 10. Exceeding -> error collected, sub-tree skipped (no abort) |
456
+ | Ordem de declaração, não priority | Sub-rules são uma cascata dentro de uma rule — a ordem importa semanticamente |
457
+ | Hooks NÃO se aplicam a sub-rules | Hooks governam o loop principal, não o branching interno |
458
+ | Params de middleware herdados | Os `params` enriquecidos pelo middleware do pai propagam as-is |
459
+ | Abort propaga pra cima | Halt em sub-rule -> pai aborta -> loop principal para |
460
+ | Profundidade limitada | Default 10. Exceder -> erro coletado, sub-tree skipada (sem abort) |
461
461
 
462
- ### Example: tiered discounts
462
+ ### Exemplo: descontos por tier
463
463
 
464
464
  ```typescript
465
465
  ruleEngine.register([
@@ -467,7 +467,7 @@ ruleEngine.register([
467
467
  id: "discount-engine",
468
468
  priority: 200,
469
469
  when: (ctx) => ctx.status === "validated" && ctx.discount === 0,
470
- then: [{ type: "log", message: "evaluating discounts" }],
470
+ then: [{ type: "log", message: "avaliando descontos" }],
471
471
  rules: [
472
472
  {
473
473
  id: "vip-discount",
@@ -492,9 +492,9 @@ ruleEngine.register([
492
492
 
493
493
  ---
494
494
 
495
- ## Hooks (Governance)
495
+ ## Hooks (Governança)
496
496
 
497
- Hooks are analyzed once at construction time via `analyzeSlots`. They govern rule evaluation only. Events have their own hooks in `@statedelta-actions/events`.
497
+ Hooks são analisados uma vez no momento da construção via `analyzeSlots`. Eles governam apenas a avaliação de rules. Eventos têm seus próprios hooks em `@statedelta-actions/events`.
498
498
 
499
499
  ### Rule Hooks
500
500
 
@@ -506,11 +506,11 @@ ruleHooks: {
506
506
  }
507
507
  ```
508
508
 
509
- | Hook | When | Returns | Error behavior |
509
+ | Hook | Quando | Retornos | Comportamento de erro |
510
510
  |------|------|---------|----------------|
511
- | `beforeRule` | Before `when()` evaluation | `"skip"` -> skipped, `"abort"` -> stop pipeline, `void` -> continue | Collected in `errors[]`, continue |
512
- | `afterRule` | After invoke (if rule had `then`) | `"abort"` -> stop pipeline, `void` -> continue | Fire-and-forget |
513
- | `onRulesComplete` | After all rules processed (or abort) | `void` | Silenced |
511
+ | `beforeRule` | Antes da avaliação do `when()` | `"skip"` -> skipped, `"abort"` -> para o pipeline, `void` -> continua | Coletado em `errors[]`, continua |
512
+ | `afterRule` | Depois do invoke (se a rule tinha `then`) | `"abort"` -> para o pipeline, `void` -> continua | Fire-and-forget |
513
+ | `onRulesComplete` | Depois de todas as rules processadas (ou abort) | `void` | Silenciado |
514
514
 
515
515
  ```typescript
516
516
  interface RuleEvaluationContext<TCtx> {
@@ -519,7 +519,7 @@ interface RuleEvaluationContext<TCtx> {
519
519
  }
520
520
  ```
521
521
 
522
- ### Example: governance by priority
522
+ ### Exemplo: governança por priority
523
523
 
524
524
  ```typescript
525
525
  const ruleEngine = createRuleEngine({
@@ -532,7 +532,7 @@ const ruleEngine = createRuleEngine({
532
532
  });
533
533
  ```
534
534
 
535
- ### Example: abort on error
535
+ ### Exemplo: abort em erro
536
536
 
537
537
  ```typescript
538
538
  ruleHooks: {
@@ -544,13 +544,13 @@ ruleHooks: {
544
544
 
545
545
  ---
546
546
 
547
- ## Middleware (Params Enrichment)
547
+ ## Middleware (Enriquecimento de Params)
548
548
 
549
- Middleware runs between match and invoke. It enriches the `params` that become the action's scope.
549
+ Middleware roda entre o match e o invoke. Ele enriquece os `params` que viram o scope da action.
550
550
 
551
- ### Composition model
551
+ ### Modelo de composição
552
552
 
553
- Delta-based. Each middleware receives the accumulated params and returns a delta to merge:
553
+ Baseado em delta. Cada middleware recebe os params acumulados e retorna um delta para mesclar:
554
554
 
555
555
  ```
556
556
  params0 = {} -> mw[0](rule, ctx, params0) -> d0 -> params1 = {...params0, ...d0}
@@ -559,9 +559,9 @@ params0 = {} -> mw[0](rule, ctx, params0) -> d0 -> params1 = {...params0, ...d0}
559
559
  invoke(actionId, paramsN)
560
560
  ```
561
561
 
562
- Middleware cannot drop what predecessors injected (only overwrite by key).
562
+ Middleware não pode descartar o que os predecessores injetaram ( sobrescrever por chave).
563
563
 
564
- ### Signature
564
+ ### Assinatura
565
565
 
566
566
  ```typescript
567
567
  type RuleMiddleware<TCtx> = (
@@ -571,15 +571,15 @@ type RuleMiddleware<TCtx> = (
571
571
  ) => Record<string, unknown>;
572
572
  ```
573
573
 
574
- ### Sub-rule middleware
574
+ ### Middleware de sub-rule
575
575
 
576
- Middleware does **not** re-run for sub-rules. The parent's middleware-enriched `params` are passed directly to sub-rule invocations.
576
+ Middleware **não** roda de novo para sub-rules. Os `params` enriquecidos pelo middleware do pai são passados diretamente para as invocações de sub-rule.
577
577
 
578
- ### Error handling
578
+ ### Tratamento de erros
579
579
 
580
- Middleware error -> collected in `errors[]`, invoke skipped, next rule continues.
580
+ Erro de middleware -> coletado em `errors[]`, invoke skipado, a próxima rule continua.
581
581
 
582
- ### Example: custom audit middleware
582
+ ### Exemplo: middleware de auditoria customizado
583
583
 
584
584
  ```typescript
585
585
  const auditMiddleware: RuleMiddleware<MyCtx> = (rule, ctx, params) => ({
@@ -598,87 +598,87 @@ const ruleEngine = createRuleEngine({
598
598
 
599
599
  ---
600
600
 
601
- ## JIT Compilation
601
+ ## Compilação JIT
602
602
 
603
- JIT compiles the **rule iteration loop**, not individual directives (ActionEngine handles directive JIT separately). Two levels of JIT coexist: ActionEngine compiles directive execution, RuleEngine compiles rule orchestration.
603
+ O JIT compila o **loop de iteração de rules**, não diretivas individuais (o ActionEngine cuida do JIT de diretivas separadamente). Dois níveis de JIT coexistem: o ActionEngine compila a execução de diretivas, o RuleEngine compila a orquestração de rules.
604
604
 
605
- ### What is compiled
605
+ ### O que é compilado
606
606
 
607
- `buildRuleExecutor` generates a function via `new Function` that replaces the interpreter. Same signaturethe engine swaps transparently.
607
+ `buildRuleExecutor` gera uma função via `new Function` que substitui o interpretador. Mesma assinaturao engine troca transparentemente.
608
608
 
609
- ### Conditional code emission
609
+ ### Emissão condicional de código
610
610
 
611
- The generated JS only contains code for features that are actually configured:
611
+ O JS gerado contém apenas código para as features que de fato estão configuradas:
612
612
 
613
- | Feature absent | Code not emitted |
613
+ | Feature ausente | Código não emitido |
614
614
  |---|---|
615
- | `beforeRule` | Entire try/catch block, skip/abort checks |
616
- | `afterRule` | Entire try/catch block, abort check |
617
- | `onRulesComplete` | Final call + cleanup blocks |
618
- | No hooks at all | `evalCtx` not created, no hook variables |
619
- | No middleware | `params` variable not declared, no pipeline call |
615
+ | `beforeRule` | Todo o bloco try/catch, checks de skip/abort |
616
+ | `afterRule` | Todo o bloco try/catch, check de abort |
617
+ | `onRulesComplete` | Chamada final + blocos de cleanup |
618
+ | Nenhum hook | `evalCtx` não criado, nenhuma variável de hook |
619
+ | Nenhum middleware | Variável `params` não declarada, nenhuma chamada de pipeline |
620
620
 
621
- ### Tier 0 — tight loop
621
+ ### Tier 0 — loop minimal
622
622
 
623
- With zero hooks and zero middleware, the generated code is a minimal loop:
623
+ Com zero hooks e zero middleware, o código gerado é um loop minimal:
624
624
 
625
625
  ```
626
- for -> when(ctx) -> invoke(actionId) -> halt check -> sub-rules -> next
626
+ for -> when(ctx) -> invoke(actionId) -> check de halt -> sub-rules -> próxima
627
627
  ```
628
628
 
629
- No try/catch for hooks. No middleware pipeline. No evalCtx allocation.
629
+ Sem try/catch para hooks. Sem pipeline de middleware. Sem alocação de evalCtx.
630
630
 
631
- ### Modes
631
+ ### Modos
632
632
 
633
633
  ```typescript
634
634
  const engine = createRuleEngine({ actionEngine, mode: "auto" });
635
635
  ```
636
636
 
637
- | Mode | Behavior |
637
+ | Modo | Comportamento |
638
638
  |------|----------|
639
- | `interpret` | Always use interpreter. JIT never activates. `compile()` is a no-op. |
640
- | `jit` | Compile immediately at construction. No interpreter phase. |
641
- | `auto` (default) | Start with interpreter. Promote after threshold calls. |
639
+ | `interpret` | Sempre usa o interpretador. O JIT nunca ativa. `compile()` é no-op. |
640
+ | `jit` | Compila imediatamente na construção. Sem fase de interpretador. |
641
+ | `auto` (default) | Começa com o interpretador. Promove após N chamadas (threshold). |
642
642
 
643
- Default threshold: 8 `evaluate()` calls. Configurable via `autoJitThreshold`.
643
+ Threshold default: 8 chamadas de `evaluate()`. Configurável via `autoJitThreshold`.
644
644
 
645
645
  ```
646
- evaluate() #1..#7 -> interpreter
647
- evaluate() #8 -> compile + swap interpreter for JIT
648
- evaluate() #9+ -> JIT compiled
646
+ evaluate() #1..#7 -> interpretador
647
+ evaluate() #8 -> compila + troca interpretador por JIT
648
+ evaluate() #9+ -> JIT compilado
649
649
  ```
650
650
 
651
651
  ### compile()
652
652
 
653
653
  ```typescript
654
- engine.compile(); // forces immediate promotion to JIT
654
+ engine.compile(); // força a promoção imediata para JIT
655
655
  ```
656
656
 
657
- Useful for warmup. No-op if `mode === "interpret"`.
657
+ Útil para warmup. No-op se `mode === "interpret"`.
658
658
 
659
- ### compilationMode getter
659
+ ### getter compilationMode
660
660
 
661
661
  ```typescript
662
662
  engine.compilationMode // "interpret" | "jit"
663
663
  ```
664
664
 
665
- Reflects current stateswitches from `"interpret"` to `"jit"` after promotion.
665
+ Reflete o estado atual muda de `"interpret"` para `"jit"` após a promoção.
666
666
 
667
667
  ---
668
668
 
669
- ## Batch Operations
669
+ ## Operações em Batch
670
670
 
671
- ### Callback-based (recommended)
671
+ ### Baseado em callback (recomendado)
672
672
 
673
673
  ```typescript
674
674
  const result = engine.batch((eng) => {
675
675
  eng.register([rule1, rule2]);
676
676
  eng.register([rule3, rule4]);
677
677
  });
678
- // endBatch() called automatically, even on throw
678
+ // endBatch() chamado automaticamente, inclusive em throw
679
679
  ```
680
680
 
681
- `batch(fn)` guarantees cleanup: if `fn` throws, `endBatch()` is still called to avoid leaving the engine in an inconsistent state.
681
+ `batch(fn)` garante o cleanup: se `fn` lança, `endBatch()` ainda é chamado para não deixar o engine num estado inconsistente.
682
682
 
683
683
  ### Manual
684
684
 
@@ -689,16 +689,16 @@ engine.register([rule3, rule4]);
689
689
  const result = engine.endBatch();
690
690
  ```
691
691
 
692
- - Delegates `beginBatch()`/`endBatch()` to ActionEngine
693
- - Accumulates registration results across multiple `register()` calls
694
- - Merges everything on `endBatch()`
695
- - Supports nesting: inner `endBatch()` returns empty, outer merges all
692
+ - Delega `beginBatch()`/`endBatch()` ao ActionEngine
693
+ - Acumula os results de registro através de múltiplas chamadas de `register()`
694
+ - Mescla tudo no `endBatch()`
695
+ - Suporta aninhamento: `endBatch()` interno retorna vazio, o externo mescla tudo
696
696
 
697
697
  ---
698
698
 
699
- ## Async Support
699
+ ## Suporte Async
700
700
 
701
- ### Detection (per-rule transitivo)
701
+ ### Detecção (per-rule transitivo)
702
702
 
703
703
  ```typescript
704
704
  const isAsync = ruleHookAnalysis.hasAnyAsync || hasAnyAsyncRuleTransitive;
@@ -709,7 +709,7 @@ Refrescado em `register()` / `unregister()` / `endBatch()` consultando o **mini-
709
709
  **Diferença importante:** antes era `actionEngine.isAsync` (global). Agora é per-rule transitivo. Engine híbrido (handler async + handler sync) com rules **100% sync na sub-árvore** permite `evaluate()` regular — só rules transitivamente async forçam `evaluateAsync()`.
710
710
 
711
711
  ```typescript
712
- // Engine híbrido — handler async existe, mas action `log` (usada em syncRule) é sync
712
+ // Engine híbrido — handler async existe, mas a action `log` (usada em syncRule) é sync
713
713
  const engine = createActionEngine({
714
714
  handlers: { log, fetchAsync: { async: true, async execute() {...} } },
715
715
  });
@@ -720,23 +720,23 @@ rules.register([
720
720
  ]);
721
721
 
722
722
  engine.isAsync; // true (engine global async — fetchAsync existe)
723
- rules.isAsync; // false (rule específica é sync transitivamente)
723
+ rules.isAsync; // false (a rule específica é sync transitivamente)
724
724
  rules.evaluate(ctx); // ✅ funciona — não força evaluateAsync
725
725
  ```
726
726
 
727
- ### Usage
727
+ ### Uso
728
728
 
729
729
  ```typescript
730
- // Sync (throws if isAsync)
730
+ // Sync (lança se isAsync)
731
731
  const result = engine.evaluate(ctx);
732
732
 
733
- // Async (always works)
733
+ // Async (sempre funciona)
734
734
  const result = await engine.evaluateAsync(ctx);
735
735
  ```
736
736
 
737
- Calling `evaluate()` when `isAsync === true` throws an errormust use `evaluateAsync()`. This is a guard against accidentally dropping promises.
737
+ Chamar `evaluate()` quando `isAsync === true` lança um erroé preciso usar `evaluateAsync()`. Isso é um guard contra descartar promises por acidente.
738
738
 
739
- ### Async hooks
739
+ ### Hooks async
740
740
 
741
741
  ```typescript
742
742
  const ruleEngine = createRuleEngine({
@@ -753,7 +753,7 @@ const ruleEngine = createRuleEngine({
753
753
  });
754
754
 
755
755
 
756
- // Must use evaluateAsync
756
+ // Precisa usar evaluateAsync
757
757
  const result = await ruleEngine.evaluateAsync(ctx);
758
758
  ```
759
759
 
@@ -761,17 +761,17 @@ const result = await ruleEngine.evaluateAsync(ctx);
761
761
 
762
762
  ## Modo Interactive
763
763
 
764
- Permite **pausar avaliação de rules** e aguardar input externo via generators — espelhamento do modo interactive do ActionEngine. Ortogonal a sync/async.
764
+ Permite **pausar a avaliação de rules** e aguardar input externo via generators — espelhamento do modo interactive do ActionEngine. Ortogonal a sync/async.
765
765
 
766
- **Habilitação:** ActionEngine precisa estar em modo interactive (`createActionEngine({ ..., interactive: {} })`). Rules detecta automaticamente quando alguma rule registrada tem ação transitivamente interactive.
766
+ **Habilitação:** o ActionEngine precisa estar em modo interactive (`createActionEngine({ ..., interactive: {} })`). O Rules detecta automaticamente quando alguma rule registrada tem ação transitivamente interactive.
767
767
 
768
- ### Detection per-rule
768
+ ### Detecção per-rule
769
769
 
770
770
  `StoredRule.isInteractive` cacheia o resultado de `engine.isActionInteractive(rule.actionId)`. Refrescado em register/unregister/endBatch.
771
771
 
772
772
  ```typescript
773
773
  rules.isInteractive; // true se qualquer rule é interactive transitivamente
774
- rules.evaluate(ctx); // throws "use evaluateInteractive"
774
+ rules.evaluate(ctx); // lança "use evaluateInteractive"
775
775
  rules.evaluateAsync(ctx); // idem
776
776
  rules.evaluateInteractive(ctx); // ✅ retorna iterator
777
777
  ```
@@ -816,9 +816,9 @@ session.next("Anderson"); // → { done: true, value: RuleEvaluationResult }
816
816
  // ctx.out: ["before", "Anderson (yes)"]
817
817
  ```
818
818
 
819
- ### Mistura sync + interactive (priority order)
819
+ ### Mistura sync + interactive (ordem de priority)
820
820
 
821
- Rules sync e interactive coexistem na mesma evaluation, respeitando priority. Rules sync rodam direto (sem yield); rules interactive pausam.
821
+ Rules sync e interactive coexistem na mesma avaliação, respeitando a priority. Rules sync rodam direto (sem yield); rules interactive pausam.
822
822
 
823
823
  ```typescript
824
824
  rules.register([
@@ -857,7 +857,7 @@ await session.next(); // loadData rodou (fetch async), getName yieldou
857
857
  await session.next("Anderson"); // matched: ["loadData", "getName"]
858
858
  ```
859
859
 
860
- ### Compilação JIT generator
860
+ ### Compilação do JIT generator
861
861
 
862
862
  Em `mode: "jit"`, `evaluateInteractive` usa **JIT generator compilado** (Fase R6 — `buildInteractiveRuleExecutor`). 4 wrappers possíveis:
863
863
 
@@ -868,7 +868,7 @@ Em `mode: "jit"`, `evaluateInteractive` usa **JIT generator compilado** (Fase R6
868
868
  | false | true | `function* ()` (`evaluateInteractive` sync) |
869
869
  | true | true | `async function* ()` (`evaluateInteractive` async) |
870
870
 
871
- JIT emit branch per-rule no loop:
871
+ Branch emitido per-rule no loop do JIT:
872
872
 
873
873
  ```javascript
874
874
  if (stored.isInteractive) {
@@ -880,29 +880,29 @@ if (stored.isInteractive) {
880
880
  }
881
881
  ```
882
882
 
883
- Decisão **per-rule em runtime**, baseada nas flags cached em `StoredRule.isAsync`/`isInteractive`. Em `mode: "interpret"` ou `"auto"` (antes do threshold), usa interpreter generator (mesmo behavior, sem unrolled performance).
883
+ Decisão **per-rule em runtime**, baseada nas flags cached em `StoredRule.isAsync`/`isInteractive`. Em `mode: "interpret"` ou `"auto"` (antes do threshold), usa o interpreter generator (mesmo comportamento, sem a performance do unrolled).
884
884
 
885
885
  ---
886
886
 
887
- ## Error Handling
887
+ ## Tratamento de Erros
888
888
 
889
- The engine **never throws** during evaluation. All runtime errors are collected:
889
+ O engine **nunca lança** durante a avaliação. Todos os erros de runtime são coletados:
890
890
 
891
- | Error source | Behavior |
891
+ | Origem do erro | Comportamento |
892
892
  |-------------|----------|
893
- | `when()` throws | Error collected, rule treated as `notMatched`, continue |
894
- | `beforeRule` throws | Error collected, continue (treated as void) |
895
- | `afterRule` throws | Fire-and-forget, continue |
896
- | `onRulesComplete` throws | Silenced |
897
- | Middleware throws | Error collected, invoke skipped, next rule |
898
- | ActionEngine invoke errors | Directive errors accumulated in counters |
899
- | Hidden action id missing at invoke time | Pipeline aborts with `abortedBy: "action-not-found"`, `success: false` |
900
- | Sub-rule `when()` throws | Error collected, sub-rule skipped |
901
- | `maxSubRuleDepth` exceeded | Error collected, sub-tree skipped (no abort) |
893
+ | `when()` lança | Erro coletado, rule tratada como `notMatched`, continua |
894
+ | `beforeRule` lança | Erro coletado, continua (tratado como void) |
895
+ | `afterRule` lança | Fire-and-forget, continua |
896
+ | `onRulesComplete` lança | Silenciado |
897
+ | Middleware lança | Erro coletado, invoke skipado, próxima rule |
898
+ | Erros de invoke do ActionEngine | Erros de diretiva acumulados nos counters |
899
+ | Id de hidden action ausente no momento do invoke | Pipeline aborta com `abortedBy: "action-not-found"`, `success: false` |
900
+ | `when()` de sub-rule lança | Erro coletado, sub-rule skipada |
901
+ | `maxSubRuleDepth` excedido | Erro coletado, sub-tree skipada (sem abort) |
902
902
 
903
- `register()` follows different rulessee [Registration](#registration). Structural errors at boot (missing handler) throw fail-fast.
903
+ `register()` segue regras diferentesver [Registro](#registro). Erros estruturais em boot (handler ausente) lançam fail-fast.
904
904
 
905
- ### Inspecting errors
905
+ ### Inspecionando erros
906
906
 
907
907
  ```typescript
908
908
  const result = engine.evaluate(ctx);
@@ -911,9 +911,9 @@ for (const err of result.errors) {
911
911
  console.log(`Rule index ${err.ruleIndex}: ${err.error}`);
912
912
  }
913
913
 
914
- // Consumer decides what errors mean:
914
+ // O consumer decide o que os erros significam:
915
915
  if (result.errors.length > 0) {
916
- // handle errors
916
+ // trata os erros
917
917
  }
918
918
  ```
919
919
 
@@ -921,7 +921,7 @@ if (result.errors.length > 0) {
921
921
 
922
922
  ## HALT_HANDLER
923
923
 
924
- A built-in handler that signals the ActionEngine to abort directive execution. The RuleEngine's interpreter checks `abortedBy === "halt"` as a controlled stop.
924
+ Um handler built-in que sinaliza ao ActionEngine para abortar a execução de diretivas. O interpretador do RuleEngine checa `abortedBy === "halt"` como uma parada controlada.
925
925
 
926
926
  ```typescript
927
927
  import { HALT_HANDLER } from "@statedelta-actions/rules";
@@ -934,7 +934,7 @@ const actionEngine = createActionEngine({
934
934
  });
935
935
  ```
936
936
 
937
- Usage in directives:
937
+ Uso em diretivas:
938
938
 
939
939
  ```typescript
940
940
  {
@@ -943,22 +943,22 @@ Usage in directives:
943
943
  when: (ctx) => ctx.hp <= 0,
944
944
  then: [
945
945
  { type: "dispatch", target: "status", op: "set", value: "dead" },
946
- { type: "halt" }, // stops all remaining rules
946
+ { type: "halt" }, // para todas as rules restantes
947
947
  ],
948
948
  }
949
949
  ```
950
950
 
951
- When halt fires:
951
+ Quando o halt dispara:
952
952
  - `result.aborted === true`
953
953
  - `result.abortedBy === "halt"`
954
- - `result.success === true` (halt is a controlled stop, not an error)
955
- - Remaining rules are not evaluated
954
+ - `result.success === true` (halt é uma parada controlada, não um erro)
955
+ - As rules restantes não são avaliadas
956
956
 
957
957
  ---
958
958
 
959
959
  ## createInvokerMiddleware
960
960
 
961
- Built-in, opt-in middleware that injects `$invoker` metadata into the action scope:
961
+ Middleware built-in, opt-in, que injeta metadados `$invoker` no scope da action:
962
962
 
963
963
  ```typescript
964
964
  import { createInvokerMiddleware } from "@statedelta-actions/rules";
@@ -969,7 +969,7 @@ const ruleEngine = createRuleEngine({
969
969
  });
970
970
  ```
971
971
 
972
- ### What it injects
972
+ ### O que ele injeta
973
973
 
974
974
  ```typescript
975
975
  {
@@ -981,11 +981,11 @@ const ruleEngine = createRuleEngine({
981
981
  }
982
982
  ```
983
983
 
984
- ### Scope propagation
984
+ ### Propagação de scope
985
985
 
986
- `$invoker` propagates to all sub-actions in the ActionEngine via prototype chain scope. If your handler invokes a child action, the child's `frame.scope.$invoker` inherits from the parent.
986
+ `$invoker` propaga para todas as sub-actions no ActionEngine via scope de prototype chain. Se o seu handler invoca uma action filha, o `frame.scope.$invoker` da filha herda do pai.
987
987
 
988
- ### Use case: audit trail
988
+ ### Caso de uso: trilha de auditoria
989
989
 
990
990
  ```typescript
991
991
  const auditHandler = {
@@ -1004,17 +1004,17 @@ const auditHandler = {
1004
1004
 
1005
1005
  ---
1006
1006
 
1007
- ## Full API Reference
1007
+ ## Referência Completa da API
1008
1008
 
1009
1009
  ### IRuleEngine\<TCtx\>
1010
1010
 
1011
1011
  ```typescript
1012
1012
  interface IRuleEngine<TCtx> {
1013
- // Registration
1013
+ // Registro
1014
1014
  register(rules: readonly RuleDefinition<TCtx>[]): RuleRegisterResult;
1015
1015
  unregister(id: string): boolean;
1016
1016
 
1017
- // Trigger evaluation
1017
+ // Avaliação de trigger
1018
1018
  evaluate(ctx: TCtx): RuleEvaluationResult;
1019
1019
  evaluateAsync(ctx: TCtx): Promise<RuleEvaluationResult>;
1020
1020
 
@@ -1026,9 +1026,9 @@ interface IRuleEngine<TCtx> {
1026
1026
  // JIT
1027
1027
  compile(): void;
1028
1028
 
1029
- // Introspection
1030
- has(id: string): boolean; // accepts qualified IDs for sub-rules
1031
- readonly size: number; // top-level rules count
1029
+ // Introspecção
1030
+ has(id: string): boolean; // aceita IDs qualificados para sub-rules
1031
+ readonly size: number; // contagem de rules top-level
1032
1032
 
1033
1033
  // Accessors
1034
1034
  readonly actionEngine: IActionEngine<TCtx>;
@@ -1041,12 +1041,12 @@ interface IRuleEngine<TCtx> {
1041
1041
 
1042
1042
  ```typescript
1043
1043
  interface RuleEngineConfig<TCtx> {
1044
- actionEngine: IActionEngine<TCtx>; // required
1045
- middleware?: readonly RuleMiddleware<TCtx>[]; // optional, default []
1046
- ruleHooks?: RuleHooks<TCtx>; // optional
1047
- maxSubRuleDepth?: number; // optional, default 10
1048
- mode?: "interpret" | "jit" | "auto"; // optional, default "auto"
1049
- autoJitThreshold?: number; // optional, default 8
1044
+ actionEngine: IActionEngine<TCtx>; // obrigatório
1045
+ middleware?: readonly RuleMiddleware<TCtx>[]; // opcional, default []
1046
+ ruleHooks?: RuleHooks<TCtx>; // opcional
1047
+ maxSubRuleDepth?: number; // opcional, default 10
1048
+ mode?: "interpret" | "jit" | "auto"; // opcional, default "auto"
1049
+ autoJitThreshold?: number; // opcional, default 8
1050
1050
  }
1051
1051
  ```
1052
1052
 
@@ -1066,9 +1066,9 @@ interface FrameCounters {
1066
1066
 
1067
1067
  ---
1068
1068
 
1069
- ## Use Case: RPG Combat Tick
1069
+ ## Caso de Uso: Tick de Combate RPG
1070
1070
 
1071
- A game tick that evaluates combat rules with sub-rules and halt.
1071
+ Um tick de jogo que avalia rules de combate com sub-rules e halt.
1072
1072
 
1073
1073
  ```typescript
1074
1074
  interface GameCtx {
@@ -1080,7 +1080,7 @@ interface GameCtx {
1080
1080
  log: string[];
1081
1081
  }
1082
1082
 
1083
- // --- ActionEngine setup ---
1083
+ // --- Setup do ActionEngine ---
1084
1084
 
1085
1085
  const actionEngine = createActionEngine<GameCtx>({
1086
1086
  handlers: {
@@ -1091,7 +1091,7 @@ const actionEngine = createActionEngine<GameCtx>({
1091
1091
  },
1092
1092
  });
1093
1093
 
1094
- // --- RuleEngine setup ---
1094
+ // --- Setup do RuleEngine ---
1095
1095
 
1096
1096
  const ruleEngine = createRuleEngine<GameCtx>({
1097
1097
  actionEngine,
@@ -1106,18 +1106,18 @@ const ruleEngine = createRuleEngine<GameCtx>({
1106
1106
  // --- Rules ---
1107
1107
 
1108
1108
  ruleEngine.register([
1109
- // High-priority death checkhalts everything
1109
+ // Check de morte de alta priority para tudo
1110
1110
  {
1111
1111
  id: "death-check",
1112
1112
  priority: 500,
1113
1113
  when: (ctx) => ctx.hp <= 0,
1114
1114
  then: [
1115
- { type: "log", message: "dead — halting" },
1115
+ { type: "log", message: "morto — halting" },
1116
1116
  { type: "halt" },
1117
1117
  ],
1118
1118
  },
1119
1119
 
1120
- // Combat zone rules with sub-rules
1120
+ // Rules de zona de combate com sub-rules
1121
1121
  {
1122
1122
  id: "combat-zone",
1123
1123
  priority: 100,
@@ -1137,7 +1137,7 @@ ruleEngine.register([
1137
1137
  ],
1138
1138
  },
1139
1139
 
1140
- // MP regen
1140
+ // Regen de MP
1141
1141
  {
1142
1142
  id: "mp-regen",
1143
1143
  priority: 50,
@@ -1153,16 +1153,16 @@ ruleEngine.register([
1153
1153
  const ctx: GameCtx = { hp: 40, maxHp: 100, mp: 30, zone: "combat", effects: [], log: [] };
1154
1154
 
1155
1155
  const result = ruleEngine.evaluate(ctx);
1156
- // combat-zone fires: hp 40->25, emits "damage-tick"
1157
- // low-hp-heal fires: hp 25->30
1158
- // mp-regen fires: mp 30->33
1156
+ // combat-zone dispara: hp 40->25, emite "damage-tick"
1157
+ // low-hp-heal dispara: hp 25->30
1158
+ // mp-regen dispara: mp 30->33
1159
1159
  ```
1160
1160
 
1161
1161
  ---
1162
1162
 
1163
- ## Use Case: E-commerce Order Pipeline
1163
+ ## Caso de Uso: Pipeline de Pedido E-commerce
1164
1164
 
1165
- An order processing pipeline with validation, tiered discounts, and fraud detection.
1165
+ Um pipeline de processamento de pedido com validação, descontos por tier e detecção de fraude.
1166
1166
 
1167
1167
  ```typescript
1168
1168
  interface OrderCtx {
@@ -1180,7 +1180,7 @@ interface OrderCtx {
1180
1180
  }
1181
1181
 
1182
1182
  ruleEngine.register([
1183
- // 1. Fraud detectionhighest priority, halts pipeline
1183
+ // 1. Detecção de fraude priority mais alta, para o pipeline
1184
1184
  {
1185
1185
  id: "fraud-check",
1186
1186
  priority: 500,
@@ -1192,7 +1192,7 @@ ruleEngine.register([
1192
1192
  ],
1193
1193
  },
1194
1194
 
1195
- // 2. Calculate subtotal
1195
+ // 2. Calcula o subtotal
1196
1196
  {
1197
1197
  id: "calc-subtotal",
1198
1198
  priority: 400,
@@ -1208,12 +1208,12 @@ ruleEngine.register([
1208
1208
  ],
1209
1209
  },
1210
1210
 
1211
- // 3. Tiered discounts via sub-rules
1211
+ // 3. Descontos por tier via sub-rules
1212
1212
  {
1213
1213
  id: "discount-engine",
1214
1214
  priority: 300,
1215
1215
  when: (ctx) => ctx.status === "validated" && ctx.discount === 0,
1216
- then: [{ type: "log", message: "evaluating discounts" }],
1216
+ then: [{ type: "log", message: "avaliando descontos" }],
1217
1217
  rules: [
1218
1218
  {
1219
1219
  id: "gold-discount",
@@ -1234,7 +1234,7 @@ ruleEngine.register([
1234
1234
  ],
1235
1235
  },
1236
1236
 
1237
- // 4. Payment
1237
+ // 4. Pagamento
1238
1238
  {
1239
1239
  id: "process-payment",
1240
1240
  priority: 200,
@@ -1251,9 +1251,9 @@ ruleEngine.register([
1251
1251
 
1252
1252
  ---
1253
1253
 
1254
- ## Use Case: Deployment Approval Workflow
1254
+ ## Caso de Uso: Workflow de Aprovação de Deploy
1255
1255
 
1256
- A CI/CD pipeline with submission, reviewer assignment, approval gates, and deploy strategy selection via sub-rules.
1256
+ Um pipeline de CI/CD com submissão, atribuição de reviewers, gates de aprovação e seleção de estratégia de deploy via sub-rules.
1257
1257
 
1258
1258
  ```typescript
1259
1259
  interface WorkflowCtx {
@@ -1273,7 +1273,7 @@ interface WorkflowCtx {
1273
1273
  }
1274
1274
 
1275
1275
  ruleEngine.register([
1276
- // 1. Rejection checkhighest priority, halts
1276
+ // 1. Check de rejeição priority mais alta, para tudo
1277
1277
  {
1278
1278
  id: "check-rejections",
1279
1279
  priority: 500,
@@ -1284,7 +1284,7 @@ ruleEngine.register([
1284
1284
  ],
1285
1285
  },
1286
1286
 
1287
- // 2. Submission with reviewer assignment via sub-rules
1287
+ // 2. Submissão com atribuição de reviewers via sub-rules
1288
1288
  {
1289
1289
  id: "submit",
1290
1290
  priority: 400,
@@ -1312,7 +1312,7 @@ ruleEngine.register([
1312
1312
  ],
1313
1313
  },
1314
1314
 
1315
- // 3. Deploy strategy by environment + risk via sub-rules
1315
+ // 3. Estratégia de deploy por environment + risco via sub-rules
1316
1316
  {
1317
1317
  id: "deploy",
1318
1318
  priority: 100,
@@ -1322,7 +1322,7 @@ ruleEngine.register([
1322
1322
  {
1323
1323
  id: "deploy-production",
1324
1324
  when: (ctx) => ctx.environment === "production",
1325
- then: [{ type: "log", message: "production deploy" }],
1325
+ then: [{ type: "log", message: "deploy de produção" }],
1326
1326
  rules: [
1327
1327
  {
1328
1328
  id: "canary-deploy",
@@ -1347,31 +1347,31 @@ ruleEngine.register([
1347
1347
 
1348
1348
  ---
1349
1349
 
1350
- ## Performance Spectrum
1350
+ ## Espectro de Performance
1351
1351
 
1352
1352
  ```
1353
- Tier 0 (no hooks, no middleware) Full (hooks + middleware + sub-rules)
1353
+ Tier 0 (sem hooks, sem middleware) Full (hooks + middleware + sub-rules)
1354
1354
  ---------------------------------------------------------------------
1355
- Zero allocations for hooks evalCtx created per evaluate()
1356
- No try/catch try/catch per hook
1357
- No params variable params allocated + middleware pipeline
1358
- Minimal loop Full governance pipeline
1355
+ Zero alocações para hooks evalCtx criado por evaluate()
1356
+ Sem try/catch try/catch por hook
1357
+ Sem variável params params alocados + pipeline de middleware
1358
+ Loop minimal Pipeline completo de governança
1359
1359
  ```
1360
1360
 
1361
- The JIT compiler emits only the code paths that are configured. Tier 0 is the **common case** for high-performance scenarios (game loops, real-time).
1361
+ O compilador JIT emite apenas os code paths que estão configurados. Tier 0 é o **caso comum** para cenários de alta performance (game loops, tempo real).
1362
1362
 
1363
1363
  ---
1364
1364
 
1365
- ## Internal Design Notes
1365
+ ## Notas de Design Interno
1366
1366
 
1367
- For detailed internal architecture, see [`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md).
1367
+ Para arquitetura interna detalhada, veja [`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md).
1368
1368
 
1369
- ### Key decisions
1369
+ ### Decisões-chave
1370
1370
 
1371
- - **Rules are hidden actions** with prefix `rule:`. Sub-rules use `.` separator.
1372
- - **Sub-rules are always interpreted** — JIT compiles only the main loop.
1373
- - **Single exit point** in the interpreter — `onRulesComplete` called exactly once.
1374
- - **Closure counter + noop swap** for auto-promote — zero overhead post-JIT.
1375
- - **`Object.assign` in-place** for middleware — 1 allocation vs N+1.
1376
- - **Immutability by convention** — no `Object.freeze()` (measurable cost in hot paths).
1377
- - **Events are a separate package** — `@statedelta-actions/events`. The RuleEngine does not know about events.
1371
+ - **Rules são hidden actions** com prefixo `rule:`. Sub-rules usam separador `.`.
1372
+ - **Sub-rules são sempre interpretadas** — o JIT compila apenas o loop principal.
1373
+ - **Ponto de saída único** no interpretador — `onRulesComplete` chamado exatamente uma vez.
1374
+ - **Closure counter + swap por noop** para auto-promote — zero overhead pós-JIT.
1375
+ - **`Object.assign` in-place** para middleware — 1 alocação vs N+1.
1376
+ - **Imutabilidade por convenção** — sem `Object.freeze()` (custo mensurável em hot paths).
1377
+ - **Eventos são um package separado** — `@statedelta-actions/events`. O RuleEngine não conhece eventos.