wendkeep 0.85.1 → 0.87.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/.githooks/commit-msg +16 -0
  2. package/.githooks/prepare-commit-msg +16 -0
  3. package/CHANGELOG.md +40 -0
  4. package/README.en.md +4 -1
  5. package/README.md +4 -1
  6. package/docs/en/commands/commit.md +159 -0
  7. package/docs/en/commands/evidence-embeddings.md +243 -0
  8. package/docs/en/commands/mcp.md +67 -7
  9. package/docs/pt-BR/commands/commit.md +159 -0
  10. package/docs/pt-BR/commands/evidence-embeddings.md +244 -0
  11. package/docs/pt-BR/commands/mcp.md +66 -7
  12. package/hooks/evidence-context.mjs +41 -7
  13. package/hooks/evidence-recall.mjs +10 -0
  14. package/package.json +5 -2
  15. package/packages/cli/src/index.mjs +11 -1
  16. package/packages/commit/package.json +6 -0
  17. package/packages/commit/src/cli.mjs +89 -0
  18. package/packages/commit/src/commit-input.mjs +181 -0
  19. package/packages/commit/src/commit-message.mjs +51 -0
  20. package/packages/commit/src/commit-policy.mjs +144 -0
  21. package/packages/commit/src/git-runtime.mjs +428 -0
  22. package/packages/commit/src/index.mjs +28 -0
  23. package/packages/commit/src/proof-validation.mjs +443 -0
  24. package/packages/mcp/src/effects.mjs +3 -2
  25. package/packages/mcp/src/evidence-recall.mjs +130 -0
  26. package/packages/mcp/src/executor.mjs +4 -0
  27. package/packages/mcp/src/server.mjs +31 -1
  28. package/packages/vault/src/evidence-embedding-plugin.mjs +531 -0
  29. package/packages/vault/src/evidence-index-store.mjs +360 -0
  30. package/packages/vault/src/evidence-recall-page.mjs +381 -0
  31. package/packages/vault/src/evidence-search-index.mjs +917 -0
  32. package/packages/vault/src/index.mjs +12 -1
  33. package/packages/vault/src/memory-ledger-view-base.mjs +545 -0
  34. package/packages/vault/src/memory-ledger-view.mjs +41 -0
  35. package/packages/vault/src/memory-rotation-store.mjs +967 -0
  36. package/packages/vault/src/memory-segment-store.mjs +820 -0
  37. package/packages/vault/src/memory-snapshot-store.mjs +1105 -0
  38. package/packages/vault/src/memory-store-base.mjs +1161 -0
  39. package/packages/vault/src/memory-store-core.mjs +2 -0
  40. package/packages/vault/src/memory-store.mjs +46 -1161
  41. package/schema/commit-message-v1.schema.json +75 -0
  42. package/scripts/validate-commit-range.mjs +244 -0
  43. package/src/doctor.mjs +48 -5
  44. package/src/evidence-search-health.mjs +221 -0
  45. package/src/git-commit-hooks.mjs +112 -0
  46. package/src/init.mjs +13 -0
  47. package/src/memory-scale-health.mjs +210 -0
  48. package/src/observer-snapshot.mjs +87 -1
  49. package/src/skills-seed.mjs +79 -0
@@ -0,0 +1,159 @@
1
+ # Commits baseados em evidências
2
+
3
+ **PT-BR** · [English](../../en/commands/commit.md)
4
+
5
+ ## Objetivo
6
+
7
+ Produzir a mesma mensagem auditável em Codex, Claude Code ou outro cliente Git, usando somente
8
+ entrada tipada, referências públicas e o resumo do index staged. O kernel é determinístico e não
9
+ lê o Vault, `.brain`, registros de sessão ou rede.
10
+
11
+ ## Quando usar
12
+
13
+ Use antes de commits de implementação `feat`, `fix`, `refactor` ou `perf` que precisam registrar
14
+ autoridade causal, tarefas, testes, escopo e evidência verificável de forma equivalente entre
15
+ harnesses.
16
+
17
+ ## Quando não usar
18
+
19
+ Não use para inventar prova, publicar conteúdo privado, reescrever histórico ou automatizar push.
20
+ Commits `docs`, `test` e `chore` dispensam contexto somente quando todos os arquivos alterados são
21
+ objetivamente documentação/testes. Alteração de produto exige o corpo governado mesmo com outro tipo.
22
+
23
+ ## Pré-requisitos
24
+
25
+ Execute dentro de um repositório Git, com o WendKeep instalado localmente e os arquivos do produto
26
+ já selecionados no index staged.
27
+
28
+ ## Sintaxe
29
+
30
+ ```bash
31
+ npx --no-install wendkeep commit context --input <json|-> [--json]
32
+ npx --no-install wendkeep commit context --clear [--json]
33
+ npx --no-install wendkeep commit render --input <json|->
34
+ npx --no-install wendkeep commit prepare --message-file <path> [--source <source>]
35
+ npx --no-install wendkeep commit validate --message-file <path> [--json]
36
+ ```
37
+
38
+ ## Opções e códigos de saída
39
+
40
+ - Exit `0`: contexto escrito/limpo ou mensagem válida.
41
+ - Exit `1`: mensagem governada inválida.
42
+ - Exit `2`: argumento, JSON, Git, privacidade ou contexto inválido/stale.
43
+ - `--consume-context` é reservado ao wrapper `commit-msg`; remove o contexto após validação verde.
44
+
45
+ ## Instalação opt-in
46
+
47
+ Os hooks Git não são ativados pelo `init` padrão. Para copiar os wrappers portáteis e configurar
48
+ `core.hooksPath=.githooks` somente neste repositório:
49
+
50
+ ```bash
51
+ npx --no-install wendkeep init --git-commit-hooks --yes
52
+ ```
53
+
54
+ Hooks personalizados nunca são sobrescritos silenciosamente. Se o `init` encontrar conflito, ele
55
+ preserva o arquivo. Revise-o e, somente se quiser substituí-lo, execute novamente com `--force`; o
56
+ arquivo anterior fica em `.bak`.
57
+ Um `core.hooksPath` customizado também é conflito: sem `--force` ele permanece intocado.
58
+
59
+ ## Exemplos
60
+
61
+ ### Preparar um commit
62
+
63
+ Crie um JSON conforme `schema/commit-message-v1.schema.json`. Declare autoridade e referências de
64
+ evidência, mas não envie `tasks`, `tests`, `fresh` ou `verified`. O runtime deriva tarefas do
65
+ checklist canônico com Task Contracts concluídos. Testes vêm somente de sensores declarados por
66
+ `[sensor:<id>]` e executados pelo coletor; `[phase:verify]`
67
+ sozinho nunca é resultado. Sensors declarados no Envelope devem corresponder exatamente em IDs,
68
+ configuração, comando, severidade e resultado à reexecução canônica; apenas essa reexecução gera a
69
+ linha `Tests`. O gate remoto reexecuta o sensor no checkout do SHA correspondente.
70
+ Cada referência publicada recebe digest SHA-256 rederivado. ADR/design validam
71
+ ID/path/artefato. Tasks com `[req:]` exigem uma referência `spec` versionada e sanitizada que defina
72
+ cada requisito. Evidence Envelope, Verdict, receipt e TDD attestation podem participar da validação
73
+ local, mas são omitidos da Evidence remota: não há publicação de IDs de worktree/sessão/branch nem
74
+ promoção de consistência autocontida para prova. Se uma mensagem os alegar como `fresh`/`verified`,
75
+ o range rejeita `WENDKEEP_COMMIT_REMOTE_PROOF_UNAVAILABLE`. Os trailers fixos
76
+ `Remote-Proof-Scope: git,authority,tasks,spec,sensors` e `Local-Causal-Proof: unpublished` tornam
77
+ essa fronteira explícita. No range, authority/artefatos, task/spec, `Scope` Git e config/sensors são
78
+ rederivados do SHA, e apenas a reexecução canônica gera `Tests`. `Co-Authored-By` é
79
+ omitido enquanto não houver identidade registrada confiável.
80
+
81
+ A autoridade normal é a ADR causal:
82
+
83
+ ```json
84
+ { "authority": { "kind": "adr", "adr": "ADR-1234", "ref": "docs/ADR-1234.md", "issue": "#123" } }
85
+ ```
86
+
87
+ Somente quando não existe change/ADR causal, o harness nativo pode declarar o fallback abaixo.
88
+ `issue` deve ser `#NNN` e `design` precisa estar versionado no mesmo commit sob
89
+ `docs/superpowers/specs/` ou `plans/`:
90
+
91
+ ```json
92
+ {
93
+ "authority": {
94
+ "kind": "native",
95
+ "issue": "#40",
96
+ "design": "docs/superpowers/specs/design-aprovado.md"
97
+ }
98
+ }
99
+ ```
100
+
101
+ O runtime confirma perfil efetivo `OFF`, ausência de context/change/lease e ADR causal reais, além
102
+ da issue no design. Esse modo gera trailers únicos `Authority: native-no-causal-change`, `Issue` e `Design`. Texto solto,
103
+ design não versionado, prova stale/unverified, corpo ou testes ausentes falham fechados.
104
+
105
+ ```bash
106
+ git add <arquivos-do-produto>
107
+ npx --no-install wendkeep commit context --input commit-input.json
108
+ git commit -m "feat(escopo): rascunho"
109
+ ```
110
+
111
+ `commit context` calcula o hash SHA-256 do diff staged e guarda o contexto sanitizado em
112
+ `.git/wendkeep-commit-input.json`, fora do working tree. `prepare-commit-msg` substitui o rascunho
113
+ pela mensagem canônica; `commit-msg` valida e consome o contexto. Se o index mudar, o contexto fica
114
+ stale e deve ser recriado.
115
+ O `commit-msg` relê o contexto, compara a mensagem inteira e o hash/files staged, e só consome o
116
+ contexto após sucesso. `merge`, `squash` e amend limpam contexto incompatível para não contaminar o
117
+ commit seguinte. `--message-file` fica contido no repositório ou git-dir.
118
+
119
+ Outros comandos:
120
+
121
+ ```bash
122
+ npx --no-install wendkeep commit render --input commit-input.json
123
+ npx --no-install wendkeep commit validate --message-file .git/COMMIT_EDITMSG
124
+ npx --no-install wendkeep commit context --clear
125
+ ```
126
+
127
+ Commits realmente triviais permanecem intactos. Commits de implementação
128
+ `feat`, `fix`, `refactor` e `perf` exigem assunto Conventional Commit com ADR ou o fallback nativo
129
+ restrito acima, seções Capability, Evidence, Tasks, Tests e Scope, hash staged e trailer
130
+ `WendKeep-Commit: v1`. Amend, merge e squash não recebem corpo duplicado ou prova inventada.
131
+
132
+ ## Privacidade e falha segura
133
+
134
+ - Caminhos absolutos mesmo embutidos, qualquer Vault configurado/default, `.brain`, registros de sessão, PII e segredos são
135
+ rejeitados antes da persistência.
136
+ - Evidência `reported`, `legacy-unbound`, `stale` ou `unproven` não pode ser apresentada como prova.
137
+ - O contexto contém referências sanitizadas e metadados do diff, nunca o conteúdo privado do Vault.
138
+ - `--no-verify` não é um fluxo aceito: o CI valida cada commit novo, inclusive merges e resoluções inéditas.
139
+
140
+ ## Resultado esperado
141
+
142
+ Uma mensagem determinística, autocontida, sem material privado, com hash do mesmo index que foi
143
+ commitado e trailers causais coerentes.
144
+
145
+ ## Erros comuns e diagnóstico
146
+
147
+ `wendkeep doctor` mostra `[commit-hooks] healthy`, `disabled`, `missing` ou `drift` e permanece
148
+ read-only. Para recuperar arquivos ausentes ou divergentes após revisão:
149
+
150
+ ```bash
151
+ npx --no-install wendkeep init --git-commit-hooks --force --yes
152
+ ```
153
+
154
+ Se um commit for abandonado, limpe apenas o contexto transitório com
155
+ `wendkeep commit context --clear`. Nenhum comando reescreve histórico ou faz push automaticamente.
156
+
157
+ ## Próximos passos
158
+
159
+ Revise a mensagem gerada, faça o commit e deixe o gate de range do PR validar qualquer bypass local.
@@ -0,0 +1,244 @@
1
+ # Plugin opcional de embeddings de evidências
2
+
3
+ [English](../../en/commands/evidence-embeddings.md)
4
+
5
+ ## Objetivo
6
+
7
+ Definir uma fronteira programática para reranqueamento semântico local sem adicionar modelo,
8
+ runtime de ML, vector database, cliente HTTP ou dependência de provider ao Core do WendKeep.
9
+
10
+ Esta superfície **não é um comando CLI**. Ela é exportada por `wendkeep/vault` para plugins locais
11
+ carregados explicitamente pelo composition root da aplicação.
12
+
13
+ ## Quando usar
14
+
15
+ Use esta API quando um composition root confiável precisar reranquear um conjunto pequeno de
16
+ candidatos que o recall lexical/FTS já filtrou, mantendo o modelo e o adapter fora do Core.
17
+
18
+ Embeddings ficam desligados por padrão.
19
+
20
+ ```js
21
+ const result = await rerankEvidenceCandidatesWithEmbedding(rows, query);
22
+ // result.metrics.status === 'disabled'
23
+ ```
24
+
25
+ O Core:
26
+
27
+ - não procura plugins em `node_modules`;
28
+ - não executa `import()` a partir de configuração do Vault;
29
+ - não baixa modelos;
30
+ - não abre conexão de rede;
31
+ - não persiste vetores;
32
+ - não entrega o corpus inteiro ao plugin.
33
+
34
+ Um plugin só recebe dados quando o chamador fornece o objeto do plugin e define `enabled: true`.
35
+
36
+ ## Quando não usar
37
+
38
+ Não use o plugin como índice autoritativo, mecanismo de ampliação de escopo, autoload de código ou
39
+ substituto para filtros/recall lexical. Também não use provider remoto: o contrato exige execução
40
+ local, in-process, sem rede e sem retenção.
41
+
42
+ ### Contrato de autoridade
43
+
44
+ A ordem de autoridade permanece:
45
+
46
+ ```text
47
+ Markdown/JSONL do Vault → índice incremental → candidatos lexical/FTS → reranqueamento opcional
48
+ ```
49
+
50
+ O plugin atua somente sobre um prefixo bounded de candidatos já filtrados. Ele não pode:
51
+
52
+ - tornar seu índice ou cache a autoridade;
53
+ - ampliar silenciosamente o escopo de projeto, sessão, change ou logical path;
54
+ - ocultar `authority`, `validity` ou proveniência;
55
+ - remover candidatos não processados — eles permanecem no final, na ordem original;
56
+ - alterar os objetos-fonte retornados pelo Core.
57
+
58
+ ## Pré-requisitos
59
+
60
+ - plugin local revisado e carregado explicitamente pela aplicação;
61
+ - modelo/configuração fixados por fingerprint SHA-256;
62
+ - budgets de batch e bytes definidos;
63
+ - candidatos já filtrados pelo recall lexical/FTS.
64
+
65
+ ### Manifest versionado
66
+
67
+ Use `buildEvidenceEmbeddingManifest()` para criar o manifest e
68
+ `createEvidenceEmbeddingPlugin()` para vinculá-lo à função `embed`.
69
+
70
+ Campos obrigatórios:
71
+
72
+ | Campo | Regra |
73
+ |---|---|
74
+ | `schema_version` | `1` |
75
+ | `protocol_version` | `1` |
76
+ | `plugin_id` | identificador estável e local |
77
+ | `plugin_version` | versão do adapter |
78
+ | `model_id` | identificador do modelo |
79
+ | `model_revision` | revisão imutável usada pelo adapter |
80
+ | `model_fingerprint` | `sha256:<64 hex>` do modelo/configuração efetiva |
81
+ | `dimensions` | 1 a 65536 |
82
+ | `locality` | exatamente `local` |
83
+ | `transport` | exatamente `in-process` |
84
+ | `network` | exatamente `forbidden` |
85
+ | `retention` | exatamente `none` |
86
+ | `max_batch_size` | 1 a 512 documentos |
87
+ | `max_input_bytes` | 1 a 4 MiB |
88
+ | `integrity` | hash do payload canônico do manifest |
89
+
90
+ O manifest é declarativo. JavaScript arbitrário não pode ser sandboxado pelo Core; portanto, instale
91
+ somente plugins locais confiáveis e revise seu código. O WendKeep impede carregamento automático e
92
+ valida o contrato antes de entregar qualquer evidência, mas não transforma código de terceiros em
93
+ código confiável.
94
+
95
+ ## Sintaxe
96
+
97
+ ```text
98
+ buildEvidenceEmbeddingManifest(options)
99
+ createEvidenceEmbeddingPlugin({ manifest, embed })
100
+ verifyEvidenceEmbeddingPlugin(plugin)
101
+ rerankEvidenceCandidatesWithEmbedding(rows, query, options)
102
+ ```
103
+
104
+ ## Exemplos
105
+
106
+ ```js
107
+ import {
108
+ buildEvidenceEmbeddingManifest,
109
+ createEvidenceEmbeddingPlugin,
110
+ rerankEvidenceCandidatesWithEmbedding,
111
+ } from 'wendkeep/vault';
112
+
113
+ const manifest = buildEvidenceEmbeddingManifest({
114
+ plugin_id: 'local.minha-embedding',
115
+ plugin_version: '1.0.0',
116
+ model_id: 'local.meu-modelo',
117
+ model_revision: '2026.08.27',
118
+ model_fingerprint: 'sha256:<hash-do-modelo-e-configuracao>',
119
+ dimensions: 384,
120
+ max_batch_size: 64,
121
+ max_input_bytes: 262144,
122
+ });
123
+
124
+ const plugin = createEvidenceEmbeddingPlugin({
125
+ manifest,
126
+ async embed(request, { signal }) {
127
+ // Adapter local: nenhum acesso de rede e nenhuma retenção de texto.
128
+ // Deve devolver exatamente uma query vector e um vector para cada document.id.
129
+ return {
130
+ schema_version: 1,
131
+ model_fingerprint: manifest.model_fingerprint,
132
+ query_vector: await localModel.embed(request.query.text, { signal }),
133
+ document_vectors: await Promise.all(request.documents.map(async (document) => ({
134
+ id: document.id,
135
+ vector: await localModel.embed(document.text, { signal }),
136
+ }))),
137
+ };
138
+ },
139
+ });
140
+
141
+ const reranked = await rerankEvidenceCandidatesWithEmbedding(rows, query, {
142
+ enabled: true,
143
+ plugin,
144
+ maxCandidates: 64,
145
+ maxInputBytes: 262144,
146
+ });
147
+ ```
148
+
149
+ O request contém somente:
150
+
151
+ ```json
152
+ {
153
+ "schema_version": 1,
154
+ "model_fingerprint": "sha256:...",
155
+ "query": { "text": "..." },
156
+ "documents": [
157
+ { "id": "<chunk_id>", "text": "<title + heading + content>" }
158
+ ]
159
+ }
160
+ ```
161
+
162
+ `logical_path` não é enviado ao plugin. A proveniência completa permanece nos objetos-fonte e volta
163
+ com a ordem reranqueada.
164
+
165
+ ## Resultado esperado
166
+
167
+ A resposta é fail-closed e deve conter apenas:
168
+
169
+ ```json
170
+ {
171
+ "schema_version": 1,
172
+ "model_fingerprint": "sha256:...",
173
+ "query_vector": [0.1, 0.2],
174
+ "document_vectors": [
175
+ { "id": "<chunk_id>", "vector": [0.3, 0.4] }
176
+ ]
177
+ }
178
+ ```
179
+
180
+ O Core rejeita:
181
+
182
+ - dimensão diferente do manifest;
183
+ - `NaN`, infinito ou vetor de norma zero;
184
+ - fingerprint de modelo divergente;
185
+ - documento ausente, duplicado ou desconhecido;
186
+ - campos adicionais no envelope;
187
+ - quantidade de vetores diferente da quantidade de documentos.
188
+
189
+ A similaridade usada pelo adapter canônico é cosseno. Empates preservam a ordem original.
190
+
191
+ ## Opções e códigos de saída
192
+
193
+ O limite efetivo é sempre o menor entre o chamador e o manifest do plugin.
194
+
195
+ - `maxCandidates`: padrão 128; máximo 512;
196
+ - `maxInputBytes`: padrão 256 KiB; máximo 4 MiB;
197
+ - documentos que não couberem permanecem depois do prefixo reranqueado;
198
+ - o Core nunca envia parcialmente um documento;
199
+ - query ou primeiro documento que não cabem produzem
200
+ `EVIDENCE_EMBEDDING_BUDGET_EXCEEDED`.
201
+
202
+ Com `required: false` — padrão — erro de contrato, budget, resposta ou execução devolve a ordem
203
+ lexical original e `metrics.status: "fallback"`. Com `required: true`, o erro tipado é propagado.
204
+
205
+ Códigos principais:
206
+
207
+ - `EVIDENCE_EMBEDDING_PLUGIN_INVALID`;
208
+ - `EVIDENCE_EMBEDDING_BUDGET_EXCEEDED`;
209
+ - `EVIDENCE_EMBEDDING_RESPONSE_INVALID`;
210
+ - `EVIDENCE_EMBEDDING_EXECUTION_FAILED`.
211
+
212
+ ## Operação segura
213
+
214
+ 1. Mantenha `enabled: false` até validar o plugin e o hash do modelo.
215
+ 2. Execute `verifyEvidenceEmbeddingPlugin(plugin)` antes de registrar o adapter.
216
+ 3. Fixe `plugin_version`, `model_revision` e `model_fingerprint`; não use alias mutável como
217
+ `latest`.
218
+ 4. Comece com budgets pequenos e compare a ordem com o recall lexical/FTS.
219
+ 5. Registre apenas métricas — IDs, contagens, bytes e tempos — nunca query, texto ou vetores.
220
+ 6. Trate mudança de fingerprint como uma geração nova de qualquer cache pertencente ao plugin.
221
+
222
+ ## Erros comuns e diagnóstico
223
+
224
+ Quando `metrics.status` for `fallback`:
225
+
226
+ 1. desative o plugin; o recall lexical/FTS continua sendo a rota segura;
227
+ 2. valide o manifest e confira `metrics.reason`;
228
+ 3. confirme dimensão, fingerprint e quantidade dos vetores;
229
+ 4. descarte somente caches pertencentes ao plugin e reconstrua-os pela autoridade
230
+ `EVIDENCE_INDEX.jsonl`;
231
+ 5. nunca apague ou edite `EVIDENCE_INDEX.jsonl`, Markdown ou sidecars do Core para reparar um
232
+ provider de embeddings;
233
+ 6. reative com `required: false` e promova para `required: true` apenas em um ambiente que realmente
234
+ exige o provider.
235
+
236
+ ## Próximos passos
237
+
238
+ Este contrato não instala um modelo nem integra embeddings automaticamente ao MCP, doctor ou
239
+ Observer. Ele define a fronteira segura e testável para um adapter irmão futuro. O Core continua
240
+ completo e funcional sem qualquer plugin.
241
+
242
+ Use o guia de [MCP nativo](mcp.md) para a superfície paginada/lexical já exposta e o guia de
243
+ [manutenção e diagnóstico](maintenance-and-diagnostics.md) para inspecionar a saúde dos artefatos
244
+ derivados sem reconstruí-los.
@@ -63,20 +63,71 @@ O `init` gera a entrada genérica reproduzível:
63
63
  ```
64
64
 
65
65
  Reads: `wendkeep_project_status`, `wendkeep_context_status`, `wendkeep_memory_recall`,
66
- `wendkeep_memory_conflicts`, `wendkeep_change_list`, `wendkeep_change_show`,
67
- `wendkeep_change_status`, `wendkeep_spec_effective`, `wendkeep_task_show`,
68
- `wendkeep_task_evaluate`, `wendkeep_handoff_current`, `wendkeep_evidence_latest` e
69
- `wendkeep_observer_query`.
66
+ `wendkeep_evidence_recall`, `wendkeep_memory_conflicts`, `wendkeep_change_list`,
67
+ `wendkeep_change_show`, `wendkeep_change_status`, `wendkeep_spec_effective`,
68
+ `wendkeep_task_show`, `wendkeep_task_evaluate`, `wendkeep_handoff_current`,
69
+ `wendkeep_evidence_latest` e `wendkeep_observer_query`.
70
70
 
71
71
  Writes: `wendkeep_memory_assert`, `wendkeep_checkpoint_create`, `wendkeep_context_select`,
72
72
  `wendkeep_task_claim`, `wendkeep_task_complete` e `wendkeep_handoff_publish`.
73
73
 
74
+ ## Recall paginado e indexado de evidências
75
+
76
+ `wendkeep_evidence_recall` é a superfície bounded para recuperar evidências do Vault. Ela seleciona
77
+ candidatos pelo sidecar lexical persistente ou pelo SQLite/FTS5 opcional, reranqueia com o scorer
78
+ canônico e devolve uma página compacta. `wendkeep_memory_recall` permanece disponível como API
79
+ legada e não ganha silenciosamente o novo contrato.
80
+
81
+ Entrada principal:
82
+
83
+ - `project_root` e `query` são obrigatórios;
84
+ - `limit` aceita 1 a 100 resultados por página;
85
+ - `cursor` é opaco e só vale para a mesma consulta, filtros e índice lógico;
86
+ - `max_bytes` aceita 2 a 524288 e limita exatamente o JSON serializado de `results`; o padrão é
87
+ 64 KiB;
88
+ - `candidate_limit` aceita 1 a 4096 candidatos;
89
+ - `posting_budget` aceita 1 a 1048576 postings visitados;
90
+ - `backend` aceita `auto`, `sqlite` ou `lexical`;
91
+ - `filters` aceita igualdade por `authority`, `validity`, `entity_type`, `project_id`,
92
+ `change_slug`, `session_id`, `work_session_id` e `logical_path`, além de
93
+ `logical_path_prefix`. Cada filtro pode ser string ou lista de strings.
94
+
95
+ Exemplo de chamada:
96
+
97
+ ```json
98
+ {
99
+ "name": "wendkeep_evidence_recall",
100
+ "arguments": {
101
+ "project_root": "<projeto>",
102
+ "query": "contrato de autenticação",
103
+ "limit": 5,
104
+ "max_bytes": 65536,
105
+ "candidate_limit": 512,
106
+ "posting_budget": 65536,
107
+ "backend": "auto",
108
+ "filters": {
109
+ "authority": "verified",
110
+ "validity": "active",
111
+ "logical_path_prefix": "04-Decisões/"
112
+ }
113
+ }
114
+ }
115
+ ```
116
+
117
+ A resposta contém `results`, `next_cursor`, `has_more`, `as_of`, contagens e bytes da página. Cada
118
+ resultado omite `content`, informa `content_bytes`, mantém um `excerpt` bounded e substitui
119
+ `logical_path` por `logical_ref`, uma referência relativa ao Vault — nunca um caminho absoluto. O
120
+ bloco `candidates` expõe backend, quantidade, postings, rebuild e fallback. Quando o orçamento de
121
+ candidatos não cobriu todo o conjunto possível, `complete_candidate_set` é `false`; isso impede que
122
+ o consumidor interprete uma seleção truncada como exaustiva.
123
+
74
124
  ## Resultado esperado
75
125
 
76
126
  O handshake e `tools/list` retornam JSON-RPC válido. Cada tool declara effect/capability e schemas
77
127
  versionados. Reads conhecidas não entram no mutation gate, mas mantêm binding explícito de
78
- projeto/worktree, paginação por cursor, budget padrão de 1 MiB, redaction, timeout e cancelamento.
79
- Observer aparece indisponível abaixo de Node 22.13 sem impedir Core no Node 18.
128
+ projeto/worktree, paginação por cursor, budgets, redaction, timeout e cancelamento. Observer aparece
129
+ indisponível abaixo de Node 22.13 sem impedir Core no Node 18. O recall indexado também funciona no
130
+ Node 18 pelo fallback lexical; SQLite/FTS5 permanece opcional.
80
131
 
81
132
  Writes exigem `project_root`, `session_id`, `active_context_id`, `actor`, `reason`, capability exata
82
133
  e `lease.id`/`lease.expires_at`; o executor revalida a autorização causal e os gates da CLI. A
@@ -89,8 +140,16 @@ código e duração — nunca argumentos ou payload.
89
140
  - `MCP_CAPABILITY_REQUIRED` / `MCP_SCOPE_AUTH_REQUIRED`: capability ausente ou não autorizada.
90
141
  - `MCP_LEASE_EXPIRED`: obtenha autorização/lease nova; não altere timestamp manualmente.
91
142
  - `MCP_PROJECT_SCOPE_MISMATCH`: `project_root` e `worktree_root` pertencem a bindings diferentes.
92
- - `MCP_REQUEST_TOO_LARGE` / `MCP_RESPONSE_TOO_LARGE`: use `limit` e o cursor retornado.
143
+ - `MCP_REQUEST_TOO_LARGE` / `MCP_RESPONSE_TOO_LARGE`: reduza os budgets e continue pelo cursor.
93
144
  - `MCP_RUNTIME_UNSUPPORTED`: use Node 22.13+ para Observer; Core permanece disponível.
145
+ - `MCP_EVIDENCE_QUERY_REQUIRED`: informe uma consulta não vazia.
146
+ - `MCP_EVIDENCE_CURSOR_INVALID`: cursor adulterado, stale ou usado com outra consulta/filtros.
147
+ - `MCP_EVIDENCE_BUDGET_TOO_SMALL`: nem os metadados mínimos do próximo resultado cabem em
148
+ `max_bytes`.
149
+ - `MCP_EVIDENCE_BACKEND_UNAVAILABLE`: o backend SQLite foi exigido, mas FTS5 não está disponível;
150
+ use `auto` ou `lexical`.
151
+ - `MCP_EVIDENCE_ARTIFACT_UNSAFE`: um artefato derivado violou a fronteira física do Vault.
152
+ - `MCP_EVIDENCE_RECALL_INVALID`: filtro, backend ou limite fora do contrato.
94
153
 
95
154
  ## Próximos passos
96
155
 
@@ -2,7 +2,13 @@
2
2
  // UserPromptSubmit: bounded, read-only retrieval from the local evidence index.
3
3
  import { pathToFileURL } from 'node:url';
4
4
  import { readHookInput, readSessionRegistry, writeHookOutput } from './obsidian-common.mjs';
5
- import { loadEvidenceIndex, recallEvidence, renderEvidenceContext } from './evidence-recall.mjs';
5
+ import {
6
+ EVIDENCE_SEARCH_MAX_CANDIDATES,
7
+ loadEvidenceIndex,
8
+ recallEvidence,
9
+ renderEvidenceContext,
10
+ searchEvidenceCandidates,
11
+ } from './evidence-recall.mjs';
6
12
  import { sanitizeMemoryText } from './memory-schema.mjs';
7
13
  import { resolveHookOperatingProfile } from './operating-profile-runtime.mjs';
8
14
  import {
@@ -11,16 +17,44 @@ import {
11
17
  } from './active-context-handoff-evidence.mjs';
12
18
  import { isBootstrapPrompt } from '../packages/integrations/src/prompt-content.mjs';
13
19
 
20
+ function scopedRows(rows, activeContext, registry) {
21
+ return scopeEvidenceRows(rows, { activeContext, registry });
22
+ }
23
+
24
+ function indexedScopedEvidence(vaultBase, query, topK, activeContext, registry) {
25
+ const initialLimit = Math.min(
26
+ EVIDENCE_SEARCH_MAX_CANDIDATES,
27
+ Math.max(512, Number(topK || 0) * 64),
28
+ );
29
+ const first = searchEvidenceCandidates(vaultBase, query, {
30
+ candidateLimit: initialLimit,
31
+ });
32
+ let scoped = scopedRows(first.rows, activeContext, registry);
33
+ if (scoped.length >= topK || !first.has_more
34
+ || initialLimit >= EVIDENCE_SEARCH_MAX_CANDIDATES) return scoped;
35
+ const expanded = searchEvidenceCandidates(vaultBase, query, {
36
+ candidateLimit: EVIDENCE_SEARCH_MAX_CANDIDATES,
37
+ });
38
+ scoped = scopedRows(expanded.rows, activeContext, registry);
39
+ return scoped;
40
+ }
41
+
14
42
  export function buildPromptEvidenceContext(vaultBase, prompt, {
15
43
  topK = 3, maxBytes = 3072, rows = null, activeContext = null, registry = null,
16
44
  } = {}) {
17
45
  const query = sanitizeMemoryText(String(prompt || '')).trim();
18
46
  if (!query || isBootstrapPrompt(query)) return '';
19
- const evidence = rows || loadEvidenceIndex(vaultBase);
20
- const scoped = scopeEvidenceRows(evidence, {
21
- activeContext,
22
- registry: registry || readSessionRegistry(vaultBase),
23
- });
47
+ const effectiveRegistry = registry || readSessionRegistry(vaultBase);
48
+ let scoped;
49
+ if (rows) {
50
+ scoped = scopedRows(rows, activeContext, effectiveRegistry);
51
+ } else {
52
+ try {
53
+ scoped = indexedScopedEvidence(vaultBase, query, topK, activeContext, effectiveRegistry);
54
+ } catch {
55
+ scoped = scopedRows(loadEvidenceIndex(vaultBase), activeContext, effectiveRegistry);
56
+ }
57
+ }
24
58
  if (!scoped.length) return '';
25
59
  return sanitizeMemoryText(renderEvidenceContext(
26
60
  recallEvidence(scoped, query, { topK }),
@@ -53,4 +87,4 @@ if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href)
53
87
  } catch {
54
88
  writeHookOutput({});
55
89
  }
56
- }
90
+ }
@@ -1 +1,11 @@
1
1
  export * from '../packages/vault/src/evidence-recall.mjs';
2
+ export * from '../packages/vault/src/evidence-recall-page.mjs';
3
+ export * from '../packages/vault/src/evidence-search-index.mjs';
4
+ export {
5
+ EVIDENCE_INDEX_STATE_FILE,
6
+ EVIDENCE_INDEX_STATE_VERSION,
7
+ buildIncrementalEvidenceIndex,
8
+ buildIncrementalEvidenceIndex as buildEvidenceIndex,
9
+ loadEvidenceIndexState,
10
+ refreshEvidenceIndex,
11
+ } from '../packages/vault/src/evidence-index-store.mjs';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wendkeep",
3
- "version": "0.85.1",
3
+ "version": "0.87.0",
4
4
  "description": "Vault-first persistent memory for AI coding agents, with an optional profile-aware governance runtime: OFF, FLOW, GUIDE, GOVERN, or ASSURE. Local-first and agent-agnostic (Claude Code, Codex, Cursor…).",
5
5
  "type": "module",
6
6
  "workspaces": [
@@ -9,6 +9,7 @@
9
9
  "exports": {
10
10
  "./harness": "./packages/harness/src/index.mjs",
11
11
  "./vault": "./packages/vault/src/index.mjs",
12
+ "./commit": "./packages/commit/src/index.mjs",
12
13
  "./hooks/*": "./hooks/*",
13
14
  "./src/*": "./src/*",
14
15
  "./bin/*": "./bin/*",
@@ -28,8 +29,10 @@
28
29
  "bin",
29
30
  "src",
30
31
  "hooks",
32
+ ".githooks",
31
33
  "packages",
32
34
  "schema",
35
+ "scripts/validate-commit-range.mjs",
33
36
  "web/observer",
34
37
  "docs/pt-BR/commands/*.md",
35
38
  "docs/en/commands/*.md",
@@ -42,7 +45,7 @@
42
45
  },
43
46
  "scripts": {
44
47
  "precheck": "node --check src/capabilities.mjs && node --check src/host-capabilities.mjs && node --check src/task-contracts.mjs && node --check src/task-leases.mjs && node --check src/task.mjs && node --check src/change.mjs && node --check src/archive-operation-lock.mjs && node --check src/worktree.mjs && node --check src/worktree-cleanup.mjs && node --check src/provenance-gate.mjs && node --check src/provenance-sources.mjs && node --check src/receipt-ledger.mjs && node --check src/evidence-envelope.mjs && node --check src/context.mjs && node --check src/active-context-health.mjs && node --check src/active-context-runtime.mjs && node --check hooks/active-context-store.mjs && node --check hooks/change-core.mjs && node --check hooks/brain-inject.mjs && node --check hooks/change-context.mjs && node --check hooks/session-stop.mjs && node --check packages/vault/src/worktree-metadata.mjs && node --check packages/vault/src/evidence-envelope.mjs && node --check packages/vault/src/memory-handoff.mjs && node --check packages/integrations/src/capabilities.mjs && node --check packages/pi/src/index.mjs && node --check src/sync-protocol.mjs && node --check src/sync-outbox.mjs && node --check src/sync-adapters.mjs && node --check src/sync-protocol-cli.mjs && node --check packages/mcp/src/sync.mjs && node --check src/portable.mjs && node --check src/tdd.mjs && node --check src/tdd-attestation.mjs && node --check src/tdd-attestation-store.mjs",
45
- "check": "node --check scripts/release.mjs && node --check scripts/release-plan.mjs && node --check scripts/release-provenance.mjs && node --check scripts/run-scope.mjs && node --check src/release-provenance.mjs && node --check bin/wendkeep.mjs && node --check packages/cli/src/index.mjs && node --check src/mcp.mjs && node --check src/init.mjs && node --check src/doctor.mjs && node --check src/active-context-health.mjs && node --check src/project-vault.mjs && node --check src/observer-auth.mjs && node --check src/observer-privacy.mjs && node --check src/observer-snapshot.mjs && node --check src/observer-store.mjs && node --check src/observer-memory.mjs && node --check src/observer-memory-publish.mjs && node --check src/observer-sql-store.mjs && node --check src/observer-sql-migrate.mjs && node --check src/observer-sql-publish.mjs && node --check src/observer-transcript-store.mjs && node --check src/observer-server.mjs && node --check src/observer.mjs && node --check src/observer-publish.mjs && node --check src/operating-profile.mjs && node --check src/profile.mjs && node --check src/flow.mjs && node --check src/work-kind.mjs && node --check src/delivery.mjs && node --check web/observer/app.mjs && node --check hooks/observer-publish.mjs && node --check hooks/evidence-context.mjs && node --check hooks/active-context-handoff-evidence.mjs && node --check hooks/evidence-recall.mjs && node --check hooks/memory-scope.mjs && node --check hooks/operating-profile-runtime.mjs && node --check hooks/operating-profile-task-store.mjs && node --check hooks/flow-core.mjs && node --check hooks/flow-protected-policy.mjs && node --check hooks/git-snapshot.mjs && node --check hooks/vault-path-safety.mjs && node --check hooks/vault-runtime-store.mjs && node --check packages/harness/src/index.mjs && node --check packages/harness/src/flow-store.mjs && node --check packages/harness/src/operating-profile.mjs && node --check packages/harness/src/sensors-core.mjs && node --check packages/integrations/src/host-hooks.mjs && node --check packages/integrations/src/hook-envelope.mjs && node --check packages/integrations/src/prompt-content.mjs && node --check packages/integrations/src/transcript-usage.mjs && node --check packages/integrations/src/transcripts.mjs && node --check packages/integrations/src/session-identity.mjs && node --check packages/integrations/src/index.mjs && node --check packages/mcp/src/audit.mjs && node --check packages/mcp/src/cli.mjs && node --check packages/mcp/src/config.mjs && node --check packages/mcp/src/effects.mjs && node --check packages/mcp/src/executor.mjs && node --check packages/mcp/src/server.mjs && node --check packages/mcp/src/stdio.mjs && node --check packages/mcp/src/index.mjs && node --check packages/vault/src/index.mjs && node --check packages/vault/src/project-vault.mjs && node --check packages/vault/src/vault-path-safety.mjs && node --check packages/vault/src/locale.mjs && node --check packages/vault/src/memory-schema.mjs && node --check packages/vault/src/memory-mode.mjs && node --check packages/vault/src/memory-scope.mjs && node --check packages/vault/src/memory-candidate-policy.mjs && node --check packages/vault/src/evidence-recall.mjs && node --check packages/vault/src/memory-handoff.mjs && node --check packages/vault/src/memory-store.mjs && node --check packages/vault/src/validate-core.mjs && node --check packages/vault/src/validate-memory.mjs",
48
+ "check": "node --check scripts/validate-commit-range.mjs && node --check packages/commit/src/index.mjs && node --check packages/commit/src/cli.mjs && node --check packages/commit/src/git-runtime.mjs && node --check src/git-commit-hooks.mjs && node --check scripts/release.mjs && node --check scripts/release-plan.mjs && node --check scripts/release-provenance.mjs && node --check scripts/run-scope.mjs && node --check src/release-provenance.mjs && node --check bin/wendkeep.mjs && node --check packages/cli/src/index.mjs && node --check src/mcp.mjs && node --check src/init.mjs && node --check src/doctor.mjs && node --check src/active-context-health.mjs && node --check src/project-vault.mjs && node --check src/observer-auth.mjs && node --check src/observer-privacy.mjs && node --check src/observer-snapshot.mjs && node --check src/observer-store.mjs && node --check src/observer-memory.mjs && node --check src/observer-memory-publish.mjs && node --check src/observer-sql-store.mjs && node --check src/observer-sql-migrate.mjs && node --check src/observer-sql-publish.mjs && node --check src/observer-transcript-store.mjs && node --check src/observer-server.mjs && node --check src/observer.mjs && node --check src/observer-publish.mjs && node --check src/operating-profile.mjs && node --check src/profile.mjs && node --check src/flow.mjs && node --check src/work-kind.mjs && node --check src/delivery.mjs && node --check web/observer/app.mjs && node --check hooks/observer-publish.mjs && node --check hooks/evidence-context.mjs && node --check hooks/active-context-handoff-evidence.mjs && node --check hooks/evidence-recall.mjs && node --check hooks/memory-scope.mjs && node --check hooks/operating-profile-runtime.mjs && node --check hooks/operating-profile-task-store.mjs && node --check hooks/flow-core.mjs && node --check hooks/flow-protected-policy.mjs && node --check hooks/git-snapshot.mjs && node --check hooks/vault-path-safety.mjs && node --check hooks/vault-runtime-store.mjs && node --check packages/harness/src/index.mjs && node --check packages/harness/src/flow-store.mjs && node --check packages/harness/src/operating-profile.mjs && node --check packages/harness/src/sensors-core.mjs && node --check packages/integrations/src/host-hooks.mjs && node --check packages/integrations/src/hook-envelope.mjs && node --check packages/integrations/src/prompt-content.mjs && node --check packages/integrations/src/transcript-usage.mjs && node --check packages/integrations/src/transcripts.mjs && node --check packages/integrations/src/session-identity.mjs && node --check packages/integrations/src/index.mjs && node --check packages/mcp/src/audit.mjs && node --check packages/mcp/src/cli.mjs && node --check packages/mcp/src/config.mjs && node --check packages/mcp/src/effects.mjs && node --check packages/mcp/src/executor.mjs && node --check packages/mcp/src/server.mjs && node --check packages/mcp/src/stdio.mjs && node --check packages/mcp/src/index.mjs && node --check packages/vault/src/index.mjs && node --check packages/vault/src/project-vault.mjs && node --check packages/vault/src/vault-path-safety.mjs && node --check packages/vault/src/locale.mjs && node --check packages/vault/src/memory-schema.mjs && node --check packages/vault/src/memory-mode.mjs && node --check packages/vault/src/memory-scope.mjs && node --check packages/vault/src/memory-candidate-policy.mjs && node --check packages/vault/src/evidence-recall.mjs && node --check packages/vault/src/memory-handoff.mjs && node --check packages/vault/src/memory-store.mjs && node --check packages/vault/src/validate-core.mjs && node --check packages/vault/src/validate-memory.mjs",
46
49
  "test": "node --test --test-concurrency=2",
47
50
  "test:core": "node scripts/run-scope.mjs core",
48
51
  "release": "node scripts/release.mjs",