wendkeep 0.72.1 → 0.74.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 (45) hide show
  1. package/CHANGELOG.md +61 -0
  2. package/README.en.md +37 -16
  3. package/README.md +37 -16
  4. package/docs/en/commands/changes-and-verification.md +10 -5
  5. package/docs/en/commands/maintenance-and-diagnostics.md +17 -9
  6. package/docs/en/commands/memory.md +16 -1
  7. package/docs/en/commands/observer.md +8 -1
  8. package/docs/en/commands/operating-profiles.md +28 -3
  9. package/docs/pt-BR/commands/changes-and-verification.md +10 -5
  10. package/docs/pt-BR/commands/maintenance-and-diagnostics.md +12 -5
  11. package/docs/pt-BR/commands/memory.md +16 -1
  12. package/docs/pt-BR/commands/observer.md +7 -1
  13. package/docs/pt-BR/commands/operating-profiles.md +28 -3
  14. package/hooks/brain-core.mjs +2 -0
  15. package/hooks/brain-inject.mjs +6 -6
  16. package/hooks/brain-recall.mjs +5 -1
  17. package/hooks/change-context.mjs +11 -0
  18. package/hooks/change-core.mjs +53 -21
  19. package/hooks/change-warn.mjs +2 -0
  20. package/hooks/evidence-context.mjs +41 -0
  21. package/hooks/evidence-recall.mjs +1 -0
  22. package/hooks/harness-doctor.mjs +13 -5
  23. package/hooks/memory-scope.mjs +1 -0
  24. package/hooks/vault-health.mjs +2 -2
  25. package/package.json +2 -2
  26. package/packages/cli/src/index.mjs +13 -3
  27. package/packages/integrations/src/host-hooks.mjs +1 -0
  28. package/packages/vault/src/evidence-recall.mjs +343 -0
  29. package/packages/vault/src/index.mjs +2 -0
  30. package/packages/vault/src/memory-handoff.mjs +58 -3
  31. package/packages/vault/src/memory-schema.mjs +12 -2
  32. package/packages/vault/src/memory-scope.mjs +119 -0
  33. package/packages/vault/src/memory-store.mjs +86 -24
  34. package/schema/observer/004-evidence-recall.sql +25 -0
  35. package/src/change.mjs +10 -4
  36. package/src/delivery.mjs +303 -0
  37. package/src/doctor.mjs +47 -10
  38. package/src/memory.mjs +95 -2
  39. package/src/observer-sql-store.mjs +141 -5
  40. package/src/release-provenance.mjs +47 -0
  41. package/src/skills-seed.mjs +25 -9
  42. package/src/sync-defs.mjs +5 -2
  43. package/src/sync.mjs +2 -2
  44. package/src/taxonomy.mjs +4 -0
  45. package/src/work-kind.mjs +62 -0
@@ -1,4 +1,4 @@
1
- # Operating profiles and FLOW
1
+ # Operating profiles, work kind, FLOW, and delivery
2
2
 
3
3
  **English** · [Português](../../pt-BR/commands/operating-profiles.md)
4
4
 
@@ -17,6 +17,8 @@ opt-in and runs that command's own validations and gates.
17
17
  Use `profile use` for a persistent human selection and `profile route` for the harness to record
18
18
  the temporary route for the current implementation. Use `FLOW` for local, reversible
19
19
  `spec_impact:none` maintenance that fits an Execute → Validate microcontract without a change.
20
+ Use `delivery` for merge, push, tag, and publication of already-approved behavior: operational
21
+ risk needs authorization and a receipt, not a new change or spec.
20
22
 
21
23
  ## When not to use
22
24
 
@@ -55,6 +57,10 @@ npx wendkeep flow status [<id>]
55
57
  npx wendkeep flow show <id> [--session <id>]
56
58
  npx wendkeep flow finish <id> [--session <id>]
57
59
  npx wendkeep flow promote <id> [--change-slug <slug>] [--session <id>]
60
+ npx wendkeep delivery start [id] --allow <capability> [--source-change <slug>] [--source-commit <sha>]
61
+ npx wendkeep delivery status [id]
62
+ npx wendkeep delivery finish [id] [--target <ref>] [--ci-url <url>] [--version <x.y.z>] [--npm-integrity <sha512>] [--release-url <url>]
63
+ npx wendkeep delivery abandon [id] --reason <text>
58
64
  ```
59
65
 
60
66
  Every FLOW subcommand also accepts `--project <path>`, `--vault <path>`, and `--json`. When
@@ -84,7 +90,7 @@ Harness. The workspaces remain private and are not published as independent npm
84
90
  |---|---|---|
85
91
  | `OFF` | LLM-native harness | Automatic governance off; Keep Core and explicit commands available. |
86
92
  | `FLOW` | E → V | Microcontract with Git baseline, allowlist, sensors, and receipt, without a change. |
87
- | `GUIDE` | P → E → V | Compact change; policy recognized for compatible evolution. |
93
+ | `GUIDE` | P → E → V | `change new --guide`; objective, acceptance, areas, tests, and result; no automatic design/spec/ADR for `contract_impact:none`. |
88
94
  | `GOVERN` | P → R → E → V | Current a2 loop and conservative fallback. |
89
95
  | `ASSURE` | P → R → E → V → C | Governance plus confirmation and handoff. |
90
96
 
@@ -164,6 +170,14 @@ ownership to the native LLM harness.
164
170
  loser remains active and can retry with `--change-slug`. Retries idempotently resume the same
165
171
  promotion instead of creating another change.
166
172
  No FLOW command accepts `--force`.
173
+ - Work kind (`inspection`, `maintenance`, `implementation`, `delivery`, `recovery`), profile,
174
+ `contract_impact`, and `operation_risk` are independent dimensions. `delivery start` captures
175
+ repo, branch/worktree, SHA, source change, and capabilities in `.brain/runtime/deliveries/`;
176
+ it creates no `08-Changes` folder, delta, spec, or ADR.
177
+ - `delivery finish` requires a clean worktree, proves that the target contains the source commit,
178
+ and for `publish` requires CI, version, npm integrity, and GitHub Release evidence. Receipts are
179
+ append-only in `.brain/runtime/delivery-receipts.jsonl`. If code/config must change, delivery
180
+ stops with `WENDKEEP_DELIVERY_IMPLEMENTATION_REQUIRED` and work returns to implementation.
167
181
  - Exit `0` means a successful query or transition; exit `1` means a policy/red-sensor block; exit
168
182
  `2` means invalid profile, session, flow, or arguments, with no partial mutation.
169
183
 
@@ -229,13 +243,22 @@ again with an explicit destination:
229
243
  npx wendkeep flow promote $flowId --change-slug another-slug
230
244
  ```
231
245
 
246
+ Deliver an approved version without manufacturing another change:
247
+
248
+ ```bash
249
+ npx wendkeep delivery start release-0-73-0 --source-change proportional-governance --allow git:merge --allow git:push --allow publish
250
+ npx wendkeep delivery status release-0-73-0
251
+ npx wendkeep delivery finish release-0-74-0 --target v0.74.0 --ci-url <run> --version 0.74.0 --npm-integrity <sha512> --release-url <release>
252
+ ```
253
+
232
254
  ## Expected result
233
255
 
234
256
  Changing profile neither creates a new session nor interrupts the Vault. In `OFF`, memory and
235
257
  lessons are still injected and Stop still persists the session/memory lifecycle, while automatic
236
258
  router, skill gate, change context/warn/nag/guard, and plan capture are inactive. Explicit commands
237
259
  remain available and run their own contracts. A completed FLOW leaves a durable, inspectable
238
- receipt; a promoted FLOW enters the normal change lifecycle.
260
+ receipt; a promoted FLOW enters the normal change lifecycle. Completed delivery leaves a receipt
261
+ without an ADR; compact GUIDE archives its result without artificial spec/design/ADR.
239
262
 
240
263
  ## Common errors and diagnosis
241
264
 
@@ -254,6 +277,8 @@ receipt; a promoted FLOW enters the normal change lifecycle.
254
277
  retry `flow finish` or `flow promote`; the idempotent marker prevents duplication.
255
278
  - Pre-existing dirt appeared in the diff: it must match the initial fingerprint and must never be
256
279
  silently attributed to the FLOW.
280
+ - Delivery without `--allow`, with a dirty worktree, or with incomplete publish evidence: resume
281
+ the real implementation or provide the receipts; do not create a change only to publish.
257
282
 
258
283
  ## Next steps
259
284
 
@@ -25,7 +25,7 @@ Tenha o projeto inicializado, um vault saudável e `wendkeep.sensors.json` váli
25
25
  ## Sintaxe
26
26
 
27
27
  ```bash
28
- npx wendkeep change new <slug>
28
+ npx wendkeep change new <slug> [--simple|--guide]
29
29
  npx wendkeep change status [slug]
30
30
  npx wendkeep spec effective --change <slug>
31
31
  npx wendkeep sensors list
@@ -35,8 +35,10 @@ npx wendkeep change archive <slug>
35
35
 
36
36
  ## Opções e códigos de saída
37
37
 
38
- - `wendkeep change new <slug> [--simple]` cria uma change; `--simple` só pula o design, não é nem
39
- equivale a `FLOW` e preserva o lifecycle/ADR legado.
38
+ - `wendkeep change new <slug> [--simple|--guide]` cria uma change. `--simple` só pula o design,
39
+ não equivale a `FLOW` e preserva o lifecycle/ADR legado. `--guide` cria o contrato GUIDE
40
+ compacto (objetivo, aceite, áreas, testes e resultado), sem design/spec/ADR automático quando
41
+ `contract_impact:none`.
40
42
  - `change use`, `list`, `show`, `status`, `diff`, `done` e `undone` inspecionam ou atualizam o
41
43
  trabalho sem arquivar.
42
44
  - `change continue <arquivada> <nova>` abre continuação sem herdar evidência antiga.
@@ -52,6 +54,7 @@ npx wendkeep change archive <slug>
52
54
 
53
55
  ```bash
54
56
  npx wendkeep change new login-tenant
57
+ npx wendkeep change new ajuste-interno --guide
55
58
  npx wendkeep spec effective --change login-tenant
56
59
  npx wendkeep change done 1.1 --change login-tenant
57
60
  npx wendkeep verify --change login-tenant
@@ -67,8 +70,10 @@ npx wendkeep sensors add api-contracts "npm run test:contracts" --severity criti
67
70
 
68
71
  ## Resultado esperado
69
72
 
70
- A change arquivada move seu delta para o spec vivo, preserva proposta/design/tarefas/evidência e
71
- gera um ADR. O archive passa com tarefas fechadas, sensores exigidos verdes e verdict atual.
73
+ A change arquivada move seu delta para o spec vivo quando aplicável e preserva proposta,
74
+ tarefas/evidência e design quando existente. GOVERN/ASSURE geram ADR; GUIDE compacta sem impacto
75
+ de contrato não gera ADR automático. O archive só passa com tarefas fechadas, sensores exigidos
76
+ verdes e verdict atual.
72
77
 
73
78
  ## Cerca de escopo para ferramentas
74
79
 
@@ -23,7 +23,7 @@ Execute na raiz do projeto ou informe `--project`/`--vault` explicitamente.
23
23
  ## Sintaxe
24
24
 
25
25
  ```bash
26
- npx --no-install wendkeep doctor [--vault <cofre>]
26
+ npx --no-install wendkeep doctor [--vault <cofre>] [--scope all|core|runtime] [--strict]
27
27
  npx --no-install wendkeep memory curate --vault <cofre>
28
28
  npx --no-install wendkeep sync-defs [--check|--reseed] --vault <cofre> --project <raiz>
29
29
  npx --no-install wendkeep theme sync --vault <cofre>
@@ -33,7 +33,10 @@ npx --no-install wendkeep --help
33
33
 
34
34
  ## Opções e códigos de saída
35
35
 
36
- - `doctor` é read-only; exit `0` aceita warnings recuperáveis e exit não zero indica falha.
36
+ - `doctor` é read-only. Por padrão, exit não zero indica erro estrutural; `--strict` também torna
37
+ atenção de workflow, dívida reparável e memória degradada apropriadas para gate de CI/release.
38
+ - `--scope core` verifica somente instalação, identidade, sessão e memória; `sync` usa esse escopo
39
+ e não falha por change ainda em andamento. `--scope runtime` isola harness/governança.
37
40
  - O `doctor` usa saída em formato humano, com blocos `[integridade]` e `[memória]`, categorias
38
41
  amigáveis e uma próxima ação copiável. O hook `vault-health.mjs` continua sendo a superfície JSON
39
42
  para automações; nenhum dos dois aplica curadoria.
@@ -44,8 +47,9 @@ npx --no-install wendkeep --help
44
47
  event IDs e checkpoint) com outbox, ledger e SHARED; não inferem saúde só pela revision atual.
45
48
  - `revision: 0` após migração válida, sem attempt v2, é saudável. Attempt `degraded` cujos eventos
46
49
  continuam duráveis na outbox/ledger é warning recuperável.
47
- - Attempt ambíguo, event ID perdido (ausente de ledger e outbox), estado `projected` apenas na
48
- outbox ou checkpoint divergente são falhas bloqueantes.
50
+ - Conflito semântico é `degraded` e omite somente as chaves afetadas; não bloqueia o Core. Attempt
51
+ causal ambíguo, event ID perdido, ledger corrompido, boundary insegura ou checkpoint divergente
52
+ continuam sendo falhas estruturais bloqueantes.
49
53
  - Para observabilidade de sessão, `legacy`, `degraded`, `stale` e `manifest-unproven` exigem
50
54
  reconciliação ou evidência adicional. Somente `none` fresco e `complete` fresco são saudáveis:
51
55
  frontier, checkpoint, root stat e source manifest precisam concordar.
@@ -63,6 +67,8 @@ Checklist pós-atualização:
63
67
  npx --no-install wendkeep --version
64
68
  npx --no-install wendkeep sync-defs --check --vault .MeuApp-vault --project .
65
69
  npx --no-install wendkeep doctor --vault .MeuApp-vault
70
+ npx --no-install wendkeep doctor --scope core --vault .MeuApp-vault
71
+ npx --no-install wendkeep doctor --scope runtime --strict --vault .MeuApp-vault
66
72
  npx --no-install wendkeep memory status --gate --vault .MeuApp-vault
67
73
  npx --no-install wendkeep memory curate --vault .MeuApp-vault
68
74
  npx --no-install wendkeep memory candidates --active --vault .MeuApp-vault
@@ -72,7 +78,8 @@ npx --no-install wendkeep cost rebuild --session <id> --json --vault .MeuApp-vau
72
78
 
73
79
  ## Resultado esperado
74
80
 
75
- O doctor nomeia sessões, registry, links, notas, preços, derivadas e memória como saudáveis ou
81
+ O doctor separa `structural error`, `workflow attention`, `repairable debt` e `semantic ambiguity`,
82
+ e nomeia sessões, registry, links, notas, preços, derivadas e memória como saudáveis ou
76
83
  fornece um comando específico de diagnóstico/reparo. Na memória, ele distingue vazio inicial
77
84
  válido, replay pendente recuperável e lifecycle perdido/divergente. Nenhum reparo é aplicado
78
85
  implicitamente nem o conteúdo privado do erro do projector é reproduzido no relatório. Na
@@ -30,6 +30,7 @@ Informe o vault explicitamente em automações. Preserve backups e evidências a
30
30
  npx wendkeep memory status [--gate] --vault <cofre>
31
31
  npx wendkeep memory curate --vault <cofre>
32
32
  npx wendkeep memory candidates [--active] --vault <cofre>
33
+ npx wendkeep memory rescope [--apply] --vault <cofre>
33
34
  npx wendkeep memory repair --vault <cofre>
34
35
  npx wendkeep memory recover-attempt <sessão> [--apply] --vault <cofre>
35
36
  npx wendkeep memory reconcile <sessão-ambígua> --by-session <sessão-sucessora> --reason <motivo> [--apply] --vault <cofre>
@@ -51,7 +52,7 @@ npx wendkeep validate-memory --vault <cofre-v2>
51
52
  não-TTY/terminal não interativo, ele retorna exit `2` sem alterar bytes e orienta usar o fallback
52
53
  avançado `memory candidates --active`.
53
54
  - `memory candidates` é read-only e imprime JSON determinístico com somente `candidate_id`,
54
- `reason`, `status`, `memory_key` e `event_ids`; não expõe valores nem conteúdo da memória e não
55
+ `reason`, `status`, `memory_key`, escopo quando presente e `event_ids`; não expõe valores nem conteúdo da memória e não
55
56
  cria lock nem altera o bundle. `--active` omite candidates terminais (`resolved`, `rejected` e
56
57
  `superseded`). Status ausente é normalizado para `active`.
57
58
  - Em `memory candidates`, exit `0` indica inventário válido (inclusive vazio ou com conflitos),
@@ -95,6 +96,18 @@ npx wendkeep validate-memory --vault <cofre-v2>
95
96
  do attempt exato, salva backup do registry e limita a mutação ao attempt ambíguo e à sucessora.
96
97
  O replay é CORE-aware, usa cursor físico do ledger no checkpoint e não reescreve ledger, CORE ou
97
98
  notas, nem consome a outbox. Repetir a mesma decisão aplicada é idempotente.
99
+ - `memory rescope` é dry-run por padrão e lista somente IDs, chaves e escopos planejados. Com
100
+ `--apply`, anexa eventos explícitos de projeto, work session, change, branch ou worktree e mantém
101
+ os bytes históricos como prefixo do ledger. Candidates ambíguos não são migrados nem recebem
102
+ vencedor; uma repetição retorna `unchanged`.
103
+ - Registradores como `git.local-head`, `handoff.latest`, `quality.latest-*` e
104
+ `change.<slug>.status` só competem dentro do mesmo escopo. Resolução automática ainda exige o
105
+ mesmo projeto e linhagem causal; decisões, constraints e blockers incompatíveis permanecem sob
106
+ curadoria. Uma chave ambígua é omitida de SHARED sem remover CORE ou chaves independentes.
107
+ - `.brain/EVIDENCE_INDEX.jsonl` divide documentos por headings e blocos e registra arquivo,
108
+ heading, tipo, change, sessão, work session, autoridade, data, validade e hash. `/brain-recall`
109
+ e o hook `UserPromptSubmit` usam BM25, frase exata, pesos por campo, autoridade, validade,
110
+ recência limitada e diversidade para retornar o trecho do match com proveniência.
98
111
  - Toda rota de memória valida a topologia física de `.brain`, ledger, outbox, CORE, SHARED,
99
112
  candidates, registry, notas, backups, temporários e sidecars antes de ler ou escrever. Junction,
100
113
  symlink, reparse point ou hardlink falham fechados sem tocar bytes externos. Locks publicam owner
@@ -134,6 +147,8 @@ npx wendkeep validate-memory --vault <cofre-v2>
134
147
  npx wendkeep memory status --gate --vault .MeuApp-vault
135
148
  npx wendkeep memory curate --vault .MeuApp-vault
136
149
  npx wendkeep memory candidates --active --vault .MeuApp-vault
150
+ npx wendkeep memory rescope --vault .MeuApp-vault
151
+ npx wendkeep memory rescope --apply --vault .MeuApp-vault
137
152
  npx wendkeep memory recover-attempt sessao-123 --vault .MeuApp-vault
138
153
  npx wendkeep memory recover-attempt sessao-123 --apply --vault .MeuApp-vault
139
154
  npx wendkeep memory reconcile antiga --by-session atual --reason "entrega continuada" --vault .MeuApp-vault
@@ -98,6 +98,11 @@ reconciliação quando o ledger detalhado não fecha com ele; essa linha não in
98
98
  Sessões históricas com o mesmo `session_id` recebem uma identidade canônica por arquivo para
99
99
  evitar que um rollup sobrescreva o outro.
100
100
 
101
+ No schema 4, cada documento ingerido também é projetado em chunks com caminho, heading,
102
+ autoridade, data e validade. O Observer faz um feature probe de FTS5 e usa o índice quando a
103
+ extensão está disponível; caso contrário, mantém a mesma semântica por fallback lexical. A busca
104
+ retorna o trecho em que houve o match e sua proveniência, não apenas o começo do documento.
105
+
101
106
  O `init` projeta `observer-publish` para `SessionStart`, `Stop` e `SubagentStop` depois dos hooks
102
107
  principais. Sem servidor disponível, ele grava snapshots em `.brain/observer-outbox/` e eventos
103
108
  SQL em `.brain/observer-sql-outbox/`, sem bloquear a sessão; uma execução posterior tenta
@@ -140,7 +145,8 @@ corte. As telas do Observer não concluem, arquivam, reparam ou promovem estado.
140
145
  chamadas e transcripts.
141
146
  - `GET /v1/projects/:project_id/memory/tree` — árvore e metadados dos documentos.
142
147
  - `GET /v1/projects/:project_id/memory/document?path=...` — conteúdo Markdown integral.
143
- - `GET /v1/projects/:project_id/memory/search?q=...` — busca no caminho e no corpo.
148
+ - `GET /v1/projects/:project_id/memory/search?q=...` — busca ranqueada por chunks, com trecho do
149
+ match e proveniência; usa fallback lexical quando FTS5 não está disponível.
144
150
  - `GET /v1/projects/:project_id/sync` — modo, contagem, conflitos e último evento.
145
151
  - `PUT /v1/projects/:project_id/sync` — compatibilidade de configuração; a autoridade continua SQL.
146
152
  - `GET /v1/projects/:project_id/memory/export` — exportação read-only com conteúdo completo.
@@ -1,4 +1,4 @@
1
- # Perfis de Operação e FLOW
1
+ # Perfis de Operação, work kind, FLOW e delivery
2
2
 
3
3
  **PT-BR** · [English](../../en/commands/operating-profiles.md)
4
4
 
@@ -17,6 +17,8 @@ deliberado e executa as validações e gates próprios daquele comando.
17
17
  Use `profile use` para uma seleção humana persistente e `profile route` para o harness registrar a
18
18
  rota temporária da implementação atual. Use `FLOW` para manutenção local, reversível e com
19
19
  `spec_impact:none` que caiba num microcontrato Executar → Validar, sem change.
20
+ Use `delivery` para merge, push, tag e publicação de comportamento já aprovado: risco operacional
21
+ exige autorização/receipt, não uma nova change ou spec.
20
22
 
21
23
  ## Quando não usar
22
24
 
@@ -55,6 +57,10 @@ npx wendkeep flow status [<id>]
55
57
  npx wendkeep flow show <id> [--session <id>]
56
58
  npx wendkeep flow finish <id> [--session <id>]
57
59
  npx wendkeep flow promote <id> [--change-slug <slug>] [--session <id>]
60
+ npx wendkeep delivery start [id] --allow <capability> [--source-change <slug>] [--source-commit <sha>]
61
+ npx wendkeep delivery status [id]
62
+ npx wendkeep delivery finish [id] [--target <ref>] [--ci-url <url>] [--version <x.y.z>] [--npm-integrity <sha512>] [--release-url <url>]
63
+ npx wendkeep delivery abandon [id] --reason <texto>
58
64
  ```
59
65
 
60
66
  Todos os subcomandos FLOW também aceitam `--project <path>`, `--vault <path>` e `--json`.
@@ -85,7 +91,7 @@ independentes.
85
91
  |---|---|---|
86
92
  | `OFF` | harness nativo da LLM | Governança automática desligada; Keep Core e comandos explícitos disponíveis. |
87
93
  | `FLOW` | E → V | Microcontrato com baseline Git, allowlist, sensores e recibo, sem change. |
88
- | `GUIDE` | P → E → V | Change compacta; política reconhecida para evolução compatível. |
94
+ | `GUIDE` | P → E → V | `change new --guide`; objetivo, aceite, áreas, testes e resultado; sem design/spec/ADR automático quando `contract_impact:none`. |
89
95
  | `GOVERN` | P → R → E → V | Loop a2 atual e fallback conservador. |
90
96
  | `ASSURE` | P → R → E → V → C | Governança acrescida de confirmação e handoff. |
91
97
 
@@ -163,6 +169,14 @@ harness nativo da LLM.
163
169
  dono; contrato, reserva, attempts, recibo e origem permanecem semanticamente vinculados. O
164
170
  perdedor permanece ativo e pode repetir com `--change-slug`. Retries retomam idempotentemente a
165
171
  mesma promoção em vez de criar outra change. Não existe `--force` no FLOW.
172
+ - Work kind (`inspection`, `maintenance`, `implementation`, `delivery`, `recovery`), perfil,
173
+ `contract_impact` e `operation_risk` são dimensões independentes. `delivery start` captura repo,
174
+ branch/worktree, SHA, change de origem e capabilities em `.brain/runtime/deliveries/`; não cria
175
+ pasta em `08-Mudanças`, delta, spec ou ADR.
176
+ - `delivery finish` exige working tree limpa, comprova que o target contém o commit de origem e,
177
+ para capability `publish`, exige CI, versão, integridade npm e GitHub Release. O receipt é
178
+ append-only em `.brain/runtime/delivery-receipts.jsonl`. Se código/config precisar mudar, a
179
+ delivery para com `WENDKEEP_DELIVERY_IMPLEMENTATION_REQUIRED` e o trabalho volta a implementation.
166
180
  - Exit `0` indica consulta ou transição concluída; exit `1` indica política/sensor vermelho; exit
167
181
  `2` indica perfil, sessão, flow ou argumentos inválidos, sem mutação parcial.
168
182
 
@@ -228,13 +242,22 @@ novamente com um destino explícito:
228
242
  npx wendkeep flow promote $flowId --change-slug outro-slug
229
243
  ```
230
244
 
245
+ Entregar uma versão já aprovada sem fabricar outra change:
246
+
247
+ ```bash
248
+ npx wendkeep delivery start release-0-73-0 --source-change governanca-proporcional --allow git:merge --allow git:push --allow publish
249
+ npx wendkeep delivery status release-0-73-0
250
+ npx wendkeep delivery finish release-0-74-0 --target v0.74.0 --ci-url <run> --version 0.74.0 --npm-integrity <sha512> --release-url <release>
251
+ ```
252
+
231
253
  ## Resultado esperado
232
254
 
233
255
  Trocar o perfil não cria outra sessão nem interrompe o Vault. Em `OFF`, a memória e as lessons
234
256
  continuam injetadas e o Stop continua persistindo sessão/memória, mas router, skill gate,
235
257
  change context/warn/nag/guard e captura de plano automáticos ficam inativos. Os comandos explícitos
236
258
  continuam disponíveis e executam seus próprios contratos. Um FLOW concluído deixa recibo durável e
237
- consultável; um FLOW promovido passa a seguir o lifecycle normal de change.
259
+ consultável; um FLOW promovido passa a seguir o lifecycle normal de change. Uma delivery concluída
260
+ deixa receipt sem gerar ADR; GUIDE compacto arquiva o resultado sem spec/design/ADR artificiais.
238
261
 
239
262
  ## Erros comuns e diagnóstico
240
263
 
@@ -253,6 +276,8 @@ consultável; um FLOW promovido passa a seguir o lifecycle normal de change.
253
276
  repita `flow finish` ou `flow promote`; o marcador idempotente impede duplicação.
254
277
  - Sujeira anterior apareceu no diff: ela deve coincidir com o fingerprint inicial e nunca pode ser
255
278
  atribuída silenciosamente ao FLOW.
279
+ - Delivery sem `--allow`, working tree suja ou evidência de publish incompleta: retome a
280
+ implementation real ou forneça os receipts; não crie uma change apenas para publicar.
256
281
 
257
282
  ## Próximos passos
258
283
 
@@ -5,6 +5,7 @@ import { basename, join } from 'node:path';
5
5
  import { ensureDir, stripYamlQuotes, toVaultRelative } from './obsidian-common.mjs';
6
6
  import { getLocale } from './locale.mjs';
7
7
  import { sanitizeMemoryText } from './memory-schema.mjs';
8
+ import { buildEvidenceIndex } from './evidence-recall.mjs';
8
9
 
9
10
  export function brainDir(vaultBase) {
10
11
  return join(vaultBase, '.brain');
@@ -85,6 +86,7 @@ export function buildBrainIndex(vaultBase) {
85
86
  ensureDir(brainDir(vaultBase));
86
87
  const out = rows.map((r) => JSON.stringify(r)).join('\n') + (rows.length ? '\n' : '');
87
88
  writeFileSync(join(brainDir(vaultBase), 'index.jsonl'), out, 'utf8');
89
+ buildEvidenceIndex(vaultBase);
88
90
  return rows;
89
91
  }
90
92
 
@@ -29,9 +29,9 @@ function processRouter(localeId) {
29
29
  if (localeId === 'en') {
30
30
  return [
31
31
  '<wk_process>',
32
- 'Spec-driven process (mandatory for any non-trivial task): INVOKE the wk-workflow Skill BEFORE editing any file.',
33
- '1. Plan: invoke the wk-brainstorming Skill (approved design) wk-planning (task plan).',
34
- '2. Record: `wendkeep change new <slug>` and FILL proposta/design/tasks. Resolve `spec_impact`: `required` needs `specs/<capability>/spec.md` + [req:ID]; `none` needs a reason. Never leave pending/placeholders.',
32
+ 'Proportional process: INVOKE the wk-workflow Skill BEFORE editing any file.',
33
+ '1. Classify work kind independently from profile: inspection, maintenance, implementation, delivery, or recovery.',
34
+ '2. Delivery of approved code uses `wendkeep delivery start/finish` and a receipt, without a new change/spec. For implementation, use wk-brainstorming + wk-planning, declare spec_impact, then select FLOW, `wendkeep change new --guide`, or GOVERN/ASSURE according to contract impact.',
35
35
  '3. Implement: wk-tdd per task; tick `- [x]` as you finish. Something broke? wk-debugging.',
36
36
  '4. Close: `wendkeep verify` (+ `--deep` + the wk-verify Skill) → `wendkeep change archive`.',
37
37
  'NEVER `archive --force` on your own — a red gate means pending work; --force is the user\'s call, not yours. Dead end? `wendkeep change abandon`.',
@@ -40,9 +40,9 @@ function processRouter(localeId) {
40
40
  }
41
41
  return [
42
42
  '<wk_process>',
43
- 'Processo spec-driven (obrigatório em tarefa não-trivial): INVOQUE a Skill wk-workflow ANTES de editar qualquer arquivo.',
44
- '1. Planejar: invoque a Skill wk-brainstorming (design aprovado) wk-planning (plano de tarefas).',
45
- '2. Registrar: `wendkeep change new <slug>` e PREENCHA proposta/design/tarefas. Resolva `spec_impact`: `required` exige `specs/<capability>/spec.md` + [req:ID]; `none` exige justificativa. Nunca deixe pending/placeholders.',
43
+ 'Processo proporcional: INVOQUE a Skill wk-workflow ANTES de editar qualquer arquivo.',
44
+ '1. Classifique work kind independentemente do perfil: inspection, maintenance, implementation, delivery ou recovery.',
45
+ '2. Entrega de código aprovado usa `wendkeep delivery start/finish` e receipt, sem nova change/spec. Em implementation, use wk-brainstorming + wk-planning, declare spec_impact e escolha FLOW, `wendkeep change new --guide` ou GOVERN/ASSURE conforme impacto de contrato.',
46
46
  '3. Implementar: wk-tdd por tarefa; marque `- [x]` ao concluir. Quebrou algo? wk-debugging.',
47
47
  '4. Fechar: `wendkeep verify` (+ `--deep` + Skill wk-verify) → `wendkeep change archive`.',
48
48
  'PROIBIDO `archive --force` por conta própria — gate vermelho significa trabalho pendente; --force é decisão do usuário, não sua. Beco sem saída? `wendkeep change abandon`.',
@@ -4,10 +4,12 @@
4
4
  import { pathToFileURL } from 'node:url';
5
5
  import { getVaultBase } from './obsidian-common.mjs';
6
6
  import { loadIndex } from './brain-core.mjs';
7
+ import { loadEvidenceIndex, recallEvidence } from './evidence-recall.mjs';
7
8
 
8
9
  export { loadIndex };
9
10
 
10
11
  export function scoreRows(rows, query, topK = 5) {
12
+ if (rows.some((row) => row?.chunk_id)) return recallEvidence(rows, query, { topK });
11
13
  const terms = String(query).toLowerCase().split(/\s+/).filter(Boolean);
12
14
  if (!terms.length) return [];
13
15
  return rows
@@ -27,6 +29,8 @@ export function scoreRows(rows, query, topK = 5) {
27
29
 
28
30
  if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
29
31
  const vaultBase = getVaultBase();
30
- const hits = scoreRows(loadIndex(vaultBase), process.argv.slice(2).join(' '));
32
+ const query = process.argv.slice(2).join(' ');
33
+ const evidence = loadEvidenceIndex(vaultBase);
34
+ const hits = evidence.length ? recallEvidence(evidence, query, { topK: 5 }) : scoreRows(loadIndex(vaultBase), query);
31
35
  process.stdout.write(JSON.stringify(hits, null, 2) + '\n');
32
36
  }
@@ -14,6 +14,7 @@ import {
14
14
  profileSentinelId,
15
15
  resolveHookOperatingProfile,
16
16
  } from './operating-profile-runtime.mjs';
17
+ import { activeDelivery } from '../src/delivery.mjs';
17
18
 
18
19
  // Conservador de propósito: verbos de tarefa comuns (pt+en) + tamanho mínimo. Falso-negativo
19
20
  // custa só o nudge; falso-positivo em pergunta curta viraria ruído.
@@ -29,6 +30,16 @@ export function buildChangePing(vaultBase, sessionId, prompt = '', changeSlug =
29
30
  const policy = hookProfilePolicy(profile);
30
31
  if (!policy.harness) return null;
31
32
  const sentinelId = profileSentinelId(sessionId, profile);
33
+ const delivery = activeDelivery(vaultBase);
34
+ if (delivery) {
35
+ const hash = `delivery:${delivery.id}`;
36
+ if (readSentinel(vaultBase, 'ctx', sentinelId) === hash) return null;
37
+ writeSentinel(vaultBase, 'ctx', sentinelId, hash);
38
+ return {
39
+ context: `<active_delivery>Delivery ${delivery.id} ativa; capabilities: ${delivery.route.operation_risk.join(', ')}. Risco operacional autorizado sem nova change/spec.</active_delivery>`,
40
+ hash,
41
+ };
42
+ }
32
43
  const st = changeCtxState(vaultBase);
33
44
  if (st) {
34
45
  if (readSentinel(vaultBase, 'ctx', sentinelId) === st.hash) return null;
@@ -18,12 +18,15 @@ export function changeDirRel(slug, vaultBase) {
18
18
  return join(getLocale(vaultBase).folders.changes, slug);
19
19
  }
20
20
 
21
- export function renderChangeScaffold({ slug, sessionRel, dateStr, locale = 'pt-BR', simple = false }) {
21
+ export function renderChangeScaffold({ slug, sessionRel, dateStr, locale = 'pt-BR', simple = false, guide = false }) {
22
22
  const en = locale === 'en';
23
23
  const source = sessionRel ? `\n - "${wikilinkFromRel(sessionRel)}"` : ' []';
24
- const impact = simple ? 'none' : 'pending';
25
- const impactReason = simple
26
- ? (en ? 'Simple change with no product-contract impact.' : 'Mudança simples sem impacto no contrato do produto.')
24
+ const compact = simple || guide;
25
+ const impact = compact ? 'none' : 'pending';
26
+ const impactReason = compact
27
+ ? (guide
28
+ ? (en ? 'Compact GUIDE change with no product-contract impact.' : 'Change GUIDE compacta sem impacto no contrato do produto.')
29
+ : (en ? 'Simple change with no product-contract impact.' : 'Mudança simples sem impacto no contrato do produto.'))
27
30
  : '';
28
31
  const proposta = `---
29
32
  type: change
@@ -34,14 +37,18 @@ cssclasses:
34
37
  tags:
35
38
  - mudanca
36
39
  source:${source}
37
- spec_impact: ${impact}
40
+ ${guide ? 'work_kind: implementation\nprofile: GUIDE\ncontract_impact: none\n' : ''}spec_impact: ${impact}
38
41
  spec_impact_reason: ${JSON.stringify(impactReason)}
39
42
  specs: []
40
43
  ---
41
44
 
42
45
  # ${slug}
43
46
 
44
- ${en ? '## Why\n\n(reason for the change)\n\n## What changes\n\n(scope of the change)' : '## Por quê\n\n(motivo da mudança)\n\n## O que muda\n\n(escopo da mudança)'}
47
+ ${guide
48
+ ? (en
49
+ ? '## Objective\n\n(objective)\n\n## Acceptance criteria\n\n- [ ] (acceptance criterion)\n\n## Affected areas\n\n(affected areas)'
50
+ : '## Objetivo\n\n(objetivo)\n\n## Critérios de aceite\n\n- [ ] (critério de aceite)\n\n## Áreas afetadas\n\n(áreas afetadas)')
51
+ : (en ? '## Why\n\n(reason for the change)\n\n## What changes\n\n(scope of the change)' : '## Por quê\n\n(motivo da mudança)\n\n## O que muda\n\n(escopo da mudança)')}
45
52
  `;
46
53
  // Hub backlink: design/tarefas link the change's proposta so no generated artifact is a
47
54
  // graph island. Full-path (never basename — proposta/design exist in every change) so the
@@ -54,11 +61,13 @@ ${hubLink}
54
61
 
55
62
  ${en ? '## Approach\n\n(technical approach)' : '## Abordagem\n\n(abordagem técnica)'}
56
63
  `;
57
- const tarefas = `# ${slug} — ${en ? 'tasks' : 'tarefas'}
64
+ const tarefas = `# ${slug} — ${guide ? (en ? 'validation' : 'validação') : (en ? 'tasks' : 'tarefas')}
58
65
 
59
66
  ${hubLink}
60
67
 
61
- - [ ] 1.1 ${en ? '(first task)' : '(primeira tarefa)'}
68
+ ${guide
69
+ ? `${en ? '## Tests' : '## Testes'}\n\n- [ ] 1.1 ${en ? '(test or validation)' : '(teste ou validação)'}\n\n${en ? '## Result' : '## Resultado'}\n\n${en ? '(result)' : '(resultado)'}`
70
+ : `- [ ] 1.1 ${en ? '(first task)' : '(primeira tarefa)'}`}
62
71
  `;
63
72
  const reqHeading = en ? 'Requirement' : 'Requisito';
64
73
  const specDelta = `## ADDED Requirements
@@ -76,11 +85,29 @@ ${en ? '(behaviour / scenarios)' : '(comportamento / cenários)'}
76
85
  // proposta/design/tarefas still carry these was never actually planned — archiving it mints a
77
86
  // bogus ADR and pollutes _arquivo (seen in production). The archive gate blocks on them.
78
87
  const SCAFFOLD_MARKERS = [
79
- ['proposta.md', ['(motivo da mudança)', '(escopo da mudança)', '(reason for the change)', '(scope of the change)']],
88
+ ['proposta.md', [
89
+ '(motivo da mudança)', '(escopo da mudança)', '(reason for the change)', '(scope of the change)',
90
+ '(objetivo)', '(objective)', '(critério de aceite)', '(acceptance criterion)',
91
+ '(áreas afetadas)', '(affected areas)',
92
+ ]],
80
93
  ['design.md', ['(abordagem técnica)', '(technical approach)']],
81
- ['tarefas.md', ['(primeira tarefa)', '(first task)']],
94
+ ['tarefas.md', [
95
+ '(primeira tarefa)', '(first task)', '(teste ou validação)', '(test or validation)',
96
+ '(resultado)', '(result)',
97
+ ]],
82
98
  ];
83
99
 
100
+ export function isGuideCompactChange(dir) {
101
+ try {
102
+ const proposal = readFileSync(join(dir, 'proposta.md'), 'utf8');
103
+ return /^profile:\s*GUIDE\s*$/mi.test(proposal)
104
+ && /^contract_impact:\s*none\s*$/mi.test(proposal)
105
+ && /^spec_impact:\s*none\s*$/mi.test(proposal);
106
+ } catch {
107
+ return false;
108
+ }
109
+ }
110
+
84
111
  export function scaffoldPlaceholders(dir) {
85
112
  const found = [];
86
113
  for (const [file, markers] of SCAFFOLD_MARKERS) {
@@ -164,12 +191,13 @@ export function assertChangeScaffoldTargetsSafe(vaultBase, slug, {
164
191
  return { dir, rel: changeDirRel(slug, vaultBase) };
165
192
  }
166
193
 
167
- export function newChange(vaultBase, slug, { sessionRel = '', dateStr, simple = false }) {
194
+ export function newChange(vaultBase, slug, { sessionRel = '', dateStr, simple = false, guide = false }) {
195
+ const compact = simple || guide;
168
196
  const loc = getLocale(vaultBase);
169
- const { dir } = assertChangeScaffoldTargetsSafe(vaultBase, slug, { simple });
197
+ const { dir } = assertChangeScaffoldTargetsSafe(vaultBase, slug, { simple: compact });
170
198
  const existed = existsSync(join(dir, 'proposta.md'));
171
199
  mkdirVaultPath(vaultBase, dir, { label: 'destino da change' });
172
- const files = renderChangeScaffold({ slug, sessionRel, dateStr, locale: loc.id, simple });
200
+ const files = renderChangeScaffold({ slug, sessionRel, dateStr, locale: loc.id, simple: compact, guide });
173
201
  const write = (name, content) => {
174
202
  const f = join(dir, name);
175
203
  const checked = assertVaultPathSafe(vaultBase, f, {
@@ -186,7 +214,7 @@ export function newChange(vaultBase, slug, { sessionRel = '', dateStr, simple =
186
214
  // No `specs/exemplo` placeholder: it was pure noise (always hand-deleted). When a change
187
215
  // resolves `spec_impact: required`, the author writes `specs/<capability>/spec.md` directly
188
216
  // — the delta format lives in the wk-workflow skill (and `renderChangeScaffold().specDelta`).
189
- if (!simple) {
217
+ if (!compact) {
190
218
  write('design.md', files.design);
191
219
  }
192
220
  if (!existed) captureSpecBaseline(vaultBase, dir);
@@ -512,6 +540,7 @@ export function archiveChange(vaultBase, slug, { gate = gateGreen, dateStr, adrN
512
540
  const loc = getLocale(vaultBase);
513
541
  const chDir = loc.folders.changes;
514
542
  const src = join(vaultBase, chDir, slug);
543
+ const createAdr = !isGuideCompactChange(src);
515
544
  const verdict = gate(src);
516
545
  if (!verdict.ok) return { ok: false, failing: verdict.failing || [] };
517
546
 
@@ -524,14 +553,17 @@ export function archiveChange(vaultBase, slug, { gate = gateGreen, dateStr, adrN
524
553
  const adrRel = join(adrDirRel, `ADR-${num}-${slug}.md`);
525
554
 
526
555
  // Validate every later mutation target before spec promotion can change living state.
527
- const [checkedSource, checkedDestination] = assertVaultPathsSafe(vaultBase, [
556
+ const mutationTargets = [
528
557
  { path: src, allowMissing: false, expectedType: 'directory', label: 'change a arquivar' },
529
558
  { path: destAbs, expectedType: 'directory', label: 'destino da change arquivada' },
530
559
  { path: archiveRoot, expectedType: 'directory', label: 'raiz de changes arquivadas' },
531
- { path: join(vaultBase, adrDirRel), expectedType: 'directory', label: 'pasta mensal de ADR' },
532
- { path: join(vaultBase, adrRel), expectedType: 'file', label: 'ADR da change arquivada' },
533
560
  { path: join(vaultBase, POINTER), expectedType: 'file', label: 'ponteiro CURRENT_CHANGE.md' },
534
- ]);
561
+ ...(createAdr ? [
562
+ { path: join(vaultBase, adrDirRel), expectedType: 'directory', label: 'pasta mensal de ADR' },
563
+ { path: join(vaultBase, adrRel), expectedType: 'file', label: 'ADR da change arquivada' },
564
+ ] : []),
565
+ ];
566
+ const [checkedSource, checkedDestination] = assertVaultPathsSafe(vaultBase, mutationTargets);
535
567
  assertVaultPathsSafe(vaultBase, [
536
568
  { path: join(checkedSource.target, 'proposta.md'), expectedType: 'file', label: 'proposta da change' },
537
569
  { path: join(checkedSource.target, 'tarefas.md'), expectedType: 'file', label: 'tarefas da change' },
@@ -597,7 +629,7 @@ export function archiveChange(vaultBase, slug, { gate = gateGreen, dateStr, adrN
597
629
 
598
630
  // ADR goes in the same dated month folder as session-derived decisions (04-Decisões/ano/MM-MMM/)
599
631
  // — not the year root — so all ADRs sit together in the vault's convention.
600
- mkdirVaultPath(vaultBase, join(vaultBase, adrDirRel), { label: 'pasta mensal de ADR' });
632
+ if (createAdr) mkdirVaultPath(vaultBase, join(vaultBase, adrDirRel), { label: 'pasta mensal de ADR' });
601
633
  const capLine = promoted.length
602
634
  ? `\n\nCapabilities: ${promoted.map((c) => wikilinkFromRel(join(loc.folders.specs, c))).join(', ')}.`
603
635
  : '';
@@ -605,7 +637,7 @@ export function archiveChange(vaultBase, slug, { gate = gateGreen, dateStr, adrN
605
637
  // Rastro auditável (0.31.0): um archive forçado ou sem prova declarada fica marcado no ADR.
606
638
  const flagLines = `${adrFlags.forced ? '\nforced: true' : ''}${adrFlags.trivial ? '\ntrivial: true' : ''}`;
607
639
  const forcedNote = adrFlags.forced ? '\n\n> ⚠️ Arquivada com --force — havia tarefa(s) aberta(s) pulada(s) no gate.' : '';
608
- writeVaultFileSync(vaultBase, join(vaultBase, adrRel), `---
640
+ if (createAdr) writeVaultFileSync(vaultBase, join(vaultBase, adrRel), `---
609
641
  type: decision
610
642
  status: accepted
611
643
  date: ${dateStr}${flagLines}
@@ -625,7 +657,7 @@ Mudança ${changeWikilink} concluída e arquivada.${capLine}${reqLine}${forcedNo
625
657
  // Only clear the pointer when the archived change IS the active one — archiving some other
626
658
  // slug explicitly must not blank the pointer of a different, still-active change.
627
659
  if (activeChange(vaultBase) === slug) clearActiveChange(vaultBase);
628
- return { ok: true, failing: [], archivedRel: destRel, adrRel, promoted, specWarnings, linksRewritten };
660
+ return { ok: true, failing: [], archivedRel: destRel, adrRel: createAdr ? adrRel : '', promoted, specWarnings, linksRewritten };
629
661
  }
630
662
 
631
663
  // --- reescrita de wikilinks pós-move (0.35.0) ----------------------------------
@@ -12,6 +12,7 @@ import {
12
12
  profileSentinelId,
13
13
  resolveHookOperatingProfile,
14
14
  } from './operating-profile-runtime.mjs';
15
+ import { activeDelivery } from '../src/delivery.mjs';
15
16
 
16
17
  const CODE_EXT = /\.(ts|tsx|js|jsx|mjs|cjs|py|prisma|sql|go|rs|java|cs)$/i;
17
18
 
@@ -32,6 +33,7 @@ export function warnDecision(filePath, {
32
33
  if (!policy.requiresChange) return null;
33
34
  if (!filePath || !isCodeFile(filePath)) return null;
34
35
  if (activeChange(vaultBase)) return null;
36
+ if (activeDelivery(vaultBase)) return null;
35
37
  const abs = norm(isAbsolute(filePath) ? filePath : resolve(cwd, filePath));
36
38
  // Dentro do vault (NTFS é case-insensitive) ou em dirs de config de agente: não é código do projeto.
37
39
  if (abs.toLowerCase().startsWith(`${norm(resolve(vaultBase)).toLowerCase()}/`)) return null;