sqlite-graphrag 1.0.21

Local GraphRAG memory for LLMs in a single SQLite file
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
Leia este documento em [inglês (EN)](CHANGELOG.md).


# Changelog

Todas as mudanças notáveis deste projeto serão documentadas neste arquivo.

O formato é baseado em [Keep a Changelog](https://keepachangelog.com/pt-BR/1.1.0/),
e este projeto adere ao [Semantic Versioning](https://semver.org/lang/pt-BR/spec/v2.0.0.html).

## [Sem Versão]

## [1.0.21] - 2026-04-26

### Corrigido
- BERT NER `iob_to_entities` não vaza mais fragmentos WordPiece como `##AI` ou `##hropic` como entidades separadas. Quando BERT emite label `B-*` em um token iniciado por `##` (estado confuso do modelo), o subword é anexado à entidade ativa se houver, ou descartado caso contrário (correção P0 em `src/extraction.rs:381-394`). Validação empírica: auditoria de 138 documentos FlowAiper produziu ZERO fragmentos `##` na tabela de entidades.
- `recall` rejeita queries vazias com `AppError::Validation` e mensagem clara em vez de vazar erro bruto do rusqlite `Invalid column type Null at index: 1, name: distance` (correção P1 em `src/commands/recall.rs`).
- `restore` agora re-embeda o corpo da memória restaurada e faz upsert em `vec_memories` para que recall vetorial funcione em memórias restauradas. v1.0.20 deixava `vec_memories` desatualizado após `forget` + `restore` (correção P1 em `src/commands/restore.rs`).
- `stats` reporta `chunks_total` com precisão consultando `memory_chunks` e tratando apenas erros "no such table" como estado legado do DB; outros erros do SQLite agora são logados via `tracing::warn!` para visibilidade (correção P1 em `src/commands/stats.rs`).
- Seis panics em caminhos de produção convertidos para `unreachable!()` idiomático dentro de blocos `#[cfg(test)]` (correção P1 em `graph_export.rs`, `memory_guard.rs`, `optimize.rs`, `tz.rs`, `namespace_detect.rs`).
- Tabelas de exit codes do README EN e pt-BR agora listam `73` (guarda de memória rejeitou condição de pouca RAM), alinhando com `llms.txt` e semântica do source (correção P1 docs).

### Adicionado
- Campo `RememberResponse.extraction_method: Option<String>` expondo se a extração automática usou `bert+regex` ou caiu em `regex-only`. Campo é omitido do JSON quando `--skip-extraction` está ativo (telemetria P1 em `src/output.rs` e `src/commands/remember.rs`).
- Campo `ExtractionResult.extraction_method` populado por `extract_graph_auto` e `RegexExtractor`, expondo o caminho real de extração (correção P1 em `src/extraction.rs`).
- 2 testes novos cobrindo o fix do merge IOB: `iob_strip_subword_b_prefix` e `iob_subword_orphan_descarta`.

### Modificado
- `Cargo.toml` versão atualizada de `1.0.20` para `1.0.21`.

## [1.0.20] - 2026-04-26

### Corrigido
- Carregamento do modelo BERT NER agora baixa `tokenizer.json` do subdiretório `onnx/` do repositório `Davlan/bert-base-multilingual-cased-ner-hrl` no HuggingFace, onde o arquivo está de fato publicado. A v1.0.19 tentava baixar da raiz do repositório e recebia 404 em toda ingestão, caindo silenciosamente em graceful degradation só com regex (correção P0 primária em `src/extraction.rs::ensure_model_files`).
- Pesos da classifier head do BERT NER agora são carregados do arquivo safetensors via `VarBuilder::pp("classifier").get(...)` tanto para `weight` quanto para `bias`. A v1.0.19 inicializava com `Tensor::zeros`, o que produziria argmax constante em todos os tokens e tornaria toda predição degenerada mesmo após o fix do tokenizer. Este segundo P0 estava mascarado pelo primeiro e foi descoberto durante o planejamento emergencial (correção P0 secundária em `src/extraction.rs::BertNerModel::load`).
- Prefilter regex de identificadores ALL_CAPS agora filtra palavras-regra do português (`NUNCA`, `SEMPRE`, `PROIBIDO`, `OBRIGATÓRIO`, `DEVE`, `JAMAIS`, etc.) e equivalentes em inglês (`NEVER`, `ALWAYS`, `MUST`, `TODO`, `FIXME`, etc.), preservando identificadores com underscore como `MAX_RETRY` e acrônimos como `OPENAI`. Na v1.0.19 contra corpus técnico em PT-BR, 70% das top entidades eram ruído de palavras-regra (correção P1).
- Tipo de entidade para email mudou de `person` para `concept` porque regex sozinho não distingue indivíduos de endereços de role ou lista (correção P2).
- `merge_and_deduplicate` agora emite `tracing::warn!` quando a contagem de entidades é truncada em `MAX_ENTS=30`, expondo o cap antes silencioso (correção P2).
- `build_relationships` agora emite `tracing::warn!` quando o cap de relacionamentos `MAX_RELS=50` é atingido, complementando o aviso de entidades (correção P2).
- `remember` agora trata bodies só com whitespace (`\n\t  `) como vazios para skip de auto-extração, já que `.is_empty()` sozinho deixava whitespace puro passar (correção P3 em `src/commands/remember.rs`).
- Normalização kebab-case de `remember` e `rename` agora aplica `trim_matches('-')` para remover hífens em bordas, corrigindo rejeição de inputs como `my-name-` truncados por limites de comprimento de filename (correção P3 em `src/commands/remember.rs` e `src/commands/rename.rs`).

### Adicionado
- 4 testes unitários novos em `src/extraction.rs` cobrindo o stopword filter (`regex_all_caps_filtra_palavra_regra_pt`), aceitação de identificador com underscore (`regex_all_caps_aceita_constante_com_underscore`), aceitação de acrônimo de domínio (`regex_all_caps_aceita_acronimo_dominio`) e a reclassificação email→concept (`regex_email_captura_endereco`).

### Modificado
- `Cargo.toml` versão bumped de `1.0.19` para `1.0.20`.

## [1.0.19] - 2026-04-26

### Adicionado
- Chunking hierárquico-recursivo de markdown via `text-splitter = "0.30.1"` (`src/chunking.rs::split_into_chunks_hierarchical`) preserva fronteiras H1/H2 e separadores suaves de parágrafo para documentos que começam com marcadores markdown.
- Extração híbrida automática de entidades (`src/extraction.rs::extract_graph_auto`) combinando pré-filtro regex (emails, URLs, UUIDs, identificadores ALL_CAPS) com passagem CPU `candle` BERT NER (`Davlan/bert-base-multilingual-cased-ner-hrl`, ~676 MB safetensors, AFL-3.0). NER opera em janela deslizante com `MAX_SEQ_LEN=512` e `STRIDE=256`, limitado a `MAX_ENTS=30`/`MAX_RELS=50`. O modelo é baixado lazy na primeira execução e degrada graciosamente para apenas regex em caso de falha (via `tracing::warn!`).
- `remember` agora invoca `extract_graph_auto` automaticamente quando `--skip-extraction` está ausente, nenhum `--entities-file`/`--relationships-file`/`--graph-stdin` é fornecido e o body é não-vazio, materializando entidades e relacionamentos `mentions` antes da persistência.
- 15 testes unitários em `src/extraction.rs` cobrindo pré-filtro regex (email/URL/UUID/ALL_CAPS), decodificação IOB (mapeamento PER/ORG/LOC, descarte de DATE, ORG-com-sufixo-`sdk` → `tool`), enforcement de `MAX_RELS`, dedup por nome em lowercase e fallback gracioso quando o modelo NER está ausente.
- 6 novos testes de chunking em `src/chunking.rs` validando fronteiras `# H1` e `## H2`, documentos markdown de 60 KB com overlap 50, fallback de texto puro e separadores suaves de parágrafo `\n\n`.

### Mudado
- `Cargo.toml` adiciona `text-splitter = "0.30.1"` (features `markdown`, `tokenizers`) e `candle-core`/`candle-nn`/`candle-transformers = "0.10.2"` (default-features off) além de `huggingface-hub` (`hf-hub` renomeado) para downloads de modelo.
- `Cargo.toml` faz bump de `sqlite-vec` de `0.1.6` para `0.1.9` (correção de DELETE e melhorias em constraints KNN) e remove seis dependências órfãs (`notify`, `slug`, `toml`, `uuid`, `zerocopy`, `tracing-appender`).
- `Cargo.toml` reduz `tokio` de `features = ["full"]` para o conjunto mínimo `["rt-multi-thread", "sync", "time", "io-util", "macros"]`.
- Footprint de threads do daemon reduzido de ~65 para ≤4 threads sustentadas via `RAYON_NUM_THREADS=2`, `ORT_INTRA_OP_NUM_THREADS=1` e `ORT_INTER_OP_NUM_THREADS=1` definidos em `src/main.rs` antes da inicialização de qualquer runtime.
- A flag `--skip-extraction` agora exibe help string documentando que desabilita a extração automática de entidades/relacionamentos; o campo previamente dormente é reutilizado como toggle visível ao usuário.

### Corrigido
- `recall` agora reporta `DB inexistente` de forma consistente com os demais subcomandos via helper compartilhado `erros::banco_nao_encontrado` (P1-A).
- `recall --min-distance` foi renomeado para `--max-distance` mantendo `min-distance` como alias legado para compatibilidade (P2-K).
- `related ''` rejeita strings vazias com erro de validação claro em vez de produzir zero resultados silenciosamente (P2-L).
- 15+ strings voltadas ao usuário em `embedder.rs`, `daemon.rs`, `paths.rs`, `tokenizer.rs` e `commands/remember.rs` agora exibem traduções em português junto aos originais em inglês (P2-I).
- `--name` é auto-normalizado para kebab-case com `tracing::warn!` quando snake_case ou CapsName são detectados (P2-H).
- Flags ocultas `--body-file`, `--entities-file`, `--relationships-file`, `--graph-stdin`, `--metadata-file` agora expõem `#[arg(help = ...)]` para aparecer no `--help` (P2-G).
- `stats.memories`, `list.items` e `health.counts.memories` foram unificados sob a chave `memories_total` em todos os outputs JSON (P3-E).
- `HybridSearchItem.rrf_score: Option<f64>` agora é populado com o score real de reciprocal-rank-fusion em vez de retornar sempre `null` (P3-F).
- Rejeição de `--tz` agora sugere fusos horários IANA válidos na mensagem de erro (P3-A).

## [1.0.18] - 2026-04-26

### Adicionado
- Novo helper `parent_or_err` em `src/paths.rs` e quatro testes unitários protegem contra paths malformados vindos de `--db /` ou de `SQLITE_GRAPHRAG_DB_PATH` vazio.
- Novo `DaemonSpawnGuard` em `src/daemon.rs` remove o arquivo `daemon-spawn.lock` em encerramento gracioso e emite uma linha estruturada `tracing::info!` ao encerrar o daemon.
- Variável de ambiente `ORT_DISABLE_CPU_MEM_ARENA=1` agora é setada por padrão em `main.rs` antes do fastembed inicializar, complementando a mitigação existente de `with_arena_allocator(false)` contra crescimento descontrolado de RSS em payloads de shapes variáveis.
- README e `README.pt-BR.md` agora expõem quatro variáveis de ambiente `SQLITE_GRAPHRAG_*` adicionais na tabela de configuração em runtime: `DISPLAY_TZ`, `DAEMON_FORCE_AUTOSTART`, `DAEMON_DISABLE_AUTOSTART`, `DAEMON_CHILD`.
- README e `README.pt-BR.md` agora apresentam o cluster de quatro badges exigido pelas regras do projeto: crates.io, docs.rs, license, Contributor Covenant.

### Alterado
- `path.parent().unwrap()` removido de `src/paths.rs`, `src/daemon.rs::try_acquire_spawn_lock` e `src/daemon.rs::save_spawn_state`; os três call sites agora propagam erros de validação via `parent_or_err`.
- Tagline do README reescrita de um parágrafo de 36 palavras para um blockquote de 12 palavras em conformidade com a regra de documentação sobre tamanho de tagline; o parágrafo duplicado acima do blockquote foi removido.
- Snippets de instalação do README não fazem mais hard-code de `--version 1.0.17` em oito locais entre `README.md` e `README.pt-BR.md`; agora recomendam `cargo install sqlite-graphrag --locked` e linkam para `CHANGELOG.md` para o histórico de versões.

### Corrigido
- O CI agora fixa `cargo-nextest` em `0.9.114`, a release mais nova compatível com o MSRV Rust 1.88.
- Os testes Loom agora usam o gate local `sqlite_graphrag_loom` para evitar compilar dependências Tokio sob o `cfg(loom)` upstream.
- O JSON de relacionamentos de grafo agora aceita aliases `from`/`to` e relações com hífen, normalizando antes da gravação.
- Clippy no macOS e testes de concorrência no Windows agora tratam errno e contenção de lock de arquivo específicos da plataforma corretamente.
- A documentação de grafo e `related` agora reflete a superfície real da CLI e não afirma mais extração automática de entidades em ingestão body-only.

## [1.0.17] - 2026-04-26

### Alterado
- `remember` agora aceita payloads de body até `512000` bytes e até `512` chunks, com embeddings multi-chunk seriais para manter a memória limitada em corpora reais de documentação
- `remember --graph-stdin` agora aceita um objeto estrito de grafo com `body` opcional, `entities` e `relationships`, permitindo que um único payload stdin grave texto e grafo explícito

### Corrigido
- A migração de schema `V006__memory_body_limit` eleva o `CHECK` SQLite de `memories.body` para bancos existentes, mantendo o limite Rust e a constraint do banco alinhados
- `scripts/audit-remember-safely.sh` agora envolve cleanup do daemon, init, health e chamadas auditadas de `remember` com `/usr/bin/timeout -k 30 "${AUDIT_TIMEOUT_SECS:-1800}"`
- A documentação de testes agora recomenda comandos longos com timeout para reduzir risco de travamentos locais em runs slow, loom, heavy e audit

## [1.0.16] - 2026-04-26

### Corrigido
- `remember` agora cria e migra o banco padrão `./graphrag.sqlite` antes da escrita, evitando arquivos SQLite vazios e falhas `no such table` em diretórios novos
- `remember --graph-stdin --skip-extraction` agora persiste payloads explícitos de grafo em vez de descartar entidades e relacionamentos silenciosamente
- Falhas em payloads de grafo agora são validadas antes da escrita e memória, chunks, entidades e relacionamentos são persistidos de forma atômica, então input inválido não deixa memórias parciais
- O parser de input de grafo agora rejeita campos desconhecidos e valida `entity_type`, `relation` e `strength` antes de tocar no SQLite
- Docs para agentes, arquivos de contexto para LLMs, schemas e saída de `--help` agora refletem o contrato estrito de JSON via stdin/stdout
- `scripts/test-loom.sh` agora envolve execuções longas de loom com timeout configurável

## [1.0.15] - 2026-04-26

### Corrigido
- `remember --graph-stdin` agora rejeita JSON inválido em vez de persistir payloads malformados como corpos de memória
- `remember` e `edit` agora rejeitam fontes ambíguas de corpo, como `--body` explícito junto com `--body-stdin`
- O CRUD de grafo via `--graph-stdin` agora preserva valores declarados de `entity_type` quando relacionamentos referenciam entidades existentes no input
- `graph --json` agora domina formatos textuais como `--format dot`, `--format mermaid` e saída textual de stats
- `daemon` agora aceita as flags compartilhadas `--db` e `--json`, mantendo a mesma superfície determinística de flags para invocações por agentes

## [1.0.14] - 2026-04-25

### Corrigido
- A matriz oficial de release agora exclui `x86_64-apple-darwin` e `x86_64-unknown-linux-musl`, que a cadeia atual de dependências com `ort` não sustenta por binários ONNX Runtime pré-compilados nesta configuração do projeto
- O workflow de release não tenta mais montar um binário universal macOS a partir de um artefato Intel não suportado
- As docs de release e de compatibilidade agora descrevem apenas os targets que o projeto consegue publicar com consistência sem build custom do ONNX Runtime

## [1.0.13] - 2026-04-25

### Corrigido
- `x86_64-apple-darwin` agora compila em runner Intel macOS explícito, em vez de falhar num host Apple Silicon sem caminho compatível para os binários ORT pré-compilados desse target
- `x86_64-unknown-linux-musl` agora compila via `cross`, fornecendo o toolchain C++ musl exigido por `esaxx-rs`
- O contrato de runtime do ONNX dinâmico em ARM64 GNU e o requisito de runner Windows ARM64 agora ficam preservados na release candidata que validará a matriz completa

## [1.0.12] - 2026-04-25

### Corrigido
- `aarch64-unknown-linux-gnu` agora compila via estratégia target-specific de ONNX Runtime com `load-dynamic`, em vez de falhar na linkedição dos arquivos ORT pré-compilados
- O contrato de runtime de `libonnxruntime.so` no ARM64 GNU agora está documentado explicitamente nas docs de release e nas docs voltadas a agentes
- O workflow de release agora usa o runner oficial GitHub-hosted Windows ARM64 para `aarch64-pc-windows-msvc`, em vez de um runner x64 incompatível

## [1.0.11] - 2026-04-25

### Corrigido
- A cobertura de smoke da binária instalada agora inclui o contrato público de fallback para `./graphrag.sqlite` no diretório da invocação, fechando um ponto cego de auditoria de release
- Os testes de contrato agora exigem os wrappers atuais de `list` (`items`) e `related` (`results`) em vez de aceitar silenciosamente arrays root legados
- `graph traverse` e `graph stats` agora expõem apenas os formatos que realmente suportam, evitando help enganoso e invocações documentadas inválidas
- O texto de help de subcomandos menos centrais agora está consistentemente inglês-first em toda a superfície pública auditada da CLI
- `COOKBOOK`, `AGENTS`, `INTEGRATIONS`, a orientação de schemas e os exemplos de grafo/health agora estão alinhados aos payloads reais e às formas válidas de comando da binária

## [1.0.10] - 2026-04-24

### Alterado
- O `--help` da CLI agora é consistentemente inglês por padrão no output estático do clap, enquanto `--lang` continua controlando apenas mensagens humanas de runtime
- A documentação de release agora deixa explícitos o upgrade com `cargo install ... --force` e a verificação da versão ativa com `sqlite-graphrag --version`
- A documentação de testes agora separa a cobertura padrão do nextest das suítes críticas de contrato em `slow-tests`

### Adicionado
- Novo job de CI `slow-contracts` executa `doc_contract_integration` e `prd_compliance` com `--features slow-tests`
- `installed_binary_smoke` agora exige por padrão paridade de versão entre a binária instalada e o workspace atual, com escape hatch explícito para auditorias legadas deliberadas

## [1.0.9] - 2026-04-24

### Corrigido
- `--skip-memory-guard` agora desabilita auto-start do daemon por padrão, evitando que subprocessos de teste e auditoria deixem daemons residentes sem opt-in explícito
- O daemon agora se encerra quando seu diretório de controle desaparece, evitando que execuções baseadas em `TempDir` deixem processos órfãos
- `installed_binary_smoke` agora desabilita explicitamente o auto-start do daemon para a binária instalada
- `audit-remember-safely.sh` agora isola `SQLITE_GRAPHRAG_CACHE_DIR` e executa `daemon --stop` no encerramento, evitando vazamento de processos após auditorias

### Adicionado
- Novo teste de regressão do daemon provando que `--skip-memory-guard` não auto-sobe o daemon sem opt-in explícito
- Novo teste de regressão do daemon provando que o processo se encerra quando o diretório temporário de cache/controle desaparece

## [1.0.8] - 2026-04-24

### Adicionado
- Auto-start automático do daemon no primeiro comando pesado de embedding quando o socket do daemon está indisponível
- Serialização de spawn via lock file dedicado do daemon para evitar tempestade de processos
- Estado persistido de backoff de spawn do daemon para suprimir tentativas repetidas após falhas
- Novos testes do daemon cobrindo auto-start e restart automático após shutdown

### Alterado
- Comandos pesados agora tentam usar o daemon, sobem o processo sob demanda e fazem fallback local apenas quando backoff ou falha de spawn exigem isso
- `sqlite-graphrag daemon` continua disponível para gestão explícita em foreground, mas deixou de ser obrigatório no caminho comum

### Corrigido
- O maior gap remanescente do daemon na `v1.0.7` foi fechado: o daemon deixou de ser puramente opt-in

## [1.0.7] - 2026-04-24

### Corrigido
- A documentação de integrações não afirma mais que o projeto roda "sem daemons" agora que `sqlite-graphrag daemon` existe
- A documentação voltada a agentes agora descreve o reuso do daemon persistente nos comandos pesados em vez de um modelo puramente stateless
- HOW_TO_USE agora documenta `sqlite-graphrag daemon`, `--ping`, `--stop` e o caminho de fallback automático nos comandos pesados
- TESTING agora documenta a suíte de integração do daemon e o fluxo básico de recuperação do daemon

## [1.0.6] - 2026-04-24

### Adicionado
- Novo subcomando `daemon` para manter o modelo de embeddings carregado em um processo IPC persistente
- Novo protocolo JSON por socket local para `ping`, `shutdown`, `embed_passage`, `embed_query` e embeddings controlados de múltiplas passagens
- Nova suíte de testes de integração do daemon provando que `init`, `remember`, `recall` e `hybrid-search` incrementam o contador de embeddings do daemon quando ele está disponível
- Novo helper `scripts/audit-remember-safely.sh` para auditar binárias instaladas ou locais sob limites de memória via cgroup

### Alterado
- `init`, `remember`, `recall` e `hybrid-search` agora tentam usar o daemon persistente primeiro e fazem fallback para o caminho local atual quando o daemon não está disponível
- `remember` agora usa o tokenizer real de `multilingual-e5-small` antes do embedding, substituindo a aproximação anterior por caracteres no caminho quente
- O embedding multi-chunk em `remember` agora usa micro-batching controlado por orçamento de tokens preenchidos em vez de serialização cega de todos os chunks
- O help de `remember --type` agora deixa explícito que o campo se refere a `memories.type`, não ao `entity_type` do grafo

### Corrigido
- O script de auditoria segura do `remember` agora usa diretório temporário único por execução e valida o banco com `health` após `init`
- Entradas sintéticas densas em bytes, mas abaixo do guard de tamanho, deixaram de fragmentar artificialmente em falhas de 7 chunks na build local melhorada

## [1.0.5] - 2026-04-24

### Corrigido
- `chunking::Chunk` deixou de armazenar corpos owned dos chunks, então o `remember` multi-chunk evita duplicar o corpo inteiro em memória dentro de cada chunk
- A persistência dos chunks agora insere slices de texto diretamente a partir do body armazenado, em vez de alocar outra coleção intermediária owned
- A documentação pública agora descreve corretamente `1.0.4` como release publicada atual e `1.0.5` como próxima linha local
- `remember` agora emite instrumentação de memória por etapa e rejeita documentos que excedem o limite operacional explícito atual de multi-chunk antes de iniciar trabalho ONNX
- O limite operacional explícito de multi-chunk foi reduzido de 8 para 6 após a auditoria segura em cgroup mostrar OOM ainda presente em entradas moderadas com 7 chunks sob `MemoryMax=4G`
- `remember` agora também rejeita corpos multi-chunk densos acima de `4500` bytes antes de iniciar trabalho ONNX, com base na janela de OOM observada na auditoria segura em cgroup
- O embedder agora força `max_length = 512` explicitamente e desabilita a CPU memory arena do ONNX Runtime para reduzir retenção de memória entre inferências repetidas com shapes variáveis

### Causa Raiz
- O desenho anterior ainda duplicava o body por meio de `Vec<Chunk>` carregando `String` owned para cada chunk
- Essa duplicação ampliava a pressão do alocador exatamente no caminho multi-chunk já tensionado pela inferência ONNX
- A ausência de um guard operacional explícito também permitia que entradas Markdown moderadas alcançassem o caminho pesado de embedding multi-chunk sem parada de segurança antecipada
- A auditoria segura subsequente mostrou que até alguns documentos com 7 chunks permaneciam inseguros dentro de um cgroup de `4G`, justificando um teto temporário mais estrito
- A auditoria segura subsequente também mostrou que alguns documentos densos entre `4540` e `4792` bytes ainda disparavam OOM abaixo do teto por chunks, justificando um guard temporário adicional por tamanho do body
- A documentação oficial do ONNX Runtime confirma que `enable_cpu_mem_arena = true` é o padrão, que desligá-lo reduz consumo de memória e que o custo pode ser maior latência
- A API da crate `ort` também documenta que `memory_pattern` deve ser desabilitado quando o tamanho da entrada varia, o que combina com o caminho de `remember` sob inferência repetida e shapes efetivos variáveis
- A inspeção do `fastembed 5.13.2` mostrou que o caminho CPU não desabilita a CPU memory arena do ONNX Runtime por padrão e só desabilita `memory_pattern` automaticamente no caminho DirectML
- A inspeção dos metadados do tokenizer de `multilingual-e5-small` confirmou que o teto real do modelo é `512`, então forçar `max_length = 512` alinha o projeto ao modelo em vez de depender de um default genérico da biblioteca
- A retenção da arena CPU passa, portanto, a ser tratada como causa fortemente sustentada e tecnicamente coerente, mas ainda não como causa única completamente provada em todos os casos patológicos

## [1.0.4] - 2026-04-23

### Corrigido
- `remember` agora gera embeddings de corpos chunkados em modo serial e reutiliza os mesmos embeddings por chunk para agregação e persistência em `vec_chunks`, evitando o caminho de batch que travava com documentos Markdown reais
- `remember` agora evita uma `Vec<String>` extra com cópias dos textos dos chunks e também evita reconstruir uma `Vec<storage::chunks::Chunk>` intermediária antes da persistência dos chunks
- `remember` agora resolve checagens baratas de duplicação antes de qualquer trabalho de embedding e não clona mais o corpo completo desnecessariamente para `NewMemory`
- `namespace-detect` agora aceita `--db` como no-op para que o contrato público do comando fique alinhado com o restante da superfície da CLI
- A documentação pública e o texto do workflow de release agora refletem corretamente a linha publicada `1.0.3` e o contrato de grafo explícito
- O chunking agora usa uma heurística mais conservadora de chars por token e garante progresso seguro em UTF-8, reduzindo o risco de chunks patológicos em entradas Markdown reais

### Causa Raiz
- Markdown real com estrutura rica em parágrafos podia levar a progressão não monotônica dos chunks com a lógica antiga de overlap
- O caminho antigo de `remember` também duplicava pressão de memória ao clonar textos de chunks para uma `Vec<String>` dedicada e ao reconstruir structs de chunk com novas `String` owned antes da persistência
- O caminho antigo de `remember` também gastava trabalho de ONNX antes de resolver condições baratas de duplicação e ainda clonava o corpo completo para `NewMemory` antes do insert ou update
- A combinação aumentava a pressão do alocador e tornava o caminho pesado de embedding mais vulnerável a crescimento patológico de memória em entradas problemáticas

## [1.0.3] - 2026-04-23

### Corrigido
- Comandos pesados agora calculam concorrência segura dinamicamente a partir da memória disponível, número de CPUs e orçamento de RSS por task antes de adquirir slots da CLI
- `init`, `remember`, `recall` e `hybrid-search` agora emitem logs defensivos de progresso mostrando a carga pesada detectada e a concorrência segura calculada
- O runtime agora reduz `--max-concurrency` para o orçamento seguro de memória em comandos pesados, em vez de deixar a heurística documentada sem enforcement
- O orçamento de RSS usado pela heurística de concorrência agora é calibrado a partir de pico de RSS medido, em vez de uma estimativa histórica mais antiga

### Adicionado
- Cobertura unitária para classificação de comandos pesados e cálculo de concorrência segura

## [1.0.2] - 2026-04-23

### Adicionado
- Schemas formais de entrada para `remember --entities-file` e `remember --relationships-file`
- Contrato estável de entrada do grafo em `AGENT_PROTOCOL`, `AGENTS`, `HOW_TO_USE` e `llms-full.txt`
- Resumo curto do contrato de entrada do grafo em `llms.txt` e `llms.pt-BR.txt`

### Corrigido
- Títulos de `AGENTS` agora descrevem `--json` como universal e `--format json` como específico por comando
- A matriz de saída em `HOW_TO_USE` agora reflete a saída padrão real de `link`, `unlink` e `cleanup-orphans`
- A documentação pública não apresenta mais o projeto como pré-publicação

## [1.0.1] - 2026-04-23

### Corrigido
- `--format` foi restringido a `json` nos comandos que não implementam `text` ou `markdown`, evitando que help e parse prometam modos de saída inexistentes
- `hybrid-search` deixou de aceitar `text` ou `markdown` para falhar apenas em runtime; formatos não suportados agora são rejeitados pelo `clap` no parse dos argumentos
- Documentação e guias para agentes agora explicam que `--json` é a flag ampla de compatibilidade, enquanto `--format json` é específico por comando

### Adicionado
- A documentação de payload de `remember` agora explica que `--relationships-file` exige `strength` em `[0.0, 1.0]` e que esse campo é mapeado para `weight` nas saídas do grafo
- A documentação de payload de `remember` agora explica que `type` é aceito como alias de `entity_type`, mas os dois campos juntos são inválidos

## [1.0.0] - 2026-04-19

- Primeira release pública sob o nome `sqlite-graphrag`
- O conjunto de funcionalidades deriva do legado `neurographrag v2.3.0`

### Corrigido
- consulta SQL de graph entities agora usa o nome de coluna correto (NG-V220-01 CRITICAL)
- stats e health agora aceitam a flag --format json (NG-V220-02 HIGH)
- obrigatoriedade de --type no remember documentada em todos os exemplos (NV-005 HIGH)
- documentação de rename corrigida para --name/--new-name (NV-002)
- documentação de recall esclarece argumento posicional QUERY (NV-004)
- documentação de forget remove flag --yes inexistente (NV-001)
- documentação de list referencia campo items correto (NV-006)
- documentação de related referencia campo results correto (NV-010)
- MIGRATION.md agora documenta a transição de rename e o plano de release `v1.0.0`

### Adicionado
- flag obrigatória --relation de unlink documentada (NV-003)
- graph traverse --from espera nome de entidade documentado (NV-007)
- lista de valores restritos de entity_type documentada (NV-009)
- flag --format adicionada ao sync-safe-copy para controle de saída (NG-V220-04)

### Alterado
- __debug_schema esclarece semântica de user_version versus schema_version (NG-V220-03)
- flags globais de i18n documentadas como exclusivas do PT (GAP-I18N-02 LOW)

## [2.2.0] - 2026-04-19

### Corrigido
- G-017: alias `--to` de `sync-safe-copy` restaurado; `--destination` permanece canônico (regressão da v2.0.3)
- G-027: `PRAGMA user_version` agora definido como 49 após migrações refinery para corresponder à contagem de linhas de `refinery_schema_history`
- NG-08: subcomando `health` agora executa `PRAGMA integrity_check` antes das contagens de memórias/entidades para defesa em profundidade; saída ganha campos `journal_mode`, `wal_size_mb` e `checks[]`

### Adicionado
- NG-04: subcomando `graph entities` lista nós do grafo com filtro opcional `--type` e saída `--json`
- NG-06: flag `--format` adicionada ao `graph stats` para paridade com `graph traverse`
- NG-05: subcomando diagnóstico oculto `__debug_schema` documentado; emite campos `schema_version`, `user_version`, `objects` e `migrations`
- NG-03: todos os subcomandos agora aceitam tanto `--json` (forma curta) quanto `--format json` (forma explícita) produzindo saída idêntica

### Alterado
- NG-07: `link` e `unlink` esclarecidos para operar exclusivamente em entidades tipadas do grafo; tipos válidos documentados no `--help`

## [2.1.0] - 2026-04-19

### Corrigido
- G-001: `rename` agora emite `action: "renamed"` no JSON de saída (`src/commands/rename.rs`)
- G-002: ranks do `hybrid-search` agora começam em 1 atendendo restrição `minimum: 1` do schema
- G-003: `--expected-updated-at` agora aplica lock otimista via cláusula WHERE + verificação `changes()` (exit 3 em conflito)
- G-005: prefixo i18n `Error:` agora traduzido para `Erro:` em PT via `i18n::prefixo_erro()` em `main.rs`
- G-007: `health` retorna exit 10 quando `integrity_ok: false` via `AppError::Database` (emite JSON antes de retornar Err)
- G-013: `restore` agora encontra memórias soft-deleted (WHERE inclui `deleted_at IS NOT NULL`)
- G-018: `emit_progress()` agora usa `tracing::info!` respeitando `LOG_FORMAT=json`
- Receitas 8 e 14 do COOKBOOK corrigidas para usar `jaq '.items[]'` conforme estrutura de `list --json`
- Semântica de score no HOW_TO_USE pt-BR corrigida (`score` alto = mais relevante, não distância baixa)

### Adicionado
- G-004: Documentação dos valores válidos de `entity_type` em `--entities-file` (`project|tool|person|file|concept|incident|decision|memory|dashboard|issue_tracker`)
- G-006: `docs/MIGRATION.md` + `docs/MIGRATION.pt-BR.md` com guia de atualização v1.x para v2.x
- G-016: Subcomando `graph traverse` (flags `--from`/`--depth`) com novo schema `docs/schemas/graph-traverse.schema.json`
- G-016: Subcomando `graph stats` com novo schema `docs/schemas/graph-stats.schema.json`
- G-019/G-020: Flag global `--tz` + `tz::init()` em `main.rs` populando `FUSO_GLOBAL` para timestamps com fuso horário
- G-024: Flag `namespace-detect --db` para override de DB múltiplo
- G-025: Flags `vacuum --checkpoint` + `--format`
- G-026: Subcomando `migrate --status` com resposta `applied_migrations`
- G-027: `PRAGMA user_version = 49` definido após conclusão das migrations do refinery
- 6 novas seções H3 em HOW_TO_USE.pt-BR.md (Aliases de Flag de Idioma, Flag de Saída JSON, Descoberta de Caminho do DB, Limite de Concorrência, Nota sobre forget, Nota sobre optimize e migrate)
- Nova receita no COOKBOOK pt-BR: "Como Exibir Timestamps no Fuso Horário Local"

### Alterado
- `migrate.schema.json` agora usa `oneOf` cobrindo os modos run vs `--status` com `$defs.MigrationEntry`
- `--json` aceito como no-op em `remember`/`read`/`history`/`forget`/`purge` para consistência
- `docs/schemas/README.md` documenta convenção de nomenclatura `__debug_schema` (binário) vs kebab-case (arquivo de schema)

### Descontinuado
- `--allow-parallel` removida em v1.2.0 — consulte `docs/MIGRATION.md` para caminho de atualização


## [2.0.5] — 2026-04-19

### Corrigido
- Exit code 13 documentado como `BatchPartialFailure` e exit code 15 como `DbBusy` em AGENTS.md — separação correta conforme `src/errors.rs` desde v2.0.0
- Exit code 73 substituído por 75 (`LockBusy/AllSlotsFull`) em todas as referências de documentação
- `PURGE_RETENTION_DAYS` corrigido de 30 para 90 em AGENTS.md e HOW_TO_USE.md EN+pt-BR — alinhado à constante `PURGE_RETENTION_DAYS_DEFAULT = 90` em `src/constants.rs`

### Adicionado
- `elapsed_ms: u64` padronizado em todos os comandos que ainda não expunham o campo — uniformidade de contrato JSON
- `schema_version: u32` adicionado ao JSON stdout de `health` — facilita detecção de migração por agentes
- Subcomando oculto `__debug_schema` que imprime schema SQLite + versão de migrations para diagnóstico
- Diretório `docs/schemas/` com JSON Schema Draft 2020-12 público de cada resposta
- 12 suites de testes cobrindo: contrato JSON, exit codes P0, migração de schema, concorrência, property-based, sinais, i18n, segurança, benchmarks, smoke de instalado, receitas do cookbook e regressão v2.0.4
- 4 benchmarks criterion em `benches/cli_benchmarks.rs` validando SLAs de latência
- `proptest = { version = "1", features = ["std"] }` e `criterion = { version = "0.5", features = ["html_reports"] }` em `[dev-dependencies]`
- `[[bench]]` com `name = "cli_benchmarks"` e `harness = false` em `Cargo.toml`


## [2.0.4] — 2026-04-19

### Corrigido
- `--expected-updated-at` agora aceita tanto Unix epoch inteiro quanto string RFC 3339 via parser duplo em src/parsers/mod.rs — aplicado em edit, rename, restore, remember (GAP 1 CRITICAL)
- `entities-file` agora aceita o campo `"type"` como alias de `"entity_type"` via `#[serde(alias = "type")]` — elimina erro 422 em payloads válidos de agentes (GAP 12 HIGH)
- Mensagens internas de validação agora localizadas EN/PT via módulo `i18n::validacao` — 7 funções cobrindo comprimento do nome, nome reservado, kebab-case, comprimento de descrição, comprimento de body (GAP 13 MEDIUM)
- Flag `purge --yes` aceita silenciosamente como no-op para compatibilidade com exemplos documentados (GAP 19 MEDIUM)
- Resposta JSON de `link` agora duplica `from` como `source` e `to` como `target` — zero breaking change, adiciona aliases esperados (GAP 20 MEDIUM)
- Objetos de nó em `graph` agora duplicam `kind` como `type` via `#[serde(rename = "type")]` em graph_export.rs — zero breaking change (GAP 21 LOW)
- Registros de versão de `history` agora incluem campo `created_at_iso` RFC 3339 paralelo ao `created_at` Unix existente (GAP 24 LOW)

### Adicionado
- Schema JSON de `health` expandido conforme spec completa do PRD: +db_size_bytes, +integrity_ok, +schema_ok, +vec_memories_ok, +vec_entities_ok, +vec_chunks_ok, +fts_ok, +model_ok, +checks[] com 7 entradas (GAP 4 HIGH)
- Resposta JSON de `recall` agora inclui `elapsed_ms: u64` medido via Instant (GAP 8 HIGH)
- Resposta JSON de `hybrid-search` agora inclui `elapsed_ms: u64`, `rrf_k: u32` e `weights: {vec, fts}` (GAPs 8+10 HIGH)
- Módulo de validação i18n `src/i18n/validacao.rs` — todas as 7 mensagens de erro de validação disponíveis em EN e PT
- Parser de timestamp duplo `src/parsers/mod.rs` — aceita Unix epoch i64 e RFC 3339 via `chrono::DateTime::parse_from_rfc3339`

### Alterado
- Varredura de docs EN (T9): schemas de recall, hybrid-search, list, health, stats alinhados com saída real do binário; pesos corrigidos 0.6/0.4 → 1.0/1.0; namespace padrão documentado como `global`; alias `--json` no-op documentado; `related` documentado para receber nome da memória e não ID
- Varredura de docs PT (T10): COOKBOOK.pt-BR.md, CROSS_PLATFORM.pt-BR.md, AGENTS.pt-BR.md, README.pt-BR.md, skill/sqlite-graphrag-pt/SKILL.md, llms.pt-BR.txt alinhados espelhando as correções EN do T9
- 18 arquivos-fonte binário atualizados; 1 arquivo novo criado (src/parsers/mod.rs)
- 283 testes PASS, zero warnings de clippy, zero erros de check após alterações no binário


## [2.0.3] - 2026-04-19

### Adicionado
- `purge --days` aceito como alias de `--retention-days` para compatibilidade com docs (GAP 3)
- `recall --json` e `hybrid-search --json` aceitos como no-op (GAP 6) — saída JSON já é o padrão
- JSON de `health` agora inclui `wal_size_mb` e `journal_mode` (GAP 7)
- JSON de `stats` agora inclui `edges` (alias de `relationships`) e `avg_body_len` (GAP 8)
- Variantes de `AppError` agora localizadas via enum `Idioma` / match exaustivo de `Mensagem` (GAP 13) — `--lang en/pt` aplica-se também às mensagens de erro
- 8 novas seções em HOW_TO_USE.md para subcomandos sem documentação prévia (GAP 12): cleanup-orphans, edit, graph, history, namespace-detect, rename, restore, unlink
- Espelho bilíngue HOW_TO_USE.pt-BR.md
- Aviso de latência no COOKBOOK informando ~1s por invocação CLI vs planos do daemon (GAP P1)

### Alterado
- Toda a documentação: `--type agent` substituído por `--type project` (GAP 1) — PRD define 7 tipos válidos (user/feedback/project/reference/decision/incident/skill); `agent` nunca foi válido
- Toda a documentação: `purge --days` reescrito como `purge --retention-days` (GAP 3)
- Toda a documentação: exemplos de `remember` agora incluem `--description "..."` (GAP 2)
- README, CLAUDE, AGENT_PROTOCOL: contagem de agentes padronizada em 27 (GAP 14)
- Schemas AGENTS.md: raiz JSON de `recall` documentada como `direct_matches[]/graph_matches[]/results[]` (conforme PRD), `hybrid-search` como `results[]` com `vec_rank/fts_rank` (GAPs 4, 5)
- Padrões do COOKBOOK corrigidos: recall --k 10, list --limit 50, pesos hybrid-search 1.0/1.0, purge --retention-days 90 (GAPs 28-31)
- Nota em docs sobre `distance` (cosseno, menor=melhor) vs `score` (1-distance, maior=melhor) em JSON vs text/markdown (GAP 17)
- Nota em docs sobre namespace padrão `global` (não `default`) (GAP 16)

### Corrigido
- Binário não retorna mais exit 2 para `purge --days 30` (GAP 3)
- Binário não retorna mais exit 2 para `recall --json "q"` (GAP 6)
- Documentação de `link` agora explicita pré-requisito de entidade (GAP 9)
- Documentação da flag `--force-merge` (GAP 18)
- Documentação de `graph --format dot|mermaid` (GAP 22)
- Documentação da flag `--db <PATH>` (GAP 25)
- Documentação de `--max-concurrency` limitado a 2×nCPUs (GAP 27)

### Documentação
- `27 agentes de IA` padronizado como contagem oficial em todo o projeto
- Evidência: plano de testes de 2026-04-19 catalogou 31 gaps em `/tmp/sqlite-graphrag-testplan-v2.0.2/gaps.md`; v2.0.3 fecha todos os 31
- GAP 11 `elapsed_ms` universal em JSON adiado para v2.1.0 (requer captura de processing_time em todos os comandos)
- GAP P1 latência < 50ms requer modo daemon planejado para v3.0.0


## [2.0.2] - 2026-04-19

### Corrigido

- Flag `--lang` agora aceita os códigos curtos `en`/`pt` conforme documentado.
- Antes exigia identificadores completos `english`/`portugues`; aliases adicionados: `en/english/EN`, `pt/portugues/portuguese/pt-BR/pt-br/PT`.


## [2.0.1] - 2026-04-19

### Adicionado

- Aliases de flags para compatibilidade retroativa com a documentação bilíngue.
- `rename --old/--new` adicionados como aliases de `--name/--new-name`.
- `link/unlink --source/--target` adicionados como aliases de `--from/--to`.
- `related --hops` adicionado como alias de `--max-hops`.
- `sync-safe-copy --output` adicionado como alias de `--dest`.
- `related` agora aceita o nome da memória como argumento posicional.
- `--json` aceito como no-op em `health`, `stats`, `migrate`, `namespace-detect`.
- Flag global `--lang en|pt` com fallback via env var `SQLITE_GRAPHRAG_LANG`.
- Fallback de locale `LC_ALL`/`LANG` usado para mensagens de progresso no stderr.
- Novo módulo `i18n` com enum `Language` e helpers `init`/`current`/`tr`.
- Helpers bilíngues adicionados em `output::emit_progress_i18n`.
- Timestamps ISO 8601: `created_at_iso` adicionado em `RememberResponse`.
- `updated_at_iso` adicionado em itens de `list`.
- `created_at_iso`/`updated_at_iso` adicionados em `read`, paralelos aos inteiros epoch existentes.
- Resposta `read` agora inclui `memory_id` (alias de `id`).
- Resposta `read` agora inclui `type` (alias de `memory_type`).
- Resposta `read` agora inclui `version` para controle otimista.
- Itens `hybrid-search` agora incluem `score` (alias de `combined_score`).
- Itens `hybrid-search` agora incluem `source: "hybrid"`.
- Itens `list` agora incluem `memory_id` (alias de `id`).
- Resposta `stats` agora inclui `memories_total`, `entities_total`, `relationships_total`.
- Resposta `stats` agora inclui `chunks_total`, `db_bytes` para conformidade com contrato.
- Resposta `health` agora inclui `schema_version` no topo conforme PRD.
- Resposta `health` agora inclui `missing_entities[]` conforme PRD.
- `RememberResponse` inclui `operation` (alias de `action`), `created_at`, `created_at_iso`.
- `RecallResponse` inclui `results[]` com merge de `direct_matches` e `graph_matches`.
- Flag `init --namespace` adicionada, resolvida e ecoada em `InitResponse.namespace`.
- Flag `recall --min-distance <float>` adicionada (default 1.0, desativada por padrão).
- Quando `--min-distance` abaixo de 1.0, retorna exit 4 se todos os hits excederem o threshold.

### Corrigido

- Arquivos DB criados por `open_rw` agora recebem chmod 600 em Unix.
- Arquivos de snapshot criados por `sync-safe-copy` agora recebem chmod 600 em Unix.
- Previne vazamento de credenciais em montagens compartilhadas (Dropbox, NFS, `/tmp` multi-usuário).
- Mensagens de progresso em `remember`, `recall`, `hybrid-search`, `init` usam helper bilíngue.
- Idioma agora respeitado de forma consistente (antes misturava EN/PT na mesma sessão).

### Documentação

- COOKBOOK, AGENT_PROTOCOL, SKILL, CLAUDE.md atualizados para refletir schemas e flags reais.
- README, INTEGRATIONS e llms.txt atualizados para refletir exit codes reais.
- Validados contra o output de `--help` de cada subcomando.
- Subcomandos `graph` e `cleanup-orphans` agora documentados nos guias apropriados.
- Disclaimer honesto de latência adicionado: recall e hybrid-search levam ~1s por invocação.
- Latência de ~8ms requer daemon (planejado para v3.0.0 Tier 4).


## [2.0.0] - 2026-04-18

### Breaking

- EXIT CODE: `DbBusy` movido de 13 para 15 para liberar exit 13 para `BatchPartialFailure`.
- Scripts shell que detectavam `EX_UNAVAILABLE` (13) como DB busy agora devem checar 15.
- HYBRID-SEARCH: formato JSON da resposta remodelado; formato antigo era `{query, combined_rank[], vec_rank[], fts_rank[]}`.
- Novo formato: `{query, k, results: [{memory_id, name, namespace, type, description, body, combined_score, vec_rank?, fts_rank?}], graph_matches: []}`.
- Consumidores que parseavam `combined_rank` devem migrar para `results` conforme PRD linhas 771-787.
- PURGE: `--older-than-seconds` descontinuada em favor de `--retention-days`.
- A flag antiga permanece como alias oculto mas emite warning; será removida em v3.0.0.
- NAME SLUG: `NAME_SLUG_REGEX` mais estrita que `SLUG_REGEX` da v1.x.
- Nomes multichar devem agora começar com letra (requisito do PRD).
- Single-char `[a-z0-9]` ainda permitido; memórias existentes com dígito inicial passam inalteradas.
- `rename` para nomes estilo legado (dígito inicial, multichar) agora falhará.

### Adicionado

- `AppError::BatchPartialFailure { total, failed }` mapeando para exit 13.
- Reservado para `import`, `reindex` e batch stdin (entrando em Tier 3/4).
- Constantes em `src/constants.rs`: `PURGE_RETENTION_DAYS_DEFAULT=90`, `MAX_NAMESPACES_ACTIVE=100`.
- Constantes: `EMBEDDING_MAX_TOKENS=512`, `K_GRAPH_MATCHES_LIMIT=20`, `K_LIST_DEFAULT_LIMIT=100`.
- Constantes: `K_GRAPH_ENTITIES_DEFAULT_LIMIT=50`, `K_RELATED_DEFAULT_LIMIT=10`, `K_HISTORY_DEFAULT_LIMIT=20`.
- Constantes: `WEIGHT_VEC_DEFAULT=1.0`, `WEIGHT_FTS_DEFAULT=1.0`, `TEXT_BODY_PREVIEW_LEN=200`.
- Constantes: `ORT_NUM_THREADS_DEFAULT="1"`, `ORT_INTRA_OP_NUM_THREADS_DEFAULT="1"`, `OMP_NUM_THREADS_DEFAULT="1"`.
- Constantes: `BATCH_PARTIAL_FAILURE_EXIT_CODE=13`, `DB_BUSY_EXIT_CODE=15`.
- Flag `--dry-run` e `--retention-days` em `purge`.
- Campos `namespace` e `merged_into_memory_id: Option<i64>` em `RememberResponse`.
- Campo `k: usize` em `RecallResponse`.
- Campos `bytes_freed: i64`, `oldest_deleted_at: Option<i64>` em `PurgeResponse`.
- Campos `retention_days_used: u32`, `dry_run: bool` em `PurgeResponse`.
- Flag `--format` em `hybrid-search` (apenas JSON; text/markdown reservados para Tier 2).
- Flag `--expected-updated-at` (optimistic locking) em `rename` e `restore`.
- Guard de limite de namespaces ativos (`MAX_NAMESPACES_ACTIVE=100`) em `remember`.
- Retorna exit 5 quando o limite de namespaces ativos é excedido.

### Alterado

- `SLUG_REGEX` renomeada para `NAME_SLUG_REGEX` com valor conforme PRD.
- Novo padrão: `r"^[a-z][a-z0-9-]{0,78}[a-z0-9]$|^[a-z0-9]$"`.
- Nomes multichar devem começar com letra.

### Corrigido

- Prefixo `__` explicitamente rejeitado em `rename` (antes apenas aplicado em `remember`).
- Constantes `WEIGHT_VEC_DEFAULT`, `WEIGHT_FTS_DEFAULT` agora declaradas em `constants.rs`.
- Referências do PRD agora mapeiam símbolos reais.


## [1.2.1] - 2026-04-18

### Corrigido

- Falha de instalação em versões de `rustc` no intervalo `1.88..1.95`.
- Causada pela dependência transitiva `constant_time_eq 0.4.3` (puxada via `blake3`).
- Essa dependência elevou seu MSRV para 1.95.0 em uma patch release.
- `cargo install sqlite-graphrag` sem `--locked` agora sucede.
- Pin direto `constant_time_eq = "=0.4.2"` força versão compatível com `rust-version = "1.88"`.

### Alterado

- `Cargo.toml` agora declara pin preventivo explícito `constant_time_eq = "=0.4.2"`.
- Comentário inline documenta a razão do drift de MSRV.
- Pin será revisitado quando `rust-version` for elevado para 1.95.
- Instruções de instalação do `README.md` (EN e PT) atualizadas para `cargo install --locked sqlite-graphrag`.
- Bullet adicionado explicando a motivação para `--locked`.

### Adicionado

- Seção `docs_rules/prd.md` "Dependency MSRV Drift Protection" documenta o padrão canônico de mitigação.
- Padrão: pinagem direta de dependências transitivas problemáticas no `Cargo.toml` de nível superior.


## [1.2.0] - 2026-04-18

### Adicionado

- Semáforo de contagem cross-process com até 4 slots simultâneos via `src/lock.rs` (`acquire_cli_slot`).
- Memory guard abortando com exit 77 quando RAM livre está abaixo de 2 GB via `sysinfo` (`src/memory_guard.rs`).
- Signal handler para SIGINT, SIGTERM e SIGHUP via `ctrlc` com feature `termination`.
- Flag `--max-concurrency <N>` para controlar limite de invocações paralelas em runtime.
- Flag oculta `--skip-memory-guard` para testes automatizados onde a alocação real não ocorre.
- Constantes `MAX_CONCURRENT_CLI_INSTANCES`, `MIN_AVAILABLE_MEMORY_MB`, `CLI_LOCK_DEFAULT_WAIT_SECS` em `src/constants.rs`.
- Constantes `EMBEDDING_LOAD_EXPECTED_RSS_MB` e `LOW_MEMORY_EXIT_CODE` em `src/constants.rs`.
- Variantes `AppError::AllSlotsFull` e `AppError::LowMemory` com mensagens em português brasileiro.
- Global `SHUTDOWN: AtomicBool` e função `shutdown_requested()` em `src/lib.rs`.

### Alterado

- Default da flag `--wait-lock` aumentado para 300 segundos (5 minutos) via `CLI_LOCK_DEFAULT_WAIT_SECS`.
- Lock file migrado de `cli.lock` único para `cli-slot-{N}.lock` (semáforo de contagem N=1..4).

### Removido

- BREAKING: flag `--allow-parallel` removida; causou OOM crítico em produção (incidente 2026-04-18).

### Corrigido

- Bug crítico onde invocações CLI paralelas esgotavam a RAM do sistema.
- 58 invocações simultâneas travaram o computador por 38 minutos (incidente 2026-04-18).


## [Unreleased]

### Adicionado

- Flags globais `--allow-parallel` e `--wait-lock SECONDS` para concorrência controlada.
- Módulo `src/lock.rs` implementando lock single-instance baseado em arquivo via `fs4`.
- Nova variante `AppError::LockBusy` mapeando para exit code 75 (`EX_TEMPFAIL`).
- Variáveis de ambiente `ORT_NUM_THREADS`, `OMP_NUM_THREADS` e `ORT_INTRA_OP_NUM_THREADS` pré-definidas para 1.
- Singleton `OnceLock<Mutex<TextEmbedding>>` para reuso do modelo intra-processo.
- Testes de integração em `tests/lock_integration.rs` cobrindo aquisição e liberação de lock.
- `.cargo/config.toml` com `RUST_TEST_THREADS` conservador padrão e aliases cargo padronizados.
- `.config/nextest.toml` com profiles `default`, `ci`, `heavy` e override `threads-required` para loom e stress.
- `scripts/test-loom.sh` como invocação canônica local com `RUSTFLAGS="--cfg loom"`.
- `docs/TESTING.md` e `docs/TESTING.pt-BR.md` guia bilíngue de testes.
- Feature Cargo `slow-tests` para futuros testes pesados opt-in.

### Alterado

- Comportamento padrão agora é single-instance.
- Uma segunda invocação concorrente sai com código 75 exceto se `--allow-parallel` for passada.
- Módulo embedder refatorado de struct-com-estado para funções livres operando sobre um singleton.
- Mover `loom = "0.7"` para `[target.'cfg(loom)'.dev-dependencies]` — ignorado em cargo test padrão.
- Remover feature Cargo legada `loom-tests` substituída pelo gate oficial `#[cfg(loom)]`.
- Workflow CI `ci.yml` migrado para `cargo nextest run --profile ci` com `RUST_TEST_THREADS` explícito por job.
- Job CI loom agora exporta `LOOM_MAX_PREEMPTIONS=2`, `LOOM_MAX_BRANCHES=500`, `RUST_TEST_THREADS=1`, `--release`.

### Corrigido

- Previne OOM livelock quando a CLI é invocada em paralelismo massivo por orquestradores LLM.
- Previne livelock térmico nos testes loom ao alinhar gate `#[cfg(loom)]` com padrão upstream.
- Serializa `tests/loom_lock_slots.rs` com `#[serial(loom_model)]` para impedir execução paralela dos modelos loom.


## [0.1.0] - 2026-04-17

### Adicionado

- Fase 1: Fundação: schema SQLite com vec0 (sqlite-vec), FTS5, grafo de entidades.
- Fase 2: Subcomandos essenciais: init, remember, recall, read, list, forget, rename, edit, history.
- Fase 2 continuação: restore, health, stats, optimize, purge, vacuum, migrate, hybrid-search.
- Fase 2 continuação: namespace-detect, sync-safe-copy.

### Corrigido

- Bug de corrupção FTS5 external-content no ciclo forget+purge.
- Removido DELETE manual em forget.rs que causava a corrupção.

### Alterado

- MSRV elevado de 1.80 para 1.88 (exigido por dependências transitivas base64ct 1.8.3, ort-sys, time).

- Os links históricos abaixo continuam apontando para o repositório legado `neurographrag`
- O projeto renomeado inicia sua linha pública de versões em `sqlite-graphrag v1.0.0`

[Unreleased]: https://github.com/daniloaguiarbr/neurographrag/compare/v2.3.0...HEAD
[2.1.0]: https://github.com/daniloaguiarbr/neurographrag/releases/tag/v2.1.0
[2.0.2]: https://github.com/daniloaguiarbr/neurographrag/releases/tag/v2.0.2
[2.0.1]: https://github.com/daniloaguiarbr/neurographrag/releases/tag/v2.0.1
[2.0.0]: https://github.com/daniloaguiarbr/neurographrag/releases/tag/v2.0.0
[1.2.1]: https://github.com/daniloaguiarbr/neurographrag/releases/tag/v1.2.1
[1.2.0]: https://github.com/daniloaguiarbr/neurographrag/releases/tag/v1.2.0
[0.1.0]: https://github.com/daniloaguiarbr/neurographrag/releases/tag/v0.1.0