@orkastery/cli 0.2.0 → 0.3.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 (242) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +86 -65
  3. package/adapters/README.md +30 -15
  4. package/adapters/claude-code/.claude-plugin/plugin.json +11 -5
  5. package/adapters/claude-code/README.md +110 -8
  6. package/adapters/claude-code/commands/onboarding.md +21 -0
  7. package/adapters/claude-code/commands/ork.md +99 -27
  8. package/adapters/claude-code/hooks/hooks.json +6 -1
  9. package/adapters/claude-code/hooks/ork-sensor.js +66 -0
  10. package/adapters/codex/skills/ork/SKILL.md +57 -0
  11. package/adapters/hermes/README.md +163 -0
  12. package/adapters/hermes/bin/ork-abrir-thread.sh +2 -0
  13. package/adapters/hermes/bin/ork-brain.sh +4 -0
  14. package/adapters/hermes/bin/ork-hitl-answer.py +82 -0
  15. package/adapters/hermes/bin/ork-maestro.sh +6 -0
  16. package/adapters/hermes/bin/ork-master-enviar.py +84 -0
  17. package/adapters/hermes/bin/ork-objective-message.sh +17 -0
  18. package/adapters/hermes/bin/ork-objective-status.sh +12 -0
  19. package/adapters/hermes/bin/ork-pulse-enviar.py +47 -0
  20. package/adapters/hermes/hermes.plugin.json +26 -4
  21. package/adapters/hermes/hitl-ingress/__init__.py +356 -0
  22. package/adapters/hermes/hitl-ingress/plugin.yaml +4 -0
  23. package/adapters/hermes/skills/orkastery-devmaster/SKILL.md +75 -22
  24. package/adapters/openclaw/README.md +135 -26
  25. package/adapters/openclaw/bin/ork-brain.sh +4 -0
  26. package/adapters/openclaw/construir.sh +19 -0
  27. package/adapters/openclaw/dist/hitl-ingress.js +199 -0
  28. package/adapters/openclaw/dist/index.js +437 -0
  29. package/adapters/openclaw/openclaw.plugin.json +39 -134
  30. package/adapters/openclaw/package.json +26 -0
  31. package/adapters/openclaw/src/hitl-ingress.ts +180 -0
  32. package/adapters/openclaw/src/index.ts +458 -0
  33. package/adapters/openclaw/src/tipos-openclaw.d.ts +58 -0
  34. package/adapters/openclaw/tsconfig.json +15 -0
  35. package/assets/docs/markdownlint-cli2.jsonc +22 -0
  36. package/assets/docs/padroes/documentacao-de-produto.md +133 -0
  37. package/assets/docs/padroes/roadmap-de-produto.md +98 -0
  38. package/assets/docs/produto/README.md +14 -0
  39. package/assets/docs/produto/_modelo-feature.md +59 -0
  40. package/assets/docs/roadmap/README.md +14 -0
  41. package/assets/docs/roadmap/_modelo-item.md +73 -0
  42. package/assets/orkmind-native-schema.json +32 -0
  43. package/assets/orkmind_bridge.py +357 -0
  44. package/assets/orkmind_fixture.py +67 -0
  45. package/assets/orkmind_prospective.py +138 -0
  46. package/assets/reference-tariffs-i07.json +23 -0
  47. package/dist/adapters/claude-bg.js +488 -39
  48. package/dist/adapters/codex-controller-sensor.js +449 -0
  49. package/dist/adapters/codex-controller-worker.js +361 -0
  50. package/dist/adapters/codex-controller.js +252 -0
  51. package/dist/adapters/codex-events.js +205 -0
  52. package/dist/adapters/codex-question.js +26 -0
  53. package/dist/adapters/codex-runner.js +133 -0
  54. package/dist/adapters/codex.js +394 -0
  55. package/dist/agents-md.js +84 -0
  56. package/dist/auditoria.js +11 -8
  57. package/dist/auditrun.js +5 -4
  58. package/dist/board.js +173 -22
  59. package/dist/branch-de-estado.js +136 -0
  60. package/dist/canarios-hitl.js +177 -0
  61. package/dist/canarios-i43.js +543 -0
  62. package/dist/canarios-pulse.js +147 -0
  63. package/dist/canarios-sensores.js +129 -0
  64. package/dist/canarios.js +111 -2
  65. package/dist/catalogo.js +9 -0
  66. package/dist/ci.js +216 -0
  67. package/dist/ciclos.js +2 -1
  68. package/dist/claim-lint.js +64 -0
  69. package/dist/claims.js +60 -0
  70. package/dist/company-brain-capture.js +195 -0
  71. package/dist/company-brain-cli.js +123 -0
  72. package/dist/company-brain-client.js +61 -0
  73. package/dist/company-brain-contract.js +166 -0
  74. package/dist/company-brain-journal.js +192 -0
  75. package/dist/company-brain-mcp.js +33 -0
  76. package/dist/company-brain-migration.js +60 -0
  77. package/dist/company-brain-source.js +177 -0
  78. package/dist/company-brain-worker.js +18 -0
  79. package/dist/conducao-texto.js +61 -0
  80. package/dist/conducao.js +876 -0
  81. package/dist/contrato-publico.js +39 -0
  82. package/dist/creation-operation-store.js +251 -0
  83. package/dist/creation-operation.js +148 -0
  84. package/dist/decisao-autonoma.js +183 -0
  85. package/dist/delegation.js +79 -0
  86. package/dist/demo.js +120 -0
  87. package/dist/docs.js +828 -0
  88. package/dist/doctor.js +183 -24
  89. package/dist/entrega-pr.js +117 -0
  90. package/dist/escopo-escrita.js +71 -0
  91. package/dist/estado-thread.js +222 -0
  92. package/dist/evalrunner.js +12 -0
  93. package/dist/fabrica-estado.js +329 -0
  94. package/dist/fabrica-publicar.js +76 -0
  95. package/dist/fix.js +21 -0
  96. package/dist/gates.js +55 -9
  97. package/dist/handoff.js +39 -23
  98. package/dist/hitl-canais.js +333 -0
  99. package/dist/hitl-classificacao.js +131 -0
  100. package/dist/hitl-contract.js +465 -0
  101. package/dist/hitl-estado.js +136 -0
  102. package/dist/hitl-gates.js +554 -0
  103. package/dist/hitl-ingress-receipt.js +382 -0
  104. package/dist/hitl-local-atestado.js +57 -0
  105. package/dist/hitl-local-receipt.js +328 -0
  106. package/dist/hitl-local.js +143 -0
  107. package/dist/hitl-lock.js +139 -0
  108. package/dist/hitl-lote.js +223 -0
  109. package/dist/hitl-native-offer.js +97 -0
  110. package/dist/hitl-native.js +65 -0
  111. package/dist/hitl-presentation.js +209 -0
  112. package/dist/hitl-public-receipt.js +176 -0
  113. package/dist/hitl-resumo.js +209 -0
  114. package/dist/hitl-sessions.js +475 -0
  115. package/dist/hitl.js +711 -0
  116. package/dist/horario.js +269 -0
  117. package/dist/hosts.js +198 -22
  118. package/dist/index.js +1736 -93
  119. package/dist/indice.js +99 -0
  120. package/dist/init.js +28 -3
  121. package/dist/integracoes-locais.js +17 -0
  122. package/dist/leases.js +65 -21
  123. package/dist/ledger-stats.js +272 -0
  124. package/dist/ledger.js +107 -2
  125. package/dist/licoes.js +215 -0
  126. package/dist/liveness.js +218 -0
  127. package/dist/maestro-actions.js +51 -0
  128. package/dist/maestro-authority.js +152 -0
  129. package/dist/maestro-cli.js +97 -0
  130. package/dist/maestro-contract.js +55 -0
  131. package/dist/maestro-discovery.js +132 -0
  132. package/dist/maestro-runtime.js +268 -0
  133. package/dist/maestro-snapshot.js +86 -0
  134. package/dist/maestro-sources.js +224 -0
  135. package/dist/manifest.js +165 -6
  136. package/dist/maquina.js +102 -0
  137. package/dist/master-audit.js +101 -0
  138. package/dist/master-batch.js +43 -0
  139. package/dist/master-digest.js +149 -0
  140. package/dist/master-migracao.js +155 -0
  141. package/dist/master.js +361 -77
  142. package/dist/mcp-artifacts.js +234 -0
  143. package/dist/mcp-git.js +433 -0
  144. package/dist/mcp-install.js +310 -0
  145. package/dist/mcp-maestro.js +25 -0
  146. package/dist/mcp-server.js +469 -0
  147. package/dist/mcp-ship.js +436 -0
  148. package/dist/mcp-verify.js +173 -0
  149. package/dist/memoria-humana.js +207 -0
  150. package/dist/memoria.js +314 -78
  151. package/dist/memory-migration.js +279 -0
  152. package/dist/memory-prospective.js +148 -0
  153. package/dist/modos-migracao.js +191 -0
  154. package/dist/modos.js +151 -15
  155. package/dist/monitor-lock.js +110 -0
  156. package/dist/objective.js +449 -0
  157. package/dist/ocupacao.js +267 -0
  158. package/dist/onboarding.js +303 -0
  159. package/dist/orkmind.js +389 -90
  160. package/dist/orquestracao.js +96 -69
  161. package/dist/phase.js +596 -150
  162. package/dist/playbook-capabilities.js +150 -0
  163. package/dist/playbook-contracts.js +188 -0
  164. package/dist/portfolio-context.js +61 -0
  165. package/dist/portfolio.js +180 -0
  166. package/dist/preflight.js +207 -0
  167. package/dist/process-audit.js +112 -0
  168. package/dist/project-state.js +93 -0
  169. package/dist/prompts.js +25 -5
  170. package/dist/prova-minima.js +112 -0
  171. package/dist/pulse-cadencia.js +163 -0
  172. package/dist/pulse-consentimento.js +260 -0
  173. package/dist/pulse-delivery.js +323 -0
  174. package/dist/pulse-resposta.js +542 -0
  175. package/dist/pulse.js +262 -0
  176. package/dist/ratelimit.js +35 -2
  177. package/dist/recall.js +80 -3
  178. package/dist/redacao-saida.js +45 -0
  179. package/dist/redacao-url.js +66 -0
  180. package/dist/retry.js +637 -115
  181. package/dist/roadmap-reservas.js +243 -0
  182. package/dist/runtime-ambiente.js +38 -0
  183. package/dist/runtime-context.js +215 -0
  184. package/dist/runtime-profiles.js +869 -0
  185. package/dist/runtimes.js +103 -0
  186. package/dist/sandbox.js +9 -0
  187. package/dist/session-events.js +203 -0
  188. package/dist/session-watcher-claude.js +637 -0
  189. package/dist/session-watcher.js +683 -0
  190. package/dist/sessoes-adopt.js +154 -0
  191. package/dist/sessoes-inventario.js +159 -0
  192. package/dist/sessoes.js +16 -35
  193. package/dist/setup.js +691 -0
  194. package/dist/ship.js +150 -15
  195. package/dist/slug.js +1 -1
  196. package/dist/thread-close.js +115 -0
  197. package/dist/thread.js +142 -28
  198. package/dist/tokens.js +1 -1
  199. package/dist/util.js +4 -2
  200. package/dist/verify-sandbox.js +265 -0
  201. package/dist/verify.js +270 -25
  202. package/dist/versao.js +60 -0
  203. package/dist/worktree.js +31 -2
  204. package/dist/write-activation.js +291 -0
  205. package/dist/yaml.js +2 -0
  206. package/eval/casos/onboarding.json +102 -0
  207. package/eval/casos/orkastery-bootstrap.json +35 -1
  208. package/eval/casos/scope-check-capability-map.json +45 -7
  209. package/eval/casos/ship-release.json +2 -2
  210. package/eval/fixtures/b0-slug-e-modos/caso.json +35 -22
  211. package/eval/fixtures/b2-master-log/caso.json +1 -1
  212. package/eval/fixtures/fx-adapter-editado-detectado/caso.json +19 -0
  213. package/eval/fixtures/fx-auto-quiet/caso.json +11 -0
  214. package/eval/fixtures/fx-blanket-approve/caso.json +10 -0
  215. package/eval/fixtures/fx-check-runtime-cruzado/caso.json +20 -0
  216. package/eval/fixtures/fx-codex-dry/caso.json +18 -0
  217. package/eval/fixtures/fx-donewhen-executavel/caso.json +15 -0
  218. package/eval/fixtures/fx-estado-dividido/caso.json +15 -0
  219. package/eval/fixtures/fx-fase-orfa/caso.json +116 -0
  220. package/eval/fixtures/fx-happy/caso.json +6 -4
  221. package/eval/fixtures/fx-hitl-latency/caso.json +20 -0
  222. package/eval/fixtures/fx-indice-reversao/caso.json +25 -0
  223. package/eval/fixtures/fx-listagem-abertas/caso.json +16 -0
  224. package/eval/fixtures/fx-maestro-bootstrap/caso.json +21 -0
  225. package/eval/fixtures/fx-modo-aposentado-escritor/caso.json +21 -0
  226. package/eval/fixtures/fx-modo-aposentado-leitor/caso.json +16 -0
  227. package/eval/fixtures/fx-objective-oscillation/caso.json +14 -0
  228. package/eval/fixtures/fx-omnicanal/caso.json +17 -0
  229. package/eval/fixtures/fx-sensores-runtime/caso.json +17 -0
  230. package/monitor/company-brain.cjs +17 -0
  231. package/monitor/pulse-scope.cjs +45 -0
  232. package/monitor/pulse.cron +18 -0
  233. package/monitor/varredura-pulse.sh +27 -0
  234. package/package.json +25 -4
  235. package/schemas/claims.schema.json +25 -0
  236. package/schemas/company-brain.schema.json +1158 -0
  237. package/schemas/creation-operation.schema.json +365 -0
  238. package/schemas/maestro-snapshot.schema.json +2716 -0
  239. package/skills/core/onboarding/SKILL.md +50 -0
  240. package/skills/core/orkastery-bootstrap/SKILL.md +95 -65
  241. package/skills/core/thread-state/SKILL.md +3 -1
  242. package/skills/governance/scope-check-capability-map/SKILL.md +17 -7
package/dist/master.js CHANGED
@@ -11,9 +11,9 @@
11
11
  * contrato e nao mudam. "Uma entrega sem MASTER log nao aconteceu."
12
12
  *
13
13
  * O score e humano, de 0 a 5, com JUSTIFICATIVA OBRIGATORIA: o `ork` recusa score sem
14
- * justificativa, em qualquer modo. Nos modos que nao pausam no MASTER (`#Ork`,
14
+ * justificativa, em qualquer modo. Nos modos que nao pausam no MASTER (`#Classic`,
15
15
  * `#Maestro`, `#Auto`) o score nao desaparece: a thread cai na fila de batch scoring,
16
- * que `ork master --batch` lista para o humano pontuar em bloco.
16
+ * que `ork master` lista com o indice ja derivado do ledger (I-43: a fila saiu).
17
17
  */
18
18
  var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
19
19
  if (k2 === undefined) k2 = k;
@@ -49,28 +49,45 @@ var __importStar = (this && this.__importStar) || (function () {
49
49
  };
50
50
  })();
51
51
  Object.defineProperty(exports, "__esModule", { value: true });
52
- exports.ORDEM_DAS_CLASSES = exports.CLASSES_DE_FALHA = exports.VERSAO_MASTER_LOG = exports.CONTRATO_MASTER_LOG = void 0;
52
+ exports.AUTOR_DA_OMISSAO = exports.CONTRATO_MASTER_PENDENTE = exports.ORDEM_DAS_CLASSES = exports.CLASSES_DE_FALHA = exports.VERSAO_MASTER_LOG = exports.CONTRATO_MASTER_LOG = void 0;
53
53
  exports.parseClasse = parseClasse;
54
54
  exports.caminhoPostmortem = caminhoPostmortem;
55
55
  exports.caminhoMasterLog = caminhoMasterLog;
56
56
  exports.fasesPercorridas = fasesPercorridas;
57
57
  exports.regimeDoScore = regimeDoScore;
58
58
  exports.entregou = entregou;
59
+ exports.indiceDaThread = indiceDaThread;
59
60
  exports.exigirScoreValido = exigirScoreValido;
61
+ exports.autoriaHumana = autoriaHumana;
62
+ exports.exigirAutoriaHumana = exigirAutoriaHumana;
63
+ exports.masterRatificado = masterRatificado;
64
+ exports.preflightMaster = preflightMaster;
60
65
  exports.registrarMaster = registrarMaster;
66
+ exports.proporMaster = proporMaster;
61
67
  exports.validarMasterLog = validarMasterLog;
68
+ exports.validarMasterPendente = validarMasterPendente;
62
69
  exports.lerMasterLog = lerMasterLog;
70
+ exports.aceitarPorOmissao = aceitarPorOmissao;
71
+ exports.aceitosPorOmissao = aceitosPorOmissao;
63
72
  exports.pendentesDeScore = pendentesDeScore;
64
- exports.tabelaDeBatch = tabelaDeBatch;
73
+ exports.tabelaDeEntregas = tabelaDeEntregas;
74
+ exports.aceitarPendentesPorOmissao = aceitarPendentesPorOmissao;
65
75
  exports.textoDoMaster = textoDoMaster;
66
76
  exports.tabelaDeClasses = tabelaDeClasses;
67
77
  const path = __importStar(require("node:path"));
78
+ const node_crypto_1 = require("node:crypto");
79
+ const thread_close_1 = require("./thread-close");
80
+ const estado_thread_1 = require("./estado-thread");
68
81
  const ledger_1 = require("./ledger");
69
82
  const modos_1 = require("./modos");
70
83
  const thread_1 = require("./thread");
71
84
  const types_1 = require("./types");
72
85
  const util_1 = require("./util");
73
86
  const fs = __importStar(require("node:fs"));
87
+ const horario_1 = require("./horario");
88
+ const indice_1 = require("./indice");
89
+ const ship_1 = require("./ship");
90
+ const fabrica_publicar_1 = require("./fabrica-publicar");
74
91
  /** Identificador do contrato congelado do MASTER log. */
75
92
  exports.CONTRATO_MASTER_LOG = 'ork.master-log/v1';
76
93
  /** Versao do contrato. Uma mudanca de contrato exige uma versao nova, nao um campo novo. */
@@ -151,11 +168,48 @@ function fasesPercorridas(raiz, id) {
151
168
  }
152
169
  /** Regime do score: `pausa` nos modos que param no MASTER, `batch` nos demais. */
153
170
  function regimeDoScore(thread) {
171
+ // Ciclo sem MASTER (o `#Fast`, I-42) nao pausa no MASTER: o score, quando vier, e de lote.
172
+ // Sem esta guarda, uma thread #Fast entregue derrubava `ork master`, o aceite por omissao
173
+ // e o pulse, que listam as pendentes de score (27/09/2026).
174
+ if (!thread.blocos?.some((b) => b.fases.includes('MASTER')))
175
+ return 'batch';
154
176
  return (0, thread_1.pausaNaThread)(thread, 'MASTER') ? 'pausa' : 'batch';
155
177
  }
156
178
  /** A thread ja entregou (o ledger tem `ship_done`)? */
157
179
  function entregou(raiz, id) {
158
- return (0, ledger_1.lerLedger)((0, thread_1.dirThread)(raiz, id)).some((e) => e.tipo === ledger_1.TIPOS_DE_EVENTO.shipConcluido);
180
+ return (0, thread_close_1.provaDeEntrega)(raiz, id) !== null;
181
+ }
182
+ /**
183
+ * Pergunta ao git se a entrega desta thread foi desfeita, e grava se foi. Nunca lanca.
184
+ *
185
+ * Idempotente por `revertSha` (`registrarReversaoDaEntrega`), entao pode rodar em toda
186
+ * consulta: a mesma reversao nao rebaixa a thread duas vezes. Git indisponivel nao
187
+ * derruba o MASTER; no pior caso o indice continua sendo o que o ledger ja sabia.
188
+ */
189
+ function sincronizarReversao(raiz, id) {
190
+ try {
191
+ (0, ship_1.registrarReversaoDaEntrega)(raiz, (0, thread_1.lerThread)(raiz, id));
192
+ }
193
+ catch { /* git indisponivel nao barra o MASTER */ }
194
+ }
195
+ /**
196
+ * O indice da thread, DEPOIS de perguntar ao git se a entrega ainda esta de pe.
197
+ *
198
+ * ESTE E O PONTO UNICO por onde o MASTER calcula indice, e ele existe por causa do que
199
+ * o CHECK de 20/09/2026 provou com `git revert` real: o unico escritor de
200
+ * `rollback_done` rodava no COMECO de um `ork ship` SEGUINTE da mesma thread, e depois
201
+ * do MASTER nao ha ship seguinte. Uma entrega desfeita na base saia daqui como 5 de 5
202
+ * "sem tropeco", e `ork master --aceitar-omissao` gravava score 5 com a justificativa
203
+ * "sem reversao" sobre ela. Em 20 das 27 threads entregues do projeto a janela do ship
204
+ * seguinte nunca chegou a abrir.
205
+ *
206
+ * A regra que ficou: quem AFIRMA o numero e quem tem de conferir o fato. Por isso a
207
+ * deteccao roda no momento em que o indice e calculado e no momento em que a omissao e
208
+ * aceita, e nao so num ship futuro que quase nunca acontece.
209
+ */
210
+ function indiceDaThread(raiz, id) {
211
+ sincronizarReversao(raiz, id);
212
+ return (0, indice_1.calcularIndice)((0, ledger_1.lerLedger)((0, thread_1.dirThread)(raiz, id)));
159
213
  }
160
214
  /**
161
215
  * Valida o score humano ANTES de gravar qualquer coisa.
@@ -176,13 +230,17 @@ function exigirScoreValido(score, justificativa) {
176
230
  * Registra o MASTER da thread: POSTMORTEM tipado, MASTER log no contrato e o score.
177
231
  * Ao fim, a thread fecha (`status: fechada`) e o ledger ganha `master_done`.
178
232
  */
179
- function registrarMaster(raiz, id, opcoes) {
233
+ function prepararDocumentos(raiz, id, opcoes) {
180
234
  const thread = (0, thread_1.lerThread)(raiz, id);
181
235
  exigirScoreValido(opcoes.score, opcoes.justificativa);
182
236
  if (thread.score && !opcoes.refazer) {
183
237
  throw new Error(`a thread ${id} ja tem score ${thread.score.valor}/5 dado por ${thread.score.avaliadoPor} ` +
184
- `em ${thread.score.avaliadoEm}; use --refazer para regravar o MASTER`);
238
+ `em ${(0, horario_1.formatarDataHoraRotulada)(thread.score.avaliadoEm)}; use --refazer para regravar o MASTER`);
185
239
  }
240
+ (0, thread_close_1.exigirEntrega)(raiz, id);
241
+ // A1: o indice gravado ao lado do score sai do ledger, e o ledger so sabe da reversao
242
+ // se alguem perguntar ao git. Aqui e o momento em que o numero e congelado.
243
+ sincronizarReversao(raiz, id);
186
244
  const eventos = (0, ledger_1.lerLedger)((0, thread_1.dirThread)(raiz, id));
187
245
  const gatesBloqueados = eventos
188
246
  .filter((e) => e.tipo === ledger_1.TIPOS_DE_EVENTO.gateBloqueado)
@@ -211,12 +269,17 @@ function registrarMaster(raiz, id, opcoes) {
211
269
  'informada: o `ork` gravou "outra". Corrija com --classe <classe> --refazer.'
212
270
  : 'nenhuma --classe informada e nenhum gate reprovou: o `ork` gravou "sem-falha".');
213
271
  }
272
+ // I-43 (D3): o indice e DERIVADO do ledger no momento do registro, e acompanha o
273
+ // score como o que a maquina achava antes de o dono falar. Quando as duas existem,
274
+ // a nota humana e a que vale; o indice fica ao lado dela, nao no lugar.
275
+ const indice = (0, indice_1.calcularIndice)(eventos);
214
276
  const score = {
215
277
  valor: opcoes.score,
216
278
  justificativa: opcoes.justificativa.trim(),
217
- avaliadoPor: (opcoes.por ?? 'humano').trim() || 'humano',
279
+ avaliadoPor: opcoes.por?.trim() ?? '',
218
280
  avaliadoEm: (0, util_1.agora)(),
219
- regime: regimeDoScore(thread),
281
+ regime: opcoes.regime ?? regimeDoScore(thread),
282
+ indice: indice.valor,
220
283
  };
221
284
  const percorridas = fasesPercorridas(raiz, id);
222
285
  const resumo = opcoes.resumo?.trim() ||
@@ -257,6 +320,12 @@ function registrarMaster(raiz, id, opcoes) {
257
320
  avaliadoEm: score.avaliadoEm,
258
321
  classesDeFalha: classes,
259
322
  resumo,
323
+ regime: score.regime,
324
+ indice: {
325
+ valor: indice.valor,
326
+ base: indice.base,
327
+ parcelas: indice.parcelas.map((p) => ({ evento: p.evento, ocorrencias: p.ocorrencias, desconto: p.desconto })),
328
+ },
260
329
  base: thread.base,
261
330
  worktree: thread.worktree,
262
331
  evidencia: {
@@ -267,72 +336,140 @@ function registrarMaster(raiz, id, opcoes) {
267
336
  claims: thread.claims.length,
268
337
  },
269
338
  };
270
- const invalido = validarMasterLog(masterLog);
271
- if (invalido.length > 0) {
272
- throw new Error(`MASTER log fora do contrato congelado:\n - ${invalido.join('\n - ')}`);
273
- }
274
- const caminhoP = caminhoPostmortem(raiz, id);
275
- const caminhoM = caminhoMasterLog(raiz, id);
276
- (0, util_1.gravarJson)(caminhoP, postmortem);
277
- (0, util_1.gravarJson)(caminhoM, masterLog);
278
- thread.score = score;
279
- thread.faseAtual = 'MASTER';
339
+ if (classes.some(c => !exports.ORDEM_DAS_CLASSES.includes(c)))
340
+ throw new Error('classe fora do catálogo fixo');
341
+ return { thread, postmortem, masterLog, caminhoPostmortem: caminhoPostmortem(raiz, id),
342
+ caminhoMasterLog: caminhoMasterLog(raiz, id), classesInferidas, avisos };
343
+ }
344
+ /** Identidade declarada explicitamente. Não é autenticação de host. */
345
+ function autoriaHumana(por) {
346
+ const genericos = ['humano', 'humana', 'operador', 'usuario', 'user', 'anonimo', 'ninguem', 'host', 'admin', 'root', 'equipe', 'time'];
347
+ return typeof por === 'string' && por.trim().length >= 2 && !por.trim().startsWith('-') &&
348
+ !genericos.includes(semAcento(por.trim().toLowerCase())) &&
349
+ !/(?:^|[^a-z0-9])(codex|claude|gpt(?:[0-9-]*)?|openai|agente?|agent|runtime|auto|ia|llm|bot|pendente|pending|batch)(?:$|[^a-z0-9])/i.test(semAcento(por));
350
+ }
351
+ function exigirAutoriaHumana(por) {
352
+ if (!autoriaHumana(por))
353
+ throw new Error('ratificação exige --por humano explícito; agente ou autoria pendente não pode pontuar');
354
+ }
355
+ function masterRatificado(raiz, id) {
356
+ const t = (0, thread_1.lerThread)(raiz, id);
357
+ if (!t.score || !autoriaHumana(t.score.avaliadoPor) || t.fechamentoAdmin)
358
+ return false;
359
+ const e = [...(0, ledger_1.lerLedger)((0, thread_1.dirThread)(raiz, id))].reverse().find(e => e.tipo === ledger_1.TIPOS_DE_EVENTO.masterConcluido);
360
+ return !!e && e.por === t.score.avaliadoPor && e.score === t.score.valor && e.justificativa === t.score.justificativa;
361
+ }
362
+ /** Preflight reutilizado pelo lote, sem escrita. */
363
+ function preflightMaster(raiz, id, opcoes) {
364
+ // Mantém erros de valor e duplicação anteriores ao erro de autoria.
365
+ const r = prepararDocumentos(raiz, id, opcoes);
366
+ exigirAutoriaHumana(opcoes.por);
367
+ const erros = validarMasterLog(r.masterLog);
368
+ if (erros.length)
369
+ throw new Error(erros.join('; '));
370
+ return r;
371
+ }
372
+ function registrarMaster(raiz, id, opcoes) {
373
+ const r = preflightMaster(raiz, id, opcoes);
374
+ const { thread, postmortem, masterLog } = r;
375
+ (0, util_1.gravarJson)(r.caminhoPostmortem, postmortem);
376
+ (0, util_1.gravarJson)(r.caminhoMasterLog, masterLog);
377
+ thread.score = postmortem.score;
378
+ thread.score_proposto = null;
379
+ // I-42: ciclo sem MASTER (o `#Fast`) fecha sem trocar de fase; `faseAtual` fica dentro do ciclo.
380
+ if (!thread.fases?.length || thread.fases.includes('MASTER'))
381
+ thread.faseAtual = 'MASTER';
280
382
  thread.status = 'fechada';
281
383
  (0, thread_1.gravarThread)(raiz, thread);
384
+ (0, fabrica_publicar_1.publicarEmSegundoPlano)(raiz);
282
385
  (0, ledger_1.registrar)((0, thread_1.dirThread)(raiz, id), id, ledger_1.TIPOS_DE_EVENTO.postmortemGravado, {
283
- fase: 'MASTER',
284
- classesDeFalha: classes,
285
- classesInferidas,
286
- gatesBloqueados: gatesBloqueados.length,
287
- arquivo: path.relative(raiz, caminhoP),
386
+ fase: 'MASTER', classesDeFalha: postmortem.classesDeFalha, classesInferidas: r.classesInferidas,
387
+ gatesBloqueados: postmortem.gatesBloqueados.length, arquivo: path.relative((0, estado_thread_1.raizDoEstado)(raiz), r.caminhoPostmortem),
288
388
  });
289
389
  (0, ledger_1.registrar)((0, thread_1.dirThread)(raiz, id), id, ledger_1.TIPOS_DE_EVENTO.masterConcluido, {
290
- fase: 'MASTER',
291
- modo: thread.modo,
292
- tag: (0, modos_1.tagDoModo)(thread.modo),
293
- score: score.valor,
294
- justificativa: score.justificativa,
295
- autorizadoPor: score.avaliadoPor,
296
- regime: score.regime,
297
- contrato: exports.CONTRATO_MASTER_LOG,
298
- arquivo: path.relative(raiz, caminhoM),
299
- estado: 'thread fechada',
390
+ fase: 'MASTER', modo: thread.modo, tag: (0, modos_1.tagDoModo)(thread.modo), score: masterLog.score,
391
+ justificativa: masterLog.justificativa, por: masterLog.avaliadoPor, autorizadoPor: masterLog.avaliadoPor,
392
+ classesDeFalha: masterLog.classesDeFalha, regime: postmortem.score.regime,
393
+ contrato: exports.CONTRATO_MASTER_LOG, arquivo: path.relative((0, estado_thread_1.raizDoEstado)(raiz), r.caminhoMasterLog), estado: 'thread fechada',
394
+ masterLogSha256: hashDocumento(r.caminhoMasterLog), postmortemSha256: hashDocumento(r.caminhoPostmortem),
300
395
  });
301
- return {
302
- thread,
303
- postmortem,
304
- masterLog,
305
- caminhoPostmortem: caminhoP,
306
- caminhoMasterLog: caminhoM,
307
- classesInferidas,
308
- avisos,
309
- };
396
+ return r;
397
+ }
398
+ exports.CONTRATO_MASTER_PENDENTE = 'ork.master-pending/v1';
399
+ function proporMaster(raiz, id, opcoes) {
400
+ if (!opcoes.por?.trim())
401
+ throw new Error('proposta exige autoria explícita');
402
+ if ((0, thread_1.lerThread)(raiz, id).score)
403
+ throw new Error('thread já pontuada; proposta não sobrescreve score');
404
+ const r = prepararDocumentos(raiz, id, opcoes);
405
+ const proposta = { valor: opcoes.score, justificativa: opcoes.justificativa.trim(),
406
+ classes: r.postmortem.classesDeFalha, propostoPor: opcoes.por.trim(), propostoEm: (0, util_1.agora)(), resumo: r.postmortem.resumo };
407
+ // O contrato pendente não contém avaliadoPor nem avaliadoEm.
408
+ const { avaliadoPor: _por, avaliadoEm: _em, ...base } = r.masterLog;
409
+ const log = { ...base, contrato: exports.CONTRATO_MASTER_PENDENTE, score: null,
410
+ estado: 'ratificacao-pendente', score_proposto: proposta };
411
+ const post = { ...r.postmortem, score: null, score_proposto: proposta };
412
+ (0, util_1.gravarJson)(r.caminhoPostmortem, post);
413
+ (0, util_1.gravarJson)(r.caminhoMasterLog, log);
414
+ r.thread.score_proposto = proposta;
415
+ if (!r.thread.fases?.length || r.thread.fases.includes('MASTER'))
416
+ r.thread.faseAtual = 'MASTER';
417
+ r.thread.status = 'aberta';
418
+ (0, thread_1.gravarThread)(raiz, r.thread);
419
+ (0, ledger_1.registrar)((0, thread_1.dirThread)(raiz, id), id, ledger_1.TIPOS_DE_EVENTO.scoreProposto, { fase: 'MASTER', ...proposta, arquivo: path.relative((0, estado_thread_1.raizDoEstado)(raiz), r.caminhoMasterLog) });
420
+ return log;
310
421
  }
311
422
  /**
312
423
  * Valida um MASTER log contra o contrato congelado. Devolve a lista de erros (vazia = valido).
313
424
  * E o mesmo validador que a suite roda: o contrato e executavel, nao prosa.
314
425
  */
315
426
  function validarMasterLog(bruto) {
316
- const erros = [];
427
+ const erros = validarBaseMaster(bruto);
317
428
  if (!bruto || typeof bruto !== 'object')
318
429
  return ['o MASTER log nao e um objeto'];
319
430
  const log = bruto;
320
431
  if (log.contrato !== exports.CONTRATO_MASTER_LOG) {
321
432
  erros.push(`campo "contrato" deve ser "${exports.CONTRATO_MASTER_LOG}"`);
322
433
  }
323
- if (log.versao !== exports.VERSAO_MASTER_LOG)
324
- erros.push(`campo "versao" deve ser ${exports.VERSAO_MASTER_LOG}`);
325
- for (const campo of ['thread', 'slug', 'modo', 'tag', 'justificativa', 'resumo', 'avaliadoPor']) {
326
- const v = log[campo];
327
- if (typeof v !== 'string' || v.trim() === '')
328
- erros.push(`campo "${campo}" ausente ou vazio`);
329
- }
330
434
  if (typeof log.score !== 'number' || !Number.isInteger(log.score) || log.score < 0 || log.score > 5) {
331
435
  erros.push('campo "score" deve ser um inteiro de 0 a 5');
332
436
  }
333
437
  if (typeof log.avaliadoEm !== 'string' || Number.isNaN(Date.parse(log.avaliadoEm))) {
334
438
  erros.push('campo "avaliadoEm" deve ser um carimbo ISO valido');
335
439
  }
440
+ if (!autoriaHumana(log.avaliadoPor))
441
+ erros.push('avaliadoPor precisa de autoria humana explícita');
442
+ return erros;
443
+ }
444
+ /** Valida a proposta sem convertê-la em avaliação humana. */
445
+ function validarMasterPendente(bruto) {
446
+ const erros = validarBaseMaster(bruto);
447
+ if (!bruto || typeof bruto !== 'object')
448
+ return erros;
449
+ const log = bruto;
450
+ if (log.contrato !== exports.CONTRATO_MASTER_PENDENTE || log.estado !== 'ratificacao-pendente' || log.score !== null ||
451
+ Object.hasOwn(log, 'avaliadoPor') || Object.hasOwn(log, 'avaliadoEm'))
452
+ erros.push('MASTER pendente exige ratificação sem score humano');
453
+ const p = log.score_proposto;
454
+ if (!p || !Number.isInteger(p.valor) || p.valor < 0 || p.valor > 5 ||
455
+ typeof p.propostoPor !== 'string' || !p.propostoPor.trim() ||
456
+ typeof p.propostoEm !== 'string' || !Number.isFinite(Date.parse(p.propostoEm)) ||
457
+ p.justificativa !== log.justificativa || p.resumo !== log.resumo ||
458
+ JSON.stringify(p.classes) !== JSON.stringify(log.classesDeFalha))
459
+ erros.push('proposta de score inválida');
460
+ return erros;
461
+ }
462
+ function validarBaseMaster(bruto) {
463
+ if (!bruto || typeof bruto !== 'object')
464
+ return ['o MASTER log nao e um objeto'];
465
+ const erros = [], log = bruto;
466
+ if (log.versao !== exports.VERSAO_MASTER_LOG)
467
+ erros.push(`campo "versao" deve ser ${exports.VERSAO_MASTER_LOG}`);
468
+ for (const campo of ['thread', 'slug', 'modo', 'tag', 'justificativa', 'resumo']) {
469
+ const v = log[campo];
470
+ if (typeof v !== 'string' || v.trim() === '')
471
+ erros.push(`campo "${campo}" ausente ou vazio`);
472
+ }
336
473
  if (!Array.isArray(log.fases) || log.fases.length === 0) {
337
474
  erros.push('campo "fases" deve listar as fases percorridas');
338
475
  }
@@ -361,22 +498,120 @@ function validarMasterLog(bruto) {
361
498
  }
362
499
  return erros;
363
500
  }
364
- /** Le o MASTER log de uma thread, quando existe. */
501
+ function hashDocumento(arquivo) {
502
+ return (0, node_crypto_1.createHash)('sha256').update(fs.readFileSync(arquivo)).digest('hex');
503
+ }
504
+ /** Leitura fail-closed: documento divergente não vira aprendizado ratificado. */
365
505
  function lerMasterLog(raiz, id) {
366
506
  const caminho = caminhoMasterLog(raiz, id);
367
507
  if (!fs.existsSync(caminho))
368
508
  return null;
369
- return (0, util_1.lerJson)(caminho);
509
+ let log;
510
+ try {
511
+ log = (0, util_1.lerJson)(caminho);
512
+ }
513
+ catch {
514
+ return null; /* JSON inválido não é MASTER */
515
+ }
516
+ if (validarMasterLog(log).length || !masterRatificado(raiz, id))
517
+ return null;
518
+ const score = (0, thread_1.lerThread)(raiz, id).score;
519
+ const evento = [...(0, ledger_1.lerLedger)((0, thread_1.dirThread)(raiz, id))].reverse().find(e => e.tipo === ledger_1.TIPOS_DE_EVENTO.masterConcluido);
520
+ if (log.thread !== id || log.score !== score.valor || log.justificativa !== score.justificativa ||
521
+ log.avaliadoPor !== score.avaliadoPor || log.avaliadoEm !== score.avaliadoEm)
522
+ return null;
523
+ if (Array.isArray(evento.classesDeFalha) && JSON.stringify(log.classesDeFalha) !== JSON.stringify(evento.classesDeFalha))
524
+ return null;
525
+ // Hashes são evidência adicional no evento, sem mudar o contrato congelado v1.
526
+ if (evento.masterLogSha256 && hashDocumento(caminho) !== evento.masterLogSha256)
527
+ return null;
528
+ if (evento.postmortemSha256 && (!fs.existsSync(caminhoPostmortem(raiz, id)) ||
529
+ hashDocumento(caminhoPostmortem(raiz, id)) !== evento.postmortemSha256))
530
+ return null;
531
+ return log;
532
+ }
533
+ /** Quem decide quando ninguem decide. Literal unico, para o leitor reconhecer. */
534
+ exports.AUTOR_DA_OMISSAO = 'nucleo ork (omissao)';
535
+ /**
536
+ * Aceita a entrega por OMISSAO e registra que foi por omissao (I-43, D3).
537
+ *
538
+ * Este e o coracao da remocao da fila de ratificacao, e a parte que nao pode dar
539
+ * errado. Aceitacao por default sem registro seria pior que a fila: a fila ao menos
540
+ * deixava 13 threads visiveis esperando; uma entrega ruim aceita em silencio some, e
541
+ * some sem deixar rastro de que sumiu (R4 do GOAL).
542
+ *
543
+ * Entao a aceitacao produz TRES rastros independentes:
544
+ * 1. o evento `aceite_por_omissao` no ledger, append-only, com o indice e os
545
+ * insumos que o produziram;
546
+ * 2. o `score` gravado com `regime: 'omissao'` e `avaliadoPor` do nucleo,
547
+ * distinguivel de nota humana a olho e por codigo;
548
+ * 3. a visao de `ork master`, que lista o que passou sem o dono olhar.
549
+ *
550
+ * E ela NAO e irreversivel: reclamar continua possivel para sempre. O dono pontua a
551
+ * thread quando quiser, o score vira `regime: 'pausa'` com o nome dele, e o evento de
552
+ * omissao PERMANECE no ledger, porque o ledger e append-only e a historia de que a
553
+ * entrega passou sem revisao continua sendo verdade.
554
+ */
555
+ function aceitarPorOmissao(raiz, id) {
556
+ const thread = (0, thread_1.lerThread)(raiz, id);
557
+ const dir = (0, thread_1.dirThread)(raiz, id);
558
+ // A1: aceitar por default so pode carimbar nota depois de perguntar ao git se a
559
+ // entrega ainda esta de pe. Era aqui que uma entrega revertida virava score 5.
560
+ const indice = indiceDaThread(raiz, id);
561
+ const aceitoEm = (0, util_1.agora)();
562
+ (0, ledger_1.registrar)(dir, id, ledger_1.TIPOS_DE_EVENTO.aceitePorOmissao, {
563
+ fase: 'MASTER',
564
+ indice: indice.valor,
565
+ base: indice.base,
566
+ // Os INSUMOS vao junto: um numero sem origem no ledger e um numero inventado.
567
+ insumos: indice.parcelas.map((p) => ({ evento: p.evento, ocorrencias: p.ocorrencias, desconto: p.desconto })),
568
+ decididoPor: exports.AUTOR_DA_OMISSAO,
569
+ razao: 'entrega aceita por default: ninguem pontuou. Nota humana posterior sobrescreve, e este evento permanece',
570
+ });
571
+ registrarMaster(raiz, id, {
572
+ score: Math.round(indice.valor),
573
+ justificativa: `Aceita por omissao: ninguem pontuou esta entrega. Indice derivado do ledger = ` +
574
+ `${indice.valor} de ${indice.base}` +
575
+ (indice.parcelas.length === 0
576
+ ? ', sem reversao, GO-FIX, CHECK refeito nem ship barrado.'
577
+ : `, descontando ${indice.parcelas.map((p) => `${p.evento} x${p.ocorrencias}`).join(', ')}.`) +
578
+ ' O dono pode pontuar quando quiser; a nota humana sobrescreve e o registro da omissao permanece.',
579
+ por: exports.AUTOR_DA_OMISSAO,
580
+ regime: 'omissao',
581
+ refazer: thread.status === 'fechada',
582
+ });
583
+ return { thread: id, indice, decididoPor: exports.AUTOR_DA_OMISSAO, aceitoEm };
584
+ }
585
+ /** As entregas aceitas por omissao: o que passou sem o dono olhar. */
586
+ function aceitosPorOmissao(raiz) {
587
+ const saida = [];
588
+ for (const id of (0, thread_1.listarIds)(raiz)) {
589
+ const eventos = (0, ledger_1.lerLedger)((0, thread_1.dirThread)(raiz, id));
590
+ const aceite = [...eventos].reverse().find((e) => e.tipo === ledger_1.TIPOS_DE_EVENTO.aceitePorOmissao);
591
+ if (!aceite)
592
+ continue;
593
+ // A1: a reversao pode ter vindo DEPOIS do aceite. O indice aqui e recalculado ao
594
+ // vivo, e `scoreGravado` fica ao lado para a divergencia aparecer em vez de sumir:
595
+ // o MASTER log e contrato congelado e nao se reescreve sozinho.
596
+ saida.push({
597
+ thread: id,
598
+ indice: indiceDaThread(raiz, id),
599
+ decididoPor: String(aceite.decididoPor ?? exports.AUTOR_DA_OMISSAO),
600
+ aceitoEm: String(aceite.ts ?? ''),
601
+ scoreGravado: (0, thread_1.lerThread)(raiz, id).score?.valor ?? null,
602
+ });
603
+ }
604
+ return saida;
370
605
  }
371
606
  /**
372
607
  * A fila de batch scoring: threads que entregaram (ou chegaram ao MASTER) e ainda nao
373
- * tem score. E a fila que `#Ork`, `#Maestro` e `#Auto` alimentam ao entregar sem pausa.
608
+ * tem score. E a fila que `#Classic`, `#Maestro` e `#Auto` alimentam ao entregar sem pausa.
374
609
  */
375
610
  function pendentesDeScore(raiz, todas = false) {
376
611
  const saida = [];
377
612
  for (const id of (0, thread_1.listarIds)(raiz)) {
378
613
  const thread = (0, thread_1.lerThread)(raiz, id);
379
- if (thread.score)
614
+ if (thread.fechamentoAdmin || masterRatificado(raiz, id))
380
615
  continue;
381
616
  const jaEntregou = entregou(raiz, id);
382
617
  const noMaster = thread.faseAtual === 'MASTER';
@@ -392,44 +627,93 @@ function pendentesDeScore(raiz, todas = false) {
392
627
  }
393
628
  return saida;
394
629
  }
395
- /** Tabela de `ork master --batch`: o review em bloco. */
396
- function tabelaDeBatch(raiz, todas = false) {
630
+ /**
631
+ * A visao de entregas de `ork master` (I-43, T8): o que a FILA deixou de ser.
632
+ *
633
+ * O que saiu foi a FILA, e o que ela era: uma lista que acumulava "entregou e nao tem
634
+ * score" esperando o humano. Ela tinha 13 entradas em 20/09/2026, e nao por falta de
635
+ * lembrete: lembrete nao converte em nota. Enquanto ela existia, a unica informacao
636
+ * sobre a qualidade de uma entrega era uma nota que ninguem dava.
637
+ *
638
+ * No lugar dela, cada entrega chega com um INDICE ja calculado do ledger, e o comando
639
+ * oferece UM caminho para drenar o que sobrou: aceitar por omissao, com registro.
640
+ *
641
+ * O que NAO saiu, e nao podia sair: pontuar. `ork master <thread> --score` continua
642
+ * inteiro, e a nota humana continua sobrescrevendo o indice quando o dono reclama.
643
+ */
644
+ function tabelaDeEntregas(raiz, todas = false) {
397
645
  const pendentes = pendentesDeScore(raiz, todas);
646
+ const omissoes = aceitosPorOmissao(raiz);
647
+ // A1: o indice da coluna e o de AGORA; `SCORE GRAVADO` e o que o MASTER log congelou.
648
+ // Quando o segundo e maior, a entrega caiu depois de aceita e isso precisa aparecer.
649
+ const caiuDepoisDeAceita = omissoes.filter((o) => typeof o.scoreGravado === 'number' && o.indice.valor < o.scoreGravado);
650
+ const secaoOmissao = omissoes.length === 0
651
+ ? []
652
+ : ['', `Aceitas por omissao (${omissoes.length}): o que passou sem voce olhar.`, '',
653
+ (0, util_1.tabela)(['ID', 'INDICE', 'SCORE GRAVADO', 'ACEITA EM'], omissoes.map((o) => [o.thread, `${o.indice.valor}/${o.indice.base}`,
654
+ typeof o.scoreGravado === 'number' ? `${o.scoreGravado}/5` : '-',
655
+ (0, horario_1.formatarDataHora)(o.aceitoEm)])),
656
+ (0, horario_1.legendaDoFuso)(),
657
+ ...(caiuDepoisDeAceita.length === 0 ? [] : ['',
658
+ `ATENCAO: ${caiuDepoisDeAceita.length} entrega(s) cairam DEPOIS de aceitas: ` +
659
+ caiuDepoisDeAceita.map((o) => o.thread).join(', ') + '.',
660
+ ' O MASTER log e contrato congelado e nao se reescreve sozinho. Pontue para o',
661
+ ' registro humano alcancar o fato; o registro da omissao permanece no ledger.']),
662
+ '', 'Discordou de alguma? A nota humana sobrescreve, e o registro da omissao permanece:',
663
+ ' ork master <thread-id> --score <0-5> --justificativa "<por que>" --por <humano>'];
398
664
  if (pendentes.length === 0) {
399
- return todas
400
- ? 'Nenhuma thread aberta sem score. A fila de batch scoring esta vazia.'
401
- : 'Nenhuma thread entregue esperando score. A fila de batch scoring esta vazia.\n' +
402
- 'Para ver tambem as threads que ainda nao entregaram: ork master --batch --todas';
665
+ return [
666
+ todas
667
+ ? 'Nenhuma thread aberta sem score.'
668
+ : 'Nenhuma entrega esperando decisao. Para ver tambem as que ainda nao entregaram: ork master --todas',
669
+ ...secaoOmissao,
670
+ ].join('\n');
403
671
  }
404
- const linhas = pendentes.map((p) => [
405
- p.thread.id,
406
- p.thread.slug,
407
- (0, modos_1.tagDoModo)(p.thread.modo),
408
- p.thread.faseAtual,
409
- p.thread.status,
410
- p.regime,
411
- p.entregou ? 'sim' : 'nao',
412
- String(p.fasesPercorridas),
413
- ]);
414
- const cabecalho = (0, util_1.tabela)(['ID', 'SLUG', 'MODO', 'FASE', 'STATUS', 'REGIME', 'ENTREGOU', 'FASES'], linhas);
672
+ const linhas = pendentes.map((p) => {
673
+ const indice = indiceDaThread(raiz, p.thread.id);
674
+ return [
675
+ p.thread.id,
676
+ p.thread.slug,
677
+ (0, modos_1.tagDoModo)(p.thread.modo),
678
+ p.thread.faseAtual,
679
+ p.thread.status,
680
+ p.entregou ? 'sim' : 'nao',
681
+ `${indice.valor}/${indice.base}`,
682
+ indice.parcelas.length === 0 ? 'sem tropeco' : indice.parcelas.map((x) => `${x.evento} x${x.ocorrencias}`).join(', '),
683
+ ];
684
+ });
415
685
  return [
416
- `Fila de score (${pendentes.length} thread(s) esperando o humano)`,
686
+ `Entregas (${pendentes.length}) com o indice ja derivado do ledger. O numero nao foi digitado por ninguem.`,
417
687
  '',
418
- cabecalho,
688
+ (0, util_1.tabela)(['ID', 'SLUG', 'MODO', 'FASE', 'STATUS', 'ENTREGOU', 'INDICE', 'DE ONDE VEIO'], linhas),
419
689
  '',
420
- 'Pontue em bloco, uma linha por thread:',
421
- ...pendentes.map((p) => ` ork master ${p.thread.id} --score <0-5> --justificativa "<por que>" --classe <classe>`),
690
+ 'ENTREGUE E ACEITO, a menos que voce diga o contrario.',
691
+ ' ork master --aceitar-omissao aceita as entregues, com o indice e os insumos no ledger',
692
+ ' ork master <id> --score <0-5> --justificativa "<por que>" --por <humano> se quiser reclamar',
422
693
  '',
423
694
  `Classes fixas: ${exports.ORDEM_DAS_CLASSES.join(', ')}`,
695
+ ...secaoOmissao,
424
696
  ].join('\n');
425
697
  }
698
+ /**
699
+ * Aceita por omissao TODAS as entregas que ainda esperam decisao.
700
+ *
701
+ * E o comando que drena a fila de uma vez, e por isso ele so alcanca o que de fato
702
+ * ENTREGOU: uma thread que nunca chegou ao ship nao tem entrega para aceitar, e
703
+ * aceita-la seria inventar um fato.
704
+ */
705
+ function aceitarPendentesPorOmissao(raiz) {
706
+ return pendentesDeScore(raiz)
707
+ .filter((p) => p.entregou)
708
+ .map((p) => aceitarPorOmissao(raiz, p.thread.id));
709
+ }
426
710
  /** Texto de `ork master <thread-id> --score`. */
427
711
  function textoDoMaster(r) {
428
712
  const linhas = [];
429
713
  linhas.push(`MASTER registrado: thread ${r.thread.id} fechada.`);
430
714
  linhas.push(` score ${r.masterLog.score}/5 (${r.postmortem.score.regime})`);
431
715
  linhas.push(` justificativa ${r.masterLog.justificativa}`);
432
- linhas.push(` avaliado por ${r.masterLog.avaliadoPor} em ${r.masterLog.avaliadoEm}`);
716
+ linhas.push(` avaliado por ${r.masterLog.avaliadoPor} em ${(0, horario_1.formatarDataHoraRotulada)(r.masterLog.avaliadoEm)}`);
433
717
  linhas.push(` classes ${r.masterLog.classesDeFalha.join(', ')}`);
434
718
  linhas.push(` fases ${r.masterLog.fases.join(' -> ')}`);
435
719
  linhas.push(` entregas ${r.postmortem.entregas.length} ship(s) concluido(s) no ledger`);