@orkastery/cli 0.6.5 → 0.6.7

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 (42) hide show
  1. package/adapters/claude-code/agents/ork-check.md +4 -0
  2. package/adapters/claude-code/mods/ork-freio/hooks/lote.ts +1 -1
  3. package/adapters/claude-code/mods/ork-torre/hooks/frases.ts +2 -1
  4. package/adapters/openclaw/openclaw.plugin.json +1 -1
  5. package/adapters/openclaw/package.json +1 -1
  6. package/assets/adapters-en/claude-code/agents/ork-check.md +4 -0
  7. package/assets/skills-en/phases/check-quality/SKILL.md +14 -0
  8. package/dist/adapters/claude-bg.js +1 -1
  9. package/dist/agendador-cpu.js +27 -4
  10. package/dist/ambiente-funcional.js +72 -0
  11. package/dist/cenarios-sensores.js +3 -7
  12. package/dist/check-agil.js +204 -60
  13. package/dist/check-paralelo.js +101 -36
  14. package/dist/claim-lint.js +19 -0
  15. package/dist/claims.js +77 -11
  16. package/dist/fila-pesada.js +8 -6
  17. package/dist/fix.js +152 -6
  18. package/dist/hitl-gates.js +1 -1
  19. package/dist/index.js +53 -4
  20. package/dist/locale-ajuda.js +10 -4
  21. package/dist/locale-claims.js +22 -6
  22. package/dist/locale-operacao-restante.js +12 -0
  23. package/dist/locale-prompts.js +4 -2
  24. package/dist/locale-pulse.js +2 -0
  25. package/dist/locale-retry.js +8 -0
  26. package/dist/locale-verify.js +8 -0
  27. package/dist/mcp-artifacts.js +24 -0
  28. package/dist/mcp-install.js +1 -1
  29. package/dist/mcp-server.js +11 -1
  30. package/dist/mcp-verify-async.js +2 -1
  31. package/dist/noctum-provas.js +56 -30
  32. package/dist/recibo-prova.js +87 -0
  33. package/dist/retry.js +6 -0
  34. package/dist/security-scan/executor.js +9 -3
  35. package/dist/security-scan/guard.js +5 -2
  36. package/dist/session-watcher.js +94 -23
  37. package/dist/ship.js +1 -1
  38. package/dist/temporario-das-lanes.js +94 -0
  39. package/dist/verify.js +662 -410
  40. package/eval/fixtures/fx-sensores-runtime/caso.json +1 -1
  41. package/package.json +1 -1
  42. package/skills/phases/check-quality/SKILL.md +14 -0
@@ -19,6 +19,10 @@ ork phase list <thread> # o que ja aconteceu, com evidencia
19
19
  ## Regras desta fase
20
20
 
21
21
  - **CHECK nao corrige.** Achado vira tarefa de GO, com commit proprio.
22
+ - Claim nova afirma o comportamento correto e passa depois da correcao; a reproducao do defeito
23
+ fica como comando no parecer e nunca vira claim.
24
+ - Achado sem claim usa `- A<n> [blocker|warning|suggestion] path:line - description`; a linha
25
+ seguinte pode usar `reproduce: \`command\``. Os tokens do formato sao estaveis nas duas linguas.
22
26
  - Eixo sem achado sai com "nenhum" explicito.
23
27
  - Zero bloqueadores de seguranca e condicao dura, em qualquer modo.
24
28
  - Correcao tipo B devolve ao GO e o CHECK seguinte e reexecucao completa.
@@ -126,7 +126,7 @@ export function soLeitura(chamadas: readonly Chamada[]): boolean {
126
126
 
127
127
  /** O lote registrou, retirou ou mudou claim: a lista do nucleo precisa ser relida. */
128
128
  export function mexeuNasClaims(chamadas: readonly Chamada[]): boolean {
129
- return chamadas.some(c => nomeDa(c) === 'mcp__orkastery__ork_claim_add'
129
+ return chamadas.some(c => ['mcp__orkastery__ork_claim_add', 'mcp__orkastery__ork_claim_withdraw'].includes(nomeDa(c))
130
130
  || (nomeDa(c) === 'Bash' && CLI_DE_CLAIMS.test(String((c.tool_input as { command?: unknown } | null)?.command ?? ''))))
131
131
  }
132
132
 
@@ -7,6 +7,7 @@ export const FRASE_DO_MOTIVO: Readonly<Record<string, string>> = {
7
7
  'artifact.missing': 'falta um artefato que a fase exige',
8
8
  'claims.failed': 'uma claim reprovou no HEAD',
9
9
  'claims.unverifiable': 'há claim sem comando de verificação',
10
+ 'claims.retirada-sem-substituta': 'uma retirada sem substituta espera sua decisão',
10
11
  'concurrency.lease-indeterminado': 'não foi possível provar se a vaga está livre',
11
12
  'conducao.acao-necessaria': 'a condução precisa executar uma ação',
12
13
  'policy.violation': 'uma policy de bloqueio foi violada',
@@ -36,7 +37,7 @@ export const FRASE_DO_MOTIVO: Readonly<Record<string, string>> = {
36
37
 
37
38
  /** Os motivos que so o dono resolve (D6): a linha fica em "espera voce", nao em "parada". */
38
39
  export const MOTIVOS_DO_DONO: readonly string[] = ['human.pending', 'runtime.workspace-untrusted', 'runtime.consent-pending',
39
- 'runtime.auth-missing']
40
+ 'runtime.auth-missing', 'claims.retirada-sem-substituta']
40
41
 
41
42
  /** A frase do motivo; motivo que a tabela nao conhece aparece cru, nunca some. */
42
43
  export function fraseDoMotivo(motivo: string): string {
@@ -2,7 +2,7 @@
2
2
  "id": "orkastery",
3
3
  "name": "Orkastery",
4
4
  "description": "Conducao de looping threads em 6 fases pelo nucleo `ork`, exposta ao OpenClaw como tools `ork_*`. Zero regra de negocio no host: cada tool e uma chamada de CLI. Toda tool de projeto aceita projeto (nome do projeto pedido); o cwd do gateway nunca escolhe o projeto. O status do roadmap vem de ork_network_roadmap; as maquinas da pessoa, de ork_network_status (sem projeto).",
5
- "version": "0.6.5",
5
+ "version": "0.6.7",
6
6
  "configSchema": {
7
7
  "type": "object",
8
8
  "properties": {},
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@orkastery/openclaw-plugin",
3
- "version": "0.6.5",
3
+ "version": "0.6.7",
4
4
  "description": "Plugin Orkastery para OpenClaw: 32 tools ork_* que traduzem intencao em chamada de CLI do nucleo `ork`. Zero regra de negocio no host.",
5
5
  "type": "module",
6
6
  "private": true,
@@ -19,6 +19,10 @@ ork phase list <thread> # o que ja aconteceu, com evidencia
19
19
  ## Rules for this phase
20
20
 
21
21
  - **CHECK does not fix.** A finding becomes a GO task, with its own commit.
22
+ - A new claim states the correct behavior and passes after the fix; defect reproduction stays as
23
+ a command in the report and never becomes a claim.
24
+ - A finding without a claim uses `- A<n> [blocker|warning|suggestion] path:line - description`;
25
+ the following line may use `reproduce: \`command\``.
22
26
  - An axis without findings comes out with an explicit "none".
23
27
  - Zero security blockers is a hard condition, in any mode.
24
28
  - A type B fix goes back to GO, and the next CHECK is a full re-run.
@@ -42,6 +42,20 @@ verdict up to a human in any mode, including `#Auto`.
42
42
  The catalog's four reviewers come in here: `code-reviewer`, `security-auditor`, `test-engineer`
43
43
  and `web-performance-auditor`. Each one runs in its own scope and returns categorized findings.
44
44
 
45
+ ## Claims and defect reproductions
46
+
47
+ - A claim created during CHECK states the expected correct behavior and must pass after the fix.
48
+ It never states that the defect still occurs.
49
+ - The command that reproduces the defect stays only in the report (`docs/check.md`) as finding
50
+ evidence; that command never becomes a claim.
51
+ - A finding without a claim uses a machine-readable line for the correction cycle; the format
52
+ tokens stay the same in both languages:
53
+
54
+ `- A<n> [blocker|warning|suggestion] path:line - description`
55
+
56
+ The following line may record `reproduce: \`command\``. The command remains report evidence,
57
+ not claim verification.
58
+
45
59
  ## What CHECK delivers
46
60
 
47
61
  1. **Comparison against the baseline**, separating regression from pre-existing debt. Without that
@@ -115,7 +115,7 @@ exports.CONSULTAS_MCP = [
115
115
  ];
116
116
  // RM-037 (defeito 1): a decisao autonoma pelo MCP tem o mesmo grant nos dois runtimes.
117
117
  exports.MUTACOES_WORKTREE = [
118
- 'mcp__orkastery__ork_artifact_write', 'mcp__orkastery__ork_claim_add', 'mcp__orkastery__ork_decision_record',
118
+ 'mcp__orkastery__ork_artifact_write', 'mcp__orkastery__ork_claim_add', 'mcp__orkastery__ork_claim_withdraw', 'mcp__orkastery__ork_decision_record',
119
119
  'mcp__orkastery__ork_request_conduction', 'mcp__orkastery__ork_git_commit', 'mcp__orkastery__ork_verify',
120
120
  'mcp__orkastery__ork_ship',
121
121
  ];
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.AMOSTRAS_DA_SONDA = exports.JANELA_DA_SONDA_MS = exports.LIMIAR_STEAL_DO_AGENDADOR_PCT = exports.MINIMO_ESTRUTURAL_DO_GRUPO = exports.RESERVA_DO_GRUPO = exports.ENV_CONTAINERS_DA_LANE = exports.ENV_CPUS_DOCKER = exports.ENV_SINAL_DA_RESERVA = exports.ENV_CPUS_DA_LANE_APOS_RESERVA = exports.ENV_CPUS_DA_LANE_APOS_VARREDURA = exports.ENV_WORKERS = exports.ENV_CPUS_DA_LANE = void 0;
4
+ exports.registrarCotaDockerDaLane = registrarCotaDockerDaLane;
4
5
  exports.registrarContainerDaLane = registrarContainerDaLane;
5
6
  exports.workersDaReserva = workersDaReserva;
6
7
  exports.cargaDoProcLoadavg = cargaDoProcLoadavg;
@@ -36,6 +37,16 @@ exports.MINIMO_ESTRUTURAL_DO_GRUPO = exports.RESERVA_DO_GRUPO + 1;
36
37
  exports.LIMIAR_STEAL_DO_AGENDADOR_PCT = 10;
37
38
  exports.JANELA_DA_SONDA_MS = 250;
38
39
  exports.AMOSTRAS_DA_SONDA = 5;
40
+ /** O adaptador registra a decisão real do runtime no mesmo canal privado usado pela sonda dos contêineres. */
41
+ function registrarCotaDockerDaLane(evidencia, ambiente = process.env) {
42
+ const arquivo = ambiente[exports.ENV_CONTAINERS_DA_LANE];
43
+ if (!arquivo)
44
+ return;
45
+ try {
46
+ (0, node_fs_1.appendFileSync)(arquivo, JSON.stringify({ tipo: 'cota-docker', ...evidencia, em: new Date().toISOString() }) + '\n', { mode: 0o600 });
47
+ }
48
+ catch { /* a falta da evidência impede afirmar aplicação, mas não derruba a fixture */ }
49
+ }
39
50
  /** Registra o container antes do `docker run`; falha de evidencia nunca impede a ferramenta de rodar. */
40
51
  function registrarContainerDaLane(nome, ambiente = process.env) {
41
52
  const arquivo = ambiente[exports.ENV_CONTAINERS_DA_LANE];
@@ -103,7 +114,7 @@ async function medirCpuDoGrupo(janelaMs = exports.JANELA_DA_SONDA_MS) {
103
114
  return resumirMedicaoCpuDoGrupo(cargas, steals);
104
115
  }
105
116
  /** O plano unico que alimenta concorrencia das lanes, varredura e `docker run --cpus`. */
106
- function planejarCpuDoGrupo(cpusInformadas, medicao) {
117
+ function planejarCpuDoGrupo(cpusInformadas, medicao, carga = {}) {
107
118
  const cpus = cpusValidas(cpusInformadas);
108
119
  const steal = Math.min(100, Math.max(0, medicao.stealPct ?? 0));
109
120
  // So o steal desconta capacidade. A carga de um minuto do /proc/loadavg inclui o build do proprio verify e a rodada
@@ -130,6 +141,13 @@ function planejarCpuDoGrupo(cpusInformadas, medicao) {
130
141
  ? Math.max(1, Math.min(capacidadeEfetiva - 1, Math.ceil(medida)))
131
142
  : ferramentas;
132
143
  const integracaoEmParalelo = !saturado && medidaCompativel && capacidadeEfetiva - fatia - cpusIntegracao >= 1;
144
+ const cpusIntegracaoEmUso = integracaoEmParalelo ? cpusIntegracao : fatia;
145
+ const cadeiasDeClaims = Math.max(0, Math.floor(carga.cadeiasDeClaims ?? 0));
146
+ const hermeticaSemClaims = saturado ? classic
147
+ : Math.max(1, capacidadeEfetiva - fatia - (integracaoEmParalelo ? cpusIntegracao : 0));
148
+ // Cada cadeia recebe uma vaga, mas a lane critica conserva ao menos a mesma parcela. Sem duas vagas livres, a claim
149
+ // continua depois das lanes. A conta e proporcional a capacidade efetiva, nunca a uma maquina especifica.
150
+ const cpusClaims = saturado ? 0 : Math.min(cadeiasDeClaims, Math.floor(hermeticaSemClaims / 2));
133
151
  const amostras = (xs, resumo) => `[${(xs?.length ? xs : resumo === null ? [] : [resumo]).join(', ')}]`;
134
152
  const evidencia = `carga em /proc/loadavg: amostras ${amostras(medicao.amostrasCarga1, medicao.carga1)}, mediana ` +
135
153
  `${medicao.carga1 ?? 'indisponivel'}; steal em /proc/stat: amostras ${amostras(medicao.amostrasStealPct, medicao.stealPct)}, ` +
@@ -138,7 +156,9 @@ function planejarCpuDoGrupo(cpusInformadas, medicao) {
138
156
  ? `${motivos.join('; ')}; ${evidencia}`
139
157
  : `capacidade ${capacidadeEfetiva}/${cpus} CPU(s)${estado === 'degradado' ? ' depois do desconto do steal' : ' inteira'}; ${evidencia}; ` +
140
158
  `${fatia} CPU(s) reservadas a varredura; ` +
141
- (integracaoEmParalelo ? `integracao medida cabe em paralelo com ${cpusIntegracao} CPU(s)` : 'integracao permanece encadeada');
159
+ (integracaoEmParalelo ? `integracao medida cabe em paralelo com ${cpusIntegracao} CPU(s)`
160
+ : `integracao encadeada inicia depois da varredura com ${cpusIntegracaoEmUso} CPU(s)`) +
161
+ (cadeiasDeClaims ? `; claims com ${cpusClaims} vaga(s) para ${cadeiasDeClaims} cadeia(s)` : '');
142
162
  return {
143
163
  cpus,
144
164
  ordem: saturado ? 'classic' : 'paralela',
@@ -146,13 +166,16 @@ function planejarCpuDoGrupo(cpusInformadas, medicao) {
146
166
  capacidadeEfetiva,
147
167
  saturado,
148
168
  motivo,
149
- cpusHermetica: saturado ? classic : Math.max(1, capacidadeEfetiva - fatia - (integracaoEmParalelo ? cpusIntegracao : 0)),
150
- cpusHermeticaAposVarredura: saturado ? classic : Math.max(1, capacidadeEfetiva - cpusIntegracao),
169
+ cpusHermetica: Math.max(1, hermeticaSemClaims - cpusClaims),
170
+ cpusHermeticaAposVarredura: saturado ? classic : Math.max(1, capacidadeEfetiva - cpusIntegracaoEmUso),
151
171
  cpusHermeticaAposReserva: saturado ? classic : capacidadeEfetiva,
152
172
  cpusIntegracao,
173
+ cpusClaims,
174
+ cadeiasDeClaims,
153
175
  fonteCpusIntegracao: saturado ? 'classic' : medidaCompativel
154
176
  ? 'medida' : 'conservadora',
155
177
  integracaoEmParalelo,
178
+ cpusIntegracaoEmUso,
156
179
  cpusDaFatia: fatia,
157
180
  ferramentasDaVarredura: ferramentas,
158
181
  cpusPorContainer: Math.max(0.01, Math.floor((fatia / ferramentas) * 100) / 100),
@@ -0,0 +1,72 @@
1
+ "use strict";
2
+ /**
3
+ * Ambiente funcional observado pelos testes das lanes e pelas claims que podem reaproveita-las.
4
+ *
5
+ * A lane atravessa `bash` e `npm` antes de chegar ao `test-lanes.cjs`; a claim candidata parte
6
+ * direto do verify. Esta e a unica regra que retira transporte dessas duas rotas, aplica os
7
+ * acrescimos funcionais da rodada e produz a assinatura comparada pelo reaproveitamento.
8
+ */
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.ENV_PATH_FUNCIONAL_DA_RODADA = void 0;
11
+ exports.ambienteFuncionalDosTestes = ambienteFuncionalDosTestes;
12
+ exports.transporteDoAmbienteFuncional = transporteDoAmbienteFuncional;
13
+ exports.assinaturaDoAmbiente = assinaturaDoAmbiente;
14
+ const node_crypto_1 = require("node:crypto");
15
+ /** O PATH anterior a shell/npm, transportado ate o controlador da lane. */
16
+ exports.ENV_PATH_FUNCIONAL_DA_RODADA = 'ORK_CHECK_PATH_FUNCIONAL_DA_RODADA';
17
+ /**
18
+ * Controles consumidos pela orquestracao, nunca pelos testes. PATH e ORK_CHECK_MODO nao sao
19
+ * ignorados: o primeiro e restaurado e o segundo e removido dos dois ambientes efetivos.
20
+ */
21
+ const VARIAVEIS_REMOVIDAS = new Set([
22
+ 'ORK_CHECK_MODO',
23
+ 'ORK_CHECK_RELATORIO',
24
+ 'ORK_CHECK_CPUS_DA_LANE',
25
+ 'ORK_CHECK_CPUS_DA_LANE_APOS_VARREDURA',
26
+ 'ORK_CHECK_CPUS_DA_LANE_APOS_RESERVA',
27
+ 'ORK_CHECK_RESERVA_DEVOLVIDA',
28
+ 'ORK_CHECK_CONTAINERS_DA_LANE',
29
+ 'ORK_CHECK_CPUS_DOCKER',
30
+ 'ORK_CHECK_TMPDIR_DA_RODADA',
31
+ 'ORK_WORKERS',
32
+ exports.ENV_PATH_FUNCIONAL_DA_RODADA,
33
+ 'NODE_TEST_CONTEXT',
34
+ // Shell nao interativo pode executar estes arquivos antes do comando. O verify e a lane nao
35
+ // dependem de inicializacao pessoal do chamador.
36
+ 'BASH_ENV',
37
+ 'ENV',
38
+ ]);
39
+ /** Transporte do npm, do shell e do runner que nao entra no contrato funcional. */
40
+ function variavelIgnorada(nome) {
41
+ return nome.startsWith('npm_') || nome.startsWith('NPM_')
42
+ || ['COLOR', 'NODE', 'EDITOR', 'NODE_COMPILE_CACHE', 'PWD', 'OLDPWD', 'SHLVL', '_', 'INIT_CWD'].includes(nome);
43
+ }
44
+ /** Monta o ambiente real dos testes, com as mesmas remocoes e acrescimos nas duas rotas. */
45
+ function ambienteFuncionalDosTestes(base, acrescimos = {}) {
46
+ const pathDaRodada = base[exports.ENV_PATH_FUNCIONAL_DA_RODADA];
47
+ const ambiente = Object.fromEntries(Object.entries(base).filter(([nome, valor]) => valor !== undefined && !VARIAVEIS_REMOVIDAS.has(nome) && !variavelIgnorada(nome)));
48
+ if (pathDaRodada !== undefined)
49
+ ambiente.PATH = pathDaRodada;
50
+ for (const [nome, valor] of Object.entries(acrescimos)) {
51
+ if (valor !== undefined)
52
+ ambiente[nome] = valor;
53
+ }
54
+ return ambiente;
55
+ }
56
+ /**
57
+ * Dados que deixam a lane recuperar o ambiente anterior ao shell/npm. BASH_ENV e ENV vazios
58
+ * impedem inicializacao pessoal antes de o script aplicar a regra unica.
59
+ */
60
+ function transporteDoAmbienteFuncional(base) {
61
+ const pathDaRodada = ambienteFuncionalDosTestes(base).PATH;
62
+ return {
63
+ ...(pathDaRodada === undefined ? {} : { [exports.ENV_PATH_FUNCIONAL_DA_RODADA]: pathDaRodada }),
64
+ BASH_ENV: '',
65
+ ENV: '',
66
+ };
67
+ }
68
+ /** Assina exatamente o ambiente funcional montado pela regra unica, inclusive seus acrescimos. */
69
+ function assinaturaDoAmbiente(base, acrescimos = {}) {
70
+ const pares = Object.entries(ambienteFuncionalDosTestes(base, acrescimos)).sort(([a], [b]) => a.localeCompare(b));
71
+ return (0, node_crypto_1.createHash)('sha256').update(JSON.stringify(pares)).digest('hex');
72
+ }
@@ -47,10 +47,7 @@ const estado_thread_1 = require("./estado-thread");
47
47
  const catalogo_1 = require("./catalogo");
48
48
  const linha = (e) => JSON.stringify(e) + '\n';
49
49
  function esperar(teste) {
50
- const limite = Date.now() + 15000;
51
50
  while (!teste()) {
52
- if (Date.now() >= limite)
53
- throw new Error('subprocesso do cenário não terminou no prazo de transporte');
54
51
  Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, 10);
55
52
  }
56
53
  }
@@ -71,8 +68,7 @@ exports.CENARIO_SENSORES = {
71
68
  const hook = path.join(catalogo, 'adapters/claude-code/hooks/ork-sensor.js');
72
69
  const cli = (0, catalogo_1.cliDoCatalogo)(catalogo);
73
70
  const start = Date.now();
74
- // O teto de transporte absorve a fila do Classic; a fixture continua exigindo a latência funcional abaixo de 5 s.
75
- const h = (0, node_child_process_1.spawnSync)(process.execPath, [hook], { cwd: wt, encoding: 'utf8', timeout: 15000,
71
+ const h = (0, node_child_process_1.spawnSync)(process.execPath, [hook], { cwd: wt, encoding: 'utf8',
76
72
  input: JSON.stringify({ cwd: wt, session_id: 'fixture-claude', hook_event_name: 'PermissionRequest', tool_use_id: 'fixture-tool' }),
77
73
  env: { ...process.env, ORK_SENSOR_CLI: cli } });
78
74
  if (h.status !== 0 || h.stderr || h.stdout)
@@ -99,7 +95,7 @@ exports.CENARIO_SENSORES = {
99
95
  }
100
96
  // A identidade vem de um processo realmente executado e encerrado, sem recibo.
101
97
  const runner = require.resolve('./adapters/codex-runner');
102
- const morto = (0, node_child_process_1.spawnSync)(process.execPath, ['-e', `console.log(JSON.stringify(require(process.argv[1]).identidadeProcesso(process.pid)))`, runner], { cwd: wt, encoding: 'utf8', timeout: 15000 });
98
+ const morto = (0, node_child_process_1.spawnSync)(process.execPath, ['-e', `console.log(JSON.stringify(require(process.argv[1]).identidadeProcesso(process.pid)))`, runner], { cwd: wt, encoding: 'utf8' });
103
99
  if (morto.status !== 0)
104
100
  throw new Error('processo de morte do cenário indisponível');
105
101
  const filho = JSON.parse(morto.stdout);
@@ -117,7 +113,7 @@ exports.CENARIO_SENSORES = {
117
113
  (0, session_watcher_1.observarSessao)(s.carregado, sid, { rollout: null, agoraMs: inicio + session_watcher_1.LIMITE_MORTE_MS });
118
114
  const mortes = (0, ledger_1.lerLedger)(dir).filter(e => e.tipo === 'sessao_morta' && e.sessionId === sid);
119
115
  return { tipoProva: 'harness isolado; protocolo Codex sintético', classificacoes, subprocessosComRecibo,
120
- hookLatenciaMs, carimboLatenciaMs, hookAbaixo5s: !!bloqueio && hookLatenciaMs < 5000 && carimboLatenciaMs !== null && carimboLatenciaMs < 5000,
116
+ hookLatenciaMs, carimboLatenciaMs, hookRegistrado: !!bloqueio,
121
117
  morteAntesDoLimite: antes.concluido, morteLatenciaMs: mortes[0]?.morteLatenciaMs ?? null,
122
118
  mortosSemEvento: mortes.length === 1 ? 0 : 1, duplicatas,
123
119
  estadoUnico: (0, estado_thread_1.auditarEstado)(s.dir, t.id, wt).nivel === 'ok' &&