@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.
- package/LICENSE +1 -1
- package/README.md +86 -65
- package/adapters/README.md +30 -15
- package/adapters/claude-code/.claude-plugin/plugin.json +11 -5
- package/adapters/claude-code/README.md +110 -8
- package/adapters/claude-code/commands/onboarding.md +21 -0
- package/adapters/claude-code/commands/ork.md +99 -27
- package/adapters/claude-code/hooks/hooks.json +6 -1
- package/adapters/claude-code/hooks/ork-sensor.js +66 -0
- package/adapters/codex/skills/ork/SKILL.md +57 -0
- package/adapters/hermes/README.md +163 -0
- package/adapters/hermes/bin/ork-abrir-thread.sh +2 -0
- package/adapters/hermes/bin/ork-brain.sh +4 -0
- package/adapters/hermes/bin/ork-hitl-answer.py +82 -0
- package/adapters/hermes/bin/ork-maestro.sh +6 -0
- package/adapters/hermes/bin/ork-master-enviar.py +84 -0
- package/adapters/hermes/bin/ork-objective-message.sh +17 -0
- package/adapters/hermes/bin/ork-objective-status.sh +12 -0
- package/adapters/hermes/bin/ork-pulse-enviar.py +47 -0
- package/adapters/hermes/hermes.plugin.json +26 -4
- package/adapters/hermes/hitl-ingress/__init__.py +356 -0
- package/adapters/hermes/hitl-ingress/plugin.yaml +4 -0
- package/adapters/hermes/skills/orkastery-devmaster/SKILL.md +75 -22
- package/adapters/openclaw/README.md +135 -26
- package/adapters/openclaw/bin/ork-brain.sh +4 -0
- package/adapters/openclaw/construir.sh +19 -0
- package/adapters/openclaw/dist/hitl-ingress.js +199 -0
- package/adapters/openclaw/dist/index.js +437 -0
- package/adapters/openclaw/openclaw.plugin.json +39 -134
- package/adapters/openclaw/package.json +26 -0
- package/adapters/openclaw/src/hitl-ingress.ts +180 -0
- package/adapters/openclaw/src/index.ts +458 -0
- package/adapters/openclaw/src/tipos-openclaw.d.ts +58 -0
- package/adapters/openclaw/tsconfig.json +15 -0
- package/assets/docs/markdownlint-cli2.jsonc +22 -0
- package/assets/docs/padroes/documentacao-de-produto.md +133 -0
- package/assets/docs/padroes/roadmap-de-produto.md +98 -0
- package/assets/docs/produto/README.md +14 -0
- package/assets/docs/produto/_modelo-feature.md +59 -0
- package/assets/docs/roadmap/README.md +14 -0
- package/assets/docs/roadmap/_modelo-item.md +73 -0
- package/assets/orkmind-native-schema.json +32 -0
- package/assets/orkmind_bridge.py +357 -0
- package/assets/orkmind_fixture.py +67 -0
- package/assets/orkmind_prospective.py +138 -0
- package/assets/reference-tariffs-i07.json +23 -0
- package/dist/adapters/claude-bg.js +488 -39
- package/dist/adapters/codex-controller-sensor.js +449 -0
- package/dist/adapters/codex-controller-worker.js +361 -0
- package/dist/adapters/codex-controller.js +252 -0
- package/dist/adapters/codex-events.js +205 -0
- package/dist/adapters/codex-question.js +26 -0
- package/dist/adapters/codex-runner.js +133 -0
- package/dist/adapters/codex.js +394 -0
- package/dist/agents-md.js +84 -0
- package/dist/auditoria.js +11 -8
- package/dist/auditrun.js +5 -4
- package/dist/board.js +173 -22
- package/dist/branch-de-estado.js +136 -0
- package/dist/canarios-hitl.js +177 -0
- package/dist/canarios-i43.js +543 -0
- package/dist/canarios-pulse.js +147 -0
- package/dist/canarios-sensores.js +129 -0
- package/dist/canarios.js +111 -2
- package/dist/catalogo.js +9 -0
- package/dist/ci.js +216 -0
- package/dist/ciclos.js +2 -1
- package/dist/claim-lint.js +64 -0
- package/dist/claims.js +60 -0
- package/dist/company-brain-capture.js +195 -0
- package/dist/company-brain-cli.js +123 -0
- package/dist/company-brain-client.js +61 -0
- package/dist/company-brain-contract.js +166 -0
- package/dist/company-brain-journal.js +192 -0
- package/dist/company-brain-mcp.js +33 -0
- package/dist/company-brain-migration.js +60 -0
- package/dist/company-brain-source.js +177 -0
- package/dist/company-brain-worker.js +18 -0
- package/dist/conducao-texto.js +61 -0
- package/dist/conducao.js +876 -0
- package/dist/contrato-publico.js +39 -0
- package/dist/creation-operation-store.js +251 -0
- package/dist/creation-operation.js +148 -0
- package/dist/decisao-autonoma.js +183 -0
- package/dist/delegation.js +79 -0
- package/dist/demo.js +120 -0
- package/dist/docs.js +828 -0
- package/dist/doctor.js +183 -24
- package/dist/entrega-pr.js +117 -0
- package/dist/escopo-escrita.js +71 -0
- package/dist/estado-thread.js +222 -0
- package/dist/evalrunner.js +12 -0
- package/dist/fabrica-estado.js +329 -0
- package/dist/fabrica-publicar.js +76 -0
- package/dist/fix.js +21 -0
- package/dist/gates.js +55 -9
- package/dist/handoff.js +39 -23
- package/dist/hitl-canais.js +333 -0
- package/dist/hitl-classificacao.js +131 -0
- package/dist/hitl-contract.js +465 -0
- package/dist/hitl-estado.js +136 -0
- package/dist/hitl-gates.js +554 -0
- package/dist/hitl-ingress-receipt.js +382 -0
- package/dist/hitl-local-atestado.js +57 -0
- package/dist/hitl-local-receipt.js +328 -0
- package/dist/hitl-local.js +143 -0
- package/dist/hitl-lock.js +139 -0
- package/dist/hitl-lote.js +223 -0
- package/dist/hitl-native-offer.js +97 -0
- package/dist/hitl-native.js +65 -0
- package/dist/hitl-presentation.js +209 -0
- package/dist/hitl-public-receipt.js +176 -0
- package/dist/hitl-resumo.js +209 -0
- package/dist/hitl-sessions.js +475 -0
- package/dist/hitl.js +711 -0
- package/dist/horario.js +269 -0
- package/dist/hosts.js +198 -22
- package/dist/index.js +1736 -93
- package/dist/indice.js +99 -0
- package/dist/init.js +28 -3
- package/dist/integracoes-locais.js +17 -0
- package/dist/leases.js +65 -21
- package/dist/ledger-stats.js +272 -0
- package/dist/ledger.js +107 -2
- package/dist/licoes.js +215 -0
- package/dist/liveness.js +218 -0
- package/dist/maestro-actions.js +51 -0
- package/dist/maestro-authority.js +152 -0
- package/dist/maestro-cli.js +97 -0
- package/dist/maestro-contract.js +55 -0
- package/dist/maestro-discovery.js +132 -0
- package/dist/maestro-runtime.js +268 -0
- package/dist/maestro-snapshot.js +86 -0
- package/dist/maestro-sources.js +224 -0
- package/dist/manifest.js +165 -6
- package/dist/maquina.js +102 -0
- package/dist/master-audit.js +101 -0
- package/dist/master-batch.js +43 -0
- package/dist/master-digest.js +149 -0
- package/dist/master-migracao.js +155 -0
- package/dist/master.js +361 -77
- package/dist/mcp-artifacts.js +234 -0
- package/dist/mcp-git.js +433 -0
- package/dist/mcp-install.js +310 -0
- package/dist/mcp-maestro.js +25 -0
- package/dist/mcp-server.js +469 -0
- package/dist/mcp-ship.js +436 -0
- package/dist/mcp-verify.js +173 -0
- package/dist/memoria-humana.js +207 -0
- package/dist/memoria.js +314 -78
- package/dist/memory-migration.js +279 -0
- package/dist/memory-prospective.js +148 -0
- package/dist/modos-migracao.js +191 -0
- package/dist/modos.js +151 -15
- package/dist/monitor-lock.js +110 -0
- package/dist/objective.js +449 -0
- package/dist/ocupacao.js +267 -0
- package/dist/onboarding.js +303 -0
- package/dist/orkmind.js +389 -90
- package/dist/orquestracao.js +96 -69
- package/dist/phase.js +596 -150
- package/dist/playbook-capabilities.js +150 -0
- package/dist/playbook-contracts.js +188 -0
- package/dist/portfolio-context.js +61 -0
- package/dist/portfolio.js +180 -0
- package/dist/preflight.js +207 -0
- package/dist/process-audit.js +112 -0
- package/dist/project-state.js +93 -0
- package/dist/prompts.js +25 -5
- package/dist/prova-minima.js +112 -0
- package/dist/pulse-cadencia.js +163 -0
- package/dist/pulse-consentimento.js +260 -0
- package/dist/pulse-delivery.js +323 -0
- package/dist/pulse-resposta.js +542 -0
- package/dist/pulse.js +262 -0
- package/dist/ratelimit.js +35 -2
- package/dist/recall.js +80 -3
- package/dist/redacao-saida.js +45 -0
- package/dist/redacao-url.js +66 -0
- package/dist/retry.js +637 -115
- package/dist/roadmap-reservas.js +243 -0
- package/dist/runtime-ambiente.js +38 -0
- package/dist/runtime-context.js +215 -0
- package/dist/runtime-profiles.js +869 -0
- package/dist/runtimes.js +103 -0
- package/dist/sandbox.js +9 -0
- package/dist/session-events.js +203 -0
- package/dist/session-watcher-claude.js +637 -0
- package/dist/session-watcher.js +683 -0
- package/dist/sessoes-adopt.js +154 -0
- package/dist/sessoes-inventario.js +159 -0
- package/dist/sessoes.js +16 -35
- package/dist/setup.js +691 -0
- package/dist/ship.js +150 -15
- package/dist/slug.js +1 -1
- package/dist/thread-close.js +115 -0
- package/dist/thread.js +142 -28
- package/dist/tokens.js +1 -1
- package/dist/util.js +4 -2
- package/dist/verify-sandbox.js +265 -0
- package/dist/verify.js +270 -25
- package/dist/versao.js +60 -0
- package/dist/worktree.js +31 -2
- package/dist/write-activation.js +291 -0
- package/dist/yaml.js +2 -0
- package/eval/casos/onboarding.json +102 -0
- package/eval/casos/orkastery-bootstrap.json +35 -1
- package/eval/casos/scope-check-capability-map.json +45 -7
- package/eval/casos/ship-release.json +2 -2
- package/eval/fixtures/b0-slug-e-modos/caso.json +35 -22
- package/eval/fixtures/b2-master-log/caso.json +1 -1
- package/eval/fixtures/fx-adapter-editado-detectado/caso.json +19 -0
- package/eval/fixtures/fx-auto-quiet/caso.json +11 -0
- package/eval/fixtures/fx-blanket-approve/caso.json +10 -0
- package/eval/fixtures/fx-check-runtime-cruzado/caso.json +20 -0
- package/eval/fixtures/fx-codex-dry/caso.json +18 -0
- package/eval/fixtures/fx-donewhen-executavel/caso.json +15 -0
- package/eval/fixtures/fx-estado-dividido/caso.json +15 -0
- package/eval/fixtures/fx-fase-orfa/caso.json +116 -0
- package/eval/fixtures/fx-happy/caso.json +6 -4
- package/eval/fixtures/fx-hitl-latency/caso.json +20 -0
- package/eval/fixtures/fx-indice-reversao/caso.json +25 -0
- package/eval/fixtures/fx-listagem-abertas/caso.json +16 -0
- package/eval/fixtures/fx-maestro-bootstrap/caso.json +21 -0
- package/eval/fixtures/fx-modo-aposentado-escritor/caso.json +21 -0
- package/eval/fixtures/fx-modo-aposentado-leitor/caso.json +16 -0
- package/eval/fixtures/fx-objective-oscillation/caso.json +14 -0
- package/eval/fixtures/fx-omnicanal/caso.json +17 -0
- package/eval/fixtures/fx-sensores-runtime/caso.json +17 -0
- package/monitor/company-brain.cjs +17 -0
- package/monitor/pulse-scope.cjs +45 -0
- package/monitor/pulse.cron +18 -0
- package/monitor/varredura-pulse.sh +27 -0
- package/package.json +25 -4
- package/schemas/claims.schema.json +25 -0
- package/schemas/company-brain.schema.json +1158 -0
- package/schemas/creation-operation.schema.json +365 -0
- package/schemas/maestro-snapshot.schema.json +2716 -0
- package/skills/core/onboarding/SKILL.md +50 -0
- package/skills/core/orkastery-bootstrap/SKILL.md +95 -65
- package/skills/core/thread-state/SKILL.md +3 -1
- package/skills/governance/scope-check-capability-map/SKILL.md +17 -7
package/dist/retry.js
CHANGED
|
@@ -1,24 +1,4 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* Politica de retry TIPADA e retomada automatica (bloco B3).
|
|
4
|
-
*
|
|
5
|
-
* O B1 deu ao `ork` o MOTIVO tipado de cada reprovacao; o B2 deu a thread um estado
|
|
6
|
-
* retomavel em disco. O B3 e a camada que liga os dois: para cada motivo tipado existe
|
|
7
|
-
* UMA acao de retry deterministica, igual em todos os modos de conducao.
|
|
8
|
-
*
|
|
9
|
-
* Tres regras mandam aqui, e nenhuma delas e afrouxavel por modo:
|
|
10
|
-
*
|
|
11
|
-
* 1. **Custo nunca reexecuta.** `cost.violation` (despacho que seria redirecionado
|
|
12
|
-
* para provider pago) e o unico motivo sem retry automatico nenhum. Reexecutar
|
|
13
|
-
* violacao de custo e gastar de novo, e a licao dos US$ 16 esta no manifesto.
|
|
14
|
-
* 2. **O modo afrouxa a PAUSA, nunca a VERIFICACAO.** A politica e identica em
|
|
15
|
-
* `#Look` e em `#Auto`. O que muda e a AUTORIZACAO: num bloco de loop que pausa,
|
|
16
|
-
* a acao espera `ork gate approve`; num bloco sem pausa (`#Maestro`, `#Auto`) o
|
|
17
|
-
* `ork` executa sozinho e grava a decisao autonoma no ledger.
|
|
18
|
-
* 3. **O limite de escalacao pausa QUALQUER modo.** Estouradas as tentativas do
|
|
19
|
-
* manifesto pelo MESMO motivo na MESMA fase, a acao vira `escalar-humano`,
|
|
20
|
-
* inclusive em `#Auto`. E a invariante de escalacao tipada da secao 3.5.
|
|
21
|
-
*/
|
|
22
2
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
23
3
|
if (k2 === undefined) k2 = k;
|
|
24
4
|
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
@@ -61,6 +41,7 @@ exports.tabelaDaPolitica = tabelaDaPolitica;
|
|
|
61
41
|
exports.ultimaReprovacao = ultimaReprovacao;
|
|
62
42
|
exports.tentativasFeitas = tentativasFeitas;
|
|
63
43
|
exports.blocoPausa = blocoPausa;
|
|
44
|
+
exports.estadoTerminalDeRetry = estadoTerminalDeRetry;
|
|
64
45
|
exports.planejarRetry = planejarRetry;
|
|
65
46
|
exports.escalarEsforco = escalarEsforco;
|
|
66
47
|
exports.redespachar = redespachar;
|
|
@@ -69,24 +50,58 @@ exports.retomarPedido = retomarPedido;
|
|
|
69
50
|
exports.retomarFila = retomarFila;
|
|
70
51
|
exports.retomarPorId = retomarPorId;
|
|
71
52
|
exports.cancelarPedido = cancelarPedido;
|
|
53
|
+
exports.alvosDeFallback = alvosDeFallback;
|
|
54
|
+
exports.proximoAlvo = proximoAlvo;
|
|
55
|
+
exports.producaoNoIntervalo = producaoNoIntervalo;
|
|
72
56
|
exports.executarRetry = executarRetry;
|
|
73
57
|
exports.textoDoPlano = textoDoPlano;
|
|
74
58
|
exports.textoDoRetry = textoDoRetry;
|
|
75
59
|
exports.textoDaRetomada = textoDaRetomada;
|
|
60
|
+
const hitl_gates_1 = require("./hitl-gates");
|
|
61
|
+
const claude_bg_1 = require("./adapters/claude-bg");
|
|
62
|
+
/**
|
|
63
|
+
* Politica de retry TIPADA e retomada automatica (bloco B3).
|
|
64
|
+
*
|
|
65
|
+
* O B1 deu ao `ork` o MOTIVO tipado de cada reprovacao; o B2 deu a thread um estado
|
|
66
|
+
* retomavel em disco. O B3 e a camada que liga os dois: para cada motivo tipado existe
|
|
67
|
+
* UMA acao de retry deterministica, igual em todos os modos de conducao.
|
|
68
|
+
*
|
|
69
|
+
* Tres regras mandam aqui, e nenhuma delas e afrouxavel por modo:
|
|
70
|
+
*
|
|
71
|
+
* 1. **Custo nunca reexecuta.** `cost.violation` (despacho que seria redirecionado
|
|
72
|
+
* para provider pago) e o unico motivo sem retry automatico nenhum. Reexecutar
|
|
73
|
+
* violacao de custo e gastar de novo, e a politica `subscription-only` esta no manifesto.
|
|
74
|
+
* 2. **O modo afrouxa a PAUSA, nunca a VERIFICACAO.** A politica e identica em
|
|
75
|
+
* `#Classic` e em `#Auto`. O que muda e a AUTORIZACAO: num bloco de loop que pausa,
|
|
76
|
+
* a acao espera `ork gate approve`; num bloco sem pausa (`#Maestro`, `#Auto`) o
|
|
77
|
+
* `ork` executa sozinho e grava a decisao autonoma no ledger.
|
|
78
|
+
* 3. **O limite de escalacao pausa QUALQUER modo.** Estouradas as tentativas do
|
|
79
|
+
* manifesto pelo MESMO motivo na MESMA fase, a acao vira `escalar-humano`,
|
|
80
|
+
* inclusive em `#Auto`. E a invariante de escalacao tipada da secao 3.5.
|
|
81
|
+
*/
|
|
76
82
|
const fs = __importStar(require("node:fs"));
|
|
77
83
|
const path = __importStar(require("node:path"));
|
|
78
|
-
const adapter = __importStar(require("./adapters/claude-bg"));
|
|
79
84
|
const fix_1 = require("./fix");
|
|
85
|
+
const runtimes_1 = require("./runtimes");
|
|
86
|
+
const setup_1 = require("./setup");
|
|
80
87
|
const gates_1 = require("./gates");
|
|
81
88
|
const ledger_1 = require("./ledger");
|
|
82
89
|
const phase_1 = require("./phase");
|
|
90
|
+
const runtime_context_1 = require("./runtime-context");
|
|
83
91
|
const slug_1 = require("./slug");
|
|
84
92
|
const policies_1 = require("./policies");
|
|
85
93
|
const ratelimit_1 = require("./ratelimit");
|
|
94
|
+
const session_watcher_claude_1 = require("./session-watcher-claude");
|
|
95
|
+
const runtime_profiles_1 = require("./runtime-profiles");
|
|
86
96
|
const thread_1 = require("./thread");
|
|
87
97
|
const tokens_1 = require("./tokens");
|
|
88
98
|
const util_1 = require("./util");
|
|
89
99
|
const worktree_1 = require("./worktree");
|
|
100
|
+
const delegation_1 = require("./delegation");
|
|
101
|
+
const gates_2 = require("./gates");
|
|
102
|
+
const horario_1 = require("./horario");
|
|
103
|
+
const conducao_1 = require("./conducao");
|
|
104
|
+
const conducao_texto_1 = require("./conducao-texto");
|
|
90
105
|
/**
|
|
91
106
|
* Escada de esforco da 2a tentativa em diante.
|
|
92
107
|
*
|
|
@@ -136,11 +151,22 @@ exports.POLITICA_DE_RETRY = {
|
|
|
136
151
|
porque: 'policy com severidade block reprova em qualquer modo: reexecutar sozinho seria a maquina revogando a policy do manifesto',
|
|
137
152
|
correcao: 'corrija a violacao no pedido/manifesto; policy block nao se resolve por repeticao',
|
|
138
153
|
},
|
|
154
|
+
'runtime.autoconferencia': {
|
|
155
|
+
motivo: 'runtime.autoconferencia',
|
|
156
|
+
// `escalar-humano` e nao `sem-retry`: `sem-retry` e o lugar reservado a violacao
|
|
157
|
+
// de CUSTO, e o teste do bloco B3 guarda essa exclusividade de proposito. Aqui a
|
|
158
|
+
// maquina nao esta proibida de agir, ela esta sem o que escolher sozinha: quem
|
|
159
|
+
// decide em que runtime o CHECK roda e quem conduz a thread.
|
|
160
|
+
acao: 'escalar-humano',
|
|
161
|
+
automatica: false,
|
|
162
|
+
porque: 'repetir o despacho no MESMO runtime daria o mesmo resultado: o que falta nao e tentativa, e um validador que nao seja quem executou. Escolher o outro runtime e decisao de conducao, nao retry',
|
|
163
|
+
correcao: 'despache o CHECK em outro runtime (`ork phase run <thread> CHECK --runtime <outro>`), ou tire a exigencia de validacao cruzada da thread se ela nao se justifica',
|
|
164
|
+
},
|
|
139
165
|
'cost.violation': {
|
|
140
166
|
motivo: 'cost.violation',
|
|
141
167
|
acao: 'sem-retry',
|
|
142
168
|
automatica: false,
|
|
143
|
-
porque: 'violacao de CUSTO nunca recebe retry automatico: cada reexecucao gastaria de novo pelo provider pago (
|
|
169
|
+
porque: 'violacao de CUSTO nunca recebe retry automatico: cada reexecucao gastaria de novo pelo provider pago (subscription-only e regra de codigo, nao lembrete)',
|
|
144
170
|
correcao: 'tire do ambiente a variavel que redireciona o despacho e rode a fase de novo a mao, com o gasto sob os olhos de um humano',
|
|
145
171
|
},
|
|
146
172
|
'verify.regression': {
|
|
@@ -157,6 +183,27 @@ exports.POLITICA_DE_RETRY = {
|
|
|
157
183
|
porque: 'o comando falha sem baseline para separar regressao de divida: a correcao dirigida conserta ou grava a baseline, mas nao chuta de quem e a culpa',
|
|
158
184
|
correcao: 'ork fix open <thread>, ou ork verify <thread> --baseline antes do proximo GO',
|
|
159
185
|
},
|
|
186
|
+
'verify.timeout': {
|
|
187
|
+
motivo: 'verify.timeout',
|
|
188
|
+
acao: 'reexecutar',
|
|
189
|
+
automatica: true,
|
|
190
|
+
porque: 'o prazo estourou antes de o comando terminar: a prova nao chegou ao fim, e carga de maquina nao e defeito. A reexecucao e completa, e o limite de escalacao do manifesto impede repetir para sempre',
|
|
191
|
+
correcao: 'ork verify <thread> de novo; se estourar sempre, suba verify.timeout_ms no manifesto ou divida o comando',
|
|
192
|
+
},
|
|
193
|
+
'verify.sem-veredito': {
|
|
194
|
+
motivo: 'verify.sem-veredito',
|
|
195
|
+
acao: 'reexecutar',
|
|
196
|
+
automatica: true,
|
|
197
|
+
porque: 'um comando nao chegou a rodar ou o produto mudou no meio da rodada: nao ha veredito sobre ele, e a prova certa e rodar de novo, inteira',
|
|
198
|
+
correcao: 'ork verify <thread> de novo, sem editar a worktree durante a rodada',
|
|
199
|
+
},
|
|
200
|
+
'ci.failed': {
|
|
201
|
+
motivo: 'ci.failed',
|
|
202
|
+
acao: 'escalar-humano',
|
|
203
|
+
automatica: false,
|
|
204
|
+
porque: 'o recibo pertence ao provedor e ao SHA candidato: repetir uma fase não cria nem altera legitimamente esse resultado',
|
|
205
|
+
correcao: 'publique a candidata, aguarde o check obrigatório e repita o SHIP; se reprovou, corrija a causa registrada no runner',
|
|
206
|
+
},
|
|
160
207
|
'runtime.unavailable': {
|
|
161
208
|
motivo: 'runtime.unavailable',
|
|
162
209
|
acao: 'reexecutar',
|
|
@@ -164,6 +211,11 @@ exports.POLITICA_DE_RETRY = {
|
|
|
164
211
|
porque: 'falha de infraestrutura no despacho nao e falha de conteudo: o MESMO prompt, com o mesmo sha256, e redespachado sem alterar uma virgula',
|
|
165
212
|
correcao: 'ork retry run <thread> redespacha o prompt ja gravado em disco',
|
|
166
213
|
},
|
|
214
|
+
'runtime.silencio': {
|
|
215
|
+
motivo: 'runtime.silencio', acao: 'reexecutar', automatica: true,
|
|
216
|
+
porque: 'fase sem heartbeat: retomar o despacho original com hash conferido e limite de tentativas',
|
|
217
|
+
correcao: 'ork retry run <thread> --motivo runtime.silencio',
|
|
218
|
+
},
|
|
167
219
|
'runtime.rate-limited': {
|
|
168
220
|
motivo: 'runtime.rate-limited',
|
|
169
221
|
acao: 'esperar-janela',
|
|
@@ -171,6 +223,24 @@ exports.POLITICA_DE_RETRY = {
|
|
|
171
223
|
porque: 'o limite de uso tem HORA de volta: a fase entra na fila duravel e e retomada na janela seguinte, sem humano no meio e sem gastar por fora da assinatura',
|
|
172
224
|
correcao: 'ork retry list mostra a fila; ork retry resume retoma o que ja liberou',
|
|
173
225
|
},
|
|
226
|
+
// I-33 (D5, D11): a falha e da CONTA. O perfil sai do rodizio e o MESMO prompt vai ao proximo
|
|
227
|
+
// perfil ativo, depois ao runtime de fallback do bloco, e so por ultimo a fila duravel. A
|
|
228
|
+
// rotacao so redespacha quando a prova do `ork` confirma que o intervalo nao produziu nada;
|
|
229
|
+
// producao parcial sob cota esgotada vira `human.pending`, nunca redespacho sobre a worktree.
|
|
230
|
+
'runtime.quota-exhausted': {
|
|
231
|
+
motivo: 'runtime.quota-exhausted',
|
|
232
|
+
acao: 'reexecutar',
|
|
233
|
+
automatica: true,
|
|
234
|
+
porque: 'a cota ou os creditos da CONTA acabaram, nao a infraestrutura: o perfil sai do rodizio ate o prazo e o MESMO prompt, com o mesmo sha256, segue no proximo perfil, no runtime de fallback ou na fila ate o menor prazo',
|
|
235
|
+
correcao: 'ork accounts list mostra o perfil esgotado; ork retry run <thread> rotaciona o prompt ja gravado',
|
|
236
|
+
},
|
|
237
|
+
'runtime.auth-missing': {
|
|
238
|
+
motivo: 'runtime.auth-missing',
|
|
239
|
+
acao: 'reexecutar',
|
|
240
|
+
automatica: true,
|
|
241
|
+
porque: 'a conta do runtime perdeu a autenticacao: o perfil nunca mais recebe despacho ate o login ser refeito pelo proprio CLI, e o MESMO prompt segue no proximo perfil ou no runtime de fallback',
|
|
242
|
+
correcao: 'ork accounts check confere o login de cada perfil; ork retry run <thread> rotaciona o prompt ja gravado',
|
|
243
|
+
},
|
|
174
244
|
'tree.blocked': {
|
|
175
245
|
motivo: 'tree.blocked',
|
|
176
246
|
acao: 'sincronizar-worktree',
|
|
@@ -185,6 +255,24 @@ exports.POLITICA_DE_RETRY = {
|
|
|
185
255
|
porque: 'o lease e de outra thread e vai ser liberado: a fila ja serializa, entao a acao e tentar de novo quando chegar a vez, nunca furar a fila',
|
|
186
256
|
correcao: 'ork lease list mostra a fila; a vez chega sem ninguem forcar',
|
|
187
257
|
},
|
|
258
|
+
// I-36 (T6): a vez chega quando a conducao atual terminar. Redespachar agora so recebe a mesma recusa,
|
|
259
|
+
// e passar na frente de quem conduz e exatamente o incidente de 19/09/2026.
|
|
260
|
+
'conducao.em-andamento': {
|
|
261
|
+
motivo: 'conducao.em-andamento',
|
|
262
|
+
acao: 'esperar-janela',
|
|
263
|
+
automatica: true,
|
|
264
|
+
porque: 'outra conducao executa na mesma worktree agora: a vez chega quando ela terminar, e furar a fila e o incidente de 19/09/2026',
|
|
265
|
+
correcao: 'ork conducao status <thread> mostra quem conduz; repita o pedido com --esperar <min> para seguir sozinho quando liberar',
|
|
266
|
+
},
|
|
267
|
+
// I-41 (D10): formato e defeito de quem escreveu o pedido, e a spec dirigida conserta.
|
|
268
|
+
// Escalar isto para o dono seria pedir que ele revise a sintaxe do robo.
|
|
269
|
+
'hitl.formato': {
|
|
270
|
+
motivo: 'hitl.formato',
|
|
271
|
+
acao: 'corrigir-dirigido',
|
|
272
|
+
automatica: true,
|
|
273
|
+
porque: 'o pedido HITL saiu fora do formato obrigatorio: quem errou foi o emissor, e a correcao e reemitir com alternativas rotuladas, consequencia por alternativa e exatamente uma recomendada com o porque',
|
|
274
|
+
correcao: 'ork fix open <thread> abre a rodada com a spec exata do formato',
|
|
275
|
+
},
|
|
188
276
|
'human.pending': {
|
|
189
277
|
motivo: 'human.pending',
|
|
190
278
|
acao: 'escalar-humano',
|
|
@@ -245,6 +333,9 @@ function tentativasFeitas(raiz, threadId, fase, motivo) {
|
|
|
245
333
|
function blocoPausa(thread, fase) {
|
|
246
334
|
return (0, thread_1.blocoDaThread)(thread, fase).pausa;
|
|
247
335
|
}
|
|
336
|
+
function estadoTerminalDeRetry(estado) {
|
|
337
|
+
return ['completed', 'failed', 'stopped', 'cancelled', 'interrupted', 'terminated'].includes(estado.trim().toLowerCase());
|
|
338
|
+
}
|
|
248
339
|
/**
|
|
249
340
|
* Calcula o plano de retry SEM executar nada.
|
|
250
341
|
*
|
|
@@ -327,10 +418,14 @@ function planejarRetry(carregado, threadId, opcoes = {}) {
|
|
|
327
418
|
const effort = escala ? escalarEsforco(effortBase, tentativas) : effortBase;
|
|
328
419
|
const acao = escala ? 'escalar-esforco' : politica.acao;
|
|
329
420
|
const pausa = blocoPausa(thread, fase);
|
|
330
|
-
const
|
|
421
|
+
const delegacao = (0, delegation_1.avaliarDelegacao)(manifesto, { thread: threadId, modo: thread.modo, fase,
|
|
422
|
+
escopo: 'premissas', conteudo: detalhe + '\n' + (0, delegation_1.conteudoDePremissas)(raiz, threadId) });
|
|
423
|
+
const autorizado = delegacao.permitida || (0, gates_2.aprovacoesHumanas)(raiz, threadId).some(e => e.fase === fase && e.autorizadoPor === opcoes.autorizadoPor);
|
|
331
424
|
let bloqueio = null;
|
|
332
425
|
let automatica = politica.automatica;
|
|
333
426
|
let razao = politica.porque;
|
|
427
|
+
if (delegacao.permitida && politica.automatica)
|
|
428
|
+
razao += `; ${delegacao.razao}; delegado ${delegacao.delegado}; evidência ${delegacao.evidencia}`;
|
|
334
429
|
if (!politica.automatica) {
|
|
335
430
|
automatica = false;
|
|
336
431
|
bloqueio = 'politica.nao-automatica';
|
|
@@ -345,21 +440,18 @@ function planejarRetry(carregado, threadId, opcoes = {}) {
|
|
|
345
440
|
`(${(0, thread_1.blocoDaThread)(thread, fase).pausaSobre}): a acao ${acao} espera autorizacao humana. ` +
|
|
346
441
|
'O modo afrouxa a pausa, nunca a verificacao.';
|
|
347
442
|
}
|
|
443
|
+
if (motivo === 'runtime.silencio') {
|
|
444
|
+
const despacho = ultimoDespachoFalho(raiz, threadId, fase, true);
|
|
445
|
+
const prova = opcoes.estadoDaSessao;
|
|
446
|
+
if (!prova || prova.sessionId !== despacho?.sessionId || !estadoTerminalDeRetry(prova.estado)) {
|
|
447
|
+
automatica = false;
|
|
448
|
+
bloqueio = 'politica.nao-automatica';
|
|
449
|
+
razao = 'runtime.silencio exige prova terminal atual da mesma sessao; ausencia ou silencio nao provam morte';
|
|
450
|
+
}
|
|
451
|
+
}
|
|
348
452
|
return {
|
|
349
|
-
thread: threadId,
|
|
350
|
-
|
|
351
|
-
fase,
|
|
352
|
-
motivo,
|
|
353
|
-
detalhe,
|
|
354
|
-
politica,
|
|
355
|
-
acao,
|
|
356
|
-
tentativas,
|
|
357
|
-
limite,
|
|
358
|
-
effort,
|
|
359
|
-
effortAnterior,
|
|
360
|
-
automatica,
|
|
361
|
-
bloqueio,
|
|
362
|
-
razao,
|
|
453
|
+
thread: threadId, modo: thread.modo, fase, motivo, detalhe, politica, acao, tentativas,
|
|
454
|
+
limite, effort, effortAnterior, automatica, bloqueio, razao,
|
|
363
455
|
};
|
|
364
456
|
}
|
|
365
457
|
/** O esforco depois de `n` escaladas a partir do esforco base do manifesto. */
|
|
@@ -380,12 +472,19 @@ function escalarEsforco(base, degraus) {
|
|
|
380
472
|
* de provider pago enquanto a fase esperava, a retomada recusa em vez de gastar.
|
|
381
473
|
*/
|
|
382
474
|
function redespachar(carregado, thread, fase, promptRelativo, sha, opcoes = {}) {
|
|
475
|
+
const run = () => redespacharSobLock(carregado, (0, thread_1.lerThread)(carregado.raiz, thread.id), fase, promptRelativo, sha, opcoes);
|
|
476
|
+
return opcoes.dryRun ? run() : (0, hitl_gates_1.comLockHitl)(carregado.raiz, thread.id, run);
|
|
477
|
+
}
|
|
478
|
+
function redespacharSobLock(carregado, thread, fase, promptRelativo, sha, opcoes = {}) {
|
|
383
479
|
const { raiz, manifesto } = carregado;
|
|
384
480
|
const absoluto = path.isAbsolute(promptRelativo)
|
|
385
481
|
? promptRelativo
|
|
386
482
|
: path.join(raiz, promptRelativo);
|
|
387
483
|
const slug = opcoes.slug ?? (0, phase_1.slugDaSessao)(thread, fase);
|
|
388
484
|
const vazio = { slug, sessionId: null, verificada: false, sinal: null, comando: [] };
|
|
485
|
+
const erroDeEstado = (0, phase_1.estadoParaDespacho)(raiz, thread, opcoes.dryRun);
|
|
486
|
+
if (erroDeEstado)
|
|
487
|
+
return { ...vazio, ok: false, motivo: 'tree.blocked', detalhe: erroDeEstado, dryRun: opcoes.dryRun === true };
|
|
389
488
|
if (!fs.existsSync(absoluto)) {
|
|
390
489
|
return {
|
|
391
490
|
...vazio,
|
|
@@ -424,73 +523,171 @@ function redespachar(carregado, thread, fase, promptRelativo, sha, opcoes = {})
|
|
|
424
523
|
});
|
|
425
524
|
return { ...vazio, ok: false, motivo, detalhe, dryRun: opcoes.dryRun === true };
|
|
426
525
|
}
|
|
427
|
-
|
|
428
|
-
//
|
|
429
|
-
//
|
|
430
|
-
const
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
526
|
+
// I-36 (T6): validado o pedido, a retomada toma a conducao antes de redespachar, como o
|
|
527
|
+
// `ork phase run`. A mesma fase com o mesmo prompt de quem ja conduz nao abre sessao nova;
|
|
528
|
+
// outro pedido espera a vez.
|
|
529
|
+
const identidade = (0, runtime_context_1.novaIdentidadeDeDespacho)(thread.id, fase);
|
|
530
|
+
const canal = opcoes.canal ?? (0, conducao_1.canalDoProcesso)();
|
|
531
|
+
const doBlocoDaConducao = (0, setup_1.limitesDoBloco)(manifesto, (0, setup_1.lerSetup)(raiz), thread.modo, fase);
|
|
532
|
+
const pedidoDeConducao = { canal, correlacao: null, operacao: 'retry.run', fase, promptSha256: sha,
|
|
533
|
+
identidade: identidade.dispatchId, prazoMs: (0, phase_1.prazoDaSessao)(doBlocoDaConducao) };
|
|
534
|
+
let conducao = null;
|
|
535
|
+
if (!opcoes.dryRun) {
|
|
536
|
+
const tomada = (0, conducao_1.tomarConducao)(raiz, thread.id, pedidoDeConducao);
|
|
537
|
+
if (!tomada.ok) {
|
|
538
|
+
if (tomada.idempotente && tomada.atual) {
|
|
539
|
+
(0, ledger_1.registrar)((0, thread_1.dirThread)(raiz, thread.id), thread.id, ledger_1.TIPOS_DE_EVENTO.despachoIdempotente, { fase, promptSha256: sha, canal,
|
|
540
|
+
sessionId: tomada.atual.sessao, origem: opcoes.origem ?? 'retry',
|
|
541
|
+
razao: 'mesma fase e mesmo prompt de quem ja conduz: a sessao em andamento atende a retomada, sem sessao nova' });
|
|
542
|
+
return { ...vazio, ok: true, sessionId: tomada.atual.sessao, motivo: null, dryRun: false,
|
|
543
|
+
detalhe: `a sessao ${String(tomada.atual.sessao).slice(0, 8)} ja conduz a fase ${fase} com este prompt: nada foi redespachado` };
|
|
544
|
+
}
|
|
545
|
+
const recusa = (0, conducao_1.recusaDeConducao)(thread.id, tomada.atual, pedidoDeConducao);
|
|
546
|
+
(0, conducao_1.registrarRecusa)(raiz, recusa);
|
|
547
|
+
return { ...vazio, ok: false, motivo: 'conducao.em-andamento', detalhe: recusa.texto, dryRun: false };
|
|
548
|
+
}
|
|
549
|
+
conducao = tomada;
|
|
550
|
+
}
|
|
551
|
+
try {
|
|
552
|
+
const cwd = opcoes.cwd ?? thread.worktree ?? raiz;
|
|
553
|
+
// Mesma resolucao do `ork phase run`: a retomada carimba no ledger o trio que ela de
|
|
554
|
+
// fato despachou, inclusive quando o pedido da fila trazia um modelo proprio. O setup
|
|
555
|
+
// do bloco (feature #setup) vale aqui tambem: a fase retomada abre no MESMO runtime
|
|
556
|
+
// que a fase original abriria.
|
|
557
|
+
const doBloco = (0, setup_1.configDoBloco)((0, setup_1.lerSetup)(raiz), thread.modo, fase);
|
|
558
|
+
const { runtime, model, effort } = (0, phase_1.resolverDespacho)(manifesto, {
|
|
559
|
+
runtime: opcoes.runtime ?? undefined,
|
|
560
|
+
model: opcoes.model ?? undefined,
|
|
561
|
+
effort: opcoes.effort ?? undefined,
|
|
562
|
+
}, doBloco);
|
|
563
|
+
const rt = (0, runtimes_1.resolverRuntime)(runtime);
|
|
564
|
+
// D14 (GO-FIX 2): a retomada claude-bg abre com a mesma colaboração e o mesmo contexto de
|
|
565
|
+
// runtime do `ork phase run`; sem eles, o PLAN retomado saía sem negar Edit, Write e
|
|
566
|
+
// NotebookEdit e sem a allowlist do núcleo. O ramo Codex não muda.
|
|
567
|
+
let contextoRuntime;
|
|
568
|
+
if (runtime === 'claude-bg') {
|
|
569
|
+
try {
|
|
570
|
+
contextoRuntime = (0, runtime_context_1.contextoDoProjeto)(raiz, runtime, cwd, thread.id);
|
|
571
|
+
}
|
|
572
|
+
catch (e) {
|
|
573
|
+
return { ...vazio, ok: false, motivo: 'runtime.unavailable',
|
|
574
|
+
detalhe: `runtime.unavailable: ${e.message}`, dryRun: opcoes.dryRun === true };
|
|
575
|
+
}
|
|
576
|
+
if (contextoRuntime)
|
|
577
|
+
contextoRuntime.identidade = identidade;
|
|
578
|
+
}
|
|
579
|
+
// I-33 (D4, D7): a retomada escolhe o perfil como o `ork phase run`, com o login conferido.
|
|
580
|
+
let escolha;
|
|
581
|
+
try {
|
|
582
|
+
escolha = (0, phase_1.perfilParaDespacho)(carregado, thread, fase, runtime, { perfil: opcoes.perfil ?? undefined, dryRun: opcoes.dryRun,
|
|
583
|
+
origem: opcoes.origem ?? 'retry' });
|
|
584
|
+
}
|
|
585
|
+
catch (e) {
|
|
586
|
+
escolha = { perfil: null, configurados: 0, erro: e.message };
|
|
587
|
+
}
|
|
588
|
+
if (escolha.erro) {
|
|
589
|
+
const motivo = escolha.motivo ?? 'runtime.unavailable';
|
|
590
|
+
const prazo = motivo === 'runtime.quota-exhausted' ? (0, runtime_profiles_1.prazoDoRuntime)((0, runtime_profiles_1.lerPerfisComContas)(raiz), runtime, (0, runtime_profiles_1.politicaDeRotacao)(manifesto)) : null;
|
|
591
|
+
return { ...vazio, ok: false, motivo, detalhe: `${motivo}: ${escolha.erro}`, dryRun: opcoes.dryRun === true,
|
|
592
|
+
sinal: prazo ? { resetEm: prazo, fonte: 'iso', trecho: `menor esgotadoAte dos perfis ${runtime}` } : null };
|
|
593
|
+
}
|
|
594
|
+
const perfil = escolha.perfil ?? undefined;
|
|
595
|
+
// I-33 (N1): o HEAD do GO codex sai antes do despacho, como no `ork phase run`.
|
|
596
|
+
const headNoDespacho = fase === 'GO' && runtime === 'codex' && !opcoes.dryRun ? (0, session_watcher_claude_1.headDaWorktree)(cwd) : undefined;
|
|
597
|
+
const resultado = rt.despachar({
|
|
598
|
+
prompt,
|
|
599
|
+
nome: slug,
|
|
600
|
+
cwd,
|
|
601
|
+
model,
|
|
602
|
+
effort,
|
|
603
|
+
dryRun: opcoes.dryRun,
|
|
604
|
+
sandbox: manifesto.runtime.sandbox,
|
|
605
|
+
logDir: path.join((0, thread_1.dirThread)(raiz, thread.id), 'sessoes'),
|
|
606
|
+
vinculo: { thread: thread.id, fase, promptSha256: sha },
|
|
607
|
+
...(perfil ? { perfil } : {}),
|
|
608
|
+
...(runtime === 'claude-bg' ? { contextoRuntime, ...(fase === 'PLAN' ? { colaboracao: 'plan' } : {}) } : {}),
|
|
609
|
+
// I-36 (D4): a sessao retomada herda a identidade do despacho e o canal, como no `ork phase run`.
|
|
610
|
+
ambienteExtra: (0, conducao_1.ambienteDaConducao)(identidade.dispatchId, thread.id, canal),
|
|
611
|
+
});
|
|
612
|
+
if (opcoes.dryRun) {
|
|
613
|
+
return {
|
|
614
|
+
ok: true,
|
|
615
|
+
slug,
|
|
616
|
+
sessionId: null,
|
|
617
|
+
verificada: false,
|
|
618
|
+
motivo: null,
|
|
619
|
+
detalhe: 'ensaio (--dry-run): comando montado, nada despachado',
|
|
620
|
+
sinal: null,
|
|
621
|
+
comando: resultado.comando,
|
|
622
|
+
dryRun: true,
|
|
623
|
+
};
|
|
624
|
+
}
|
|
625
|
+
if (!resultado.ok || !resultado.sessionId) {
|
|
626
|
+
(0, ledger_1.registrar)((0, thread_1.dirThread)(raiz, thread.id), thread.id, 'phase_dispatch_failed', { fase, runtime, slug, cwd,
|
|
627
|
+
promptPath: absoluto, promptSha256: sha, controlador: resultado.controlador, model, effort,
|
|
628
|
+
erro: resultado.erro ?? 'runtime.unavailable: sem sessionId', origem: 'retry', ...(perfil ? { perfil } : {}) });
|
|
629
|
+
const sinal = resultado.rateLimit ?? null;
|
|
630
|
+
// I-33 (D5): a conta recusou o redespacho; o perfil sai do rodizio aqui, onde a evidencia esta.
|
|
631
|
+
if (resultado.falhaDeConta) {
|
|
632
|
+
try {
|
|
633
|
+
(0, ratelimit_1.marcarContaDaFalha)(carregado, perfil, resultado.falhaDeConta);
|
|
634
|
+
}
|
|
635
|
+
catch { /* a rotacao segue pelo motivo tipado */ }
|
|
636
|
+
}
|
|
637
|
+
return {
|
|
638
|
+
ok: false,
|
|
639
|
+
slug,
|
|
640
|
+
sessionId: null,
|
|
641
|
+
verificada: false,
|
|
642
|
+
// I-33 (D11b): falha de conta reconhecida na saida e o motivo mais especifico.
|
|
643
|
+
motivo: resultado.falhaDeConta?.motivo ?? (sinal ? 'runtime.rate-limited' : 'runtime.unavailable'),
|
|
644
|
+
detalhe: resultado.erro ?? 'sem sessionId na saida do runtime',
|
|
645
|
+
sinal,
|
|
646
|
+
falhaDeConta: resultado.falhaDeConta ?? null,
|
|
647
|
+
perfil: perfil ?? null,
|
|
648
|
+
comando: resultado.comando,
|
|
649
|
+
controlador: resultado.controlador,
|
|
650
|
+
dryRun: false,
|
|
651
|
+
};
|
|
652
|
+
}
|
|
653
|
+
const ctx = {
|
|
654
|
+
identidade,
|
|
655
|
+
canal,
|
|
656
|
+
...(conducao ? { conducao } : {}),
|
|
657
|
+
prazoDaSessaoMs: pedidoDeConducao.prazoMs,
|
|
658
|
+
raiz,
|
|
659
|
+
thread,
|
|
660
|
+
fase,
|
|
661
|
+
slug,
|
|
662
|
+
promptPath: absoluto,
|
|
663
|
+
promptSha256: sha,
|
|
664
|
+
runtime,
|
|
665
|
+
cwd,
|
|
666
|
+
model,
|
|
667
|
+
effort,
|
|
668
|
+
origem: opcoes.origem ?? 'retry',
|
|
669
|
+
...(perfil ? { perfil } : {}),
|
|
670
|
+
...(headNoDespacho !== undefined ? { headNoDespacho } : {}),
|
|
671
|
+
};
|
|
672
|
+
(0, phase_1.concluirDespacho)(ctx, resultado.sessionId, resultado.verificada, resultado.comando, rt.fonteVerificacao, resultado.controlador);
|
|
443
673
|
return {
|
|
444
674
|
ok: true,
|
|
445
675
|
slug,
|
|
446
|
-
sessionId:
|
|
447
|
-
verificada:
|
|
676
|
+
sessionId: resultado.sessionId,
|
|
677
|
+
verificada: resultado.verificada,
|
|
448
678
|
motivo: null,
|
|
449
|
-
detalhe:
|
|
679
|
+
detalhe: `sessao ${resultado.sessionId} despachada com o mesmo prompt sha256 ${sha.slice(0, 12)}` +
|
|
680
|
+
(perfil ? ` no perfil ${perfil.id} (${runtime})` : ''),
|
|
450
681
|
sinal: null,
|
|
451
|
-
|
|
452
|
-
dryRun: true,
|
|
453
|
-
};
|
|
454
|
-
}
|
|
455
|
-
if (!resultado.ok || !resultado.sessionId) {
|
|
456
|
-
const sinal = resultado.rateLimit ?? null;
|
|
457
|
-
return {
|
|
458
|
-
ok: false,
|
|
459
|
-
slug,
|
|
460
|
-
sessionId: null,
|
|
461
|
-
verificada: false,
|
|
462
|
-
motivo: sinal ? 'runtime.rate-limited' : 'runtime.unavailable',
|
|
463
|
-
detalhe: resultado.erro ?? 'sem sessionId na saida do runtime',
|
|
464
|
-
sinal,
|
|
682
|
+
perfil: perfil ?? null,
|
|
465
683
|
comando: resultado.comando,
|
|
466
684
|
dryRun: false,
|
|
467
685
|
};
|
|
468
686
|
}
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
slug,
|
|
474
|
-
promptPath: absoluto,
|
|
475
|
-
promptSha256: sha,
|
|
476
|
-
runtime: manifesto.runtime.adapter,
|
|
477
|
-
cwd,
|
|
478
|
-
model,
|
|
479
|
-
effort,
|
|
480
|
-
origem: opcoes.origem ?? 'retry',
|
|
481
|
-
};
|
|
482
|
-
(0, phase_1.concluirDespacho)(ctx, resultado.sessionId, resultado.verificada, resultado.comando);
|
|
483
|
-
return {
|
|
484
|
-
ok: true,
|
|
485
|
-
slug,
|
|
486
|
-
sessionId: resultado.sessionId,
|
|
487
|
-
verificada: resultado.verificada,
|
|
488
|
-
motivo: null,
|
|
489
|
-
detalhe: `sessao ${resultado.sessionId} despachada com o mesmo prompt sha256 ${sha.slice(0, 12)}`,
|
|
490
|
-
sinal: null,
|
|
491
|
-
comando: resultado.comando,
|
|
492
|
-
dryRun: false,
|
|
493
|
-
};
|
|
687
|
+
finally {
|
|
688
|
+
// Retomada que nao virou sessao devolve a conducao; a que virou ja a entregou a sessao.
|
|
689
|
+
conducao?.liberar();
|
|
690
|
+
}
|
|
494
691
|
}
|
|
495
692
|
// ---------------------------------------------------------------------------
|
|
496
693
|
// Os 3 playbooks de recuperacao, em codigo.
|
|
@@ -596,14 +793,25 @@ function retomarPedido(carregado, pedidoOriginal, opcoes = {}) {
|
|
|
596
793
|
const slug = escolha.playbook === 'nova-sessao'
|
|
597
794
|
? (0, slug_1.proximaRotacao)(pedido.slug, [...thread.sessoes.map((s) => s.slug), pedido.slug])
|
|
598
795
|
: pedido.slug;
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
796
|
+
// I-33 (R3, D15/A4): pedido da conta retoma no primeiro runtime, original ou da ordem de fallback,
|
|
797
|
+
// cujo perfil da vez voltou: o prazo que liberou a fila pode ter sido o do fallback. Pedido antigo,
|
|
798
|
+
// sem os campos, segue igual.
|
|
799
|
+
const doPedido = pedido;
|
|
800
|
+
const alvo = alvoDaRetomada(carregado, thread, doPedido);
|
|
801
|
+
const r = !alvo.destino
|
|
802
|
+
? { ok: false, slug, sessionId: null, verificada: false, motivo: doPedido.motivo ?? 'runtime.quota-exhausted',
|
|
803
|
+
detalhe: `${doPedido.motivo ?? 'runtime.quota-exhausted'}: nenhum perfil da vez disponivel em ${alvo.runtimes.join(', ')}`,
|
|
804
|
+
sinal: null, comando: [], dryRun: opcoes.dryRun === true }
|
|
805
|
+
: redespachar(carregado, thread, pedido.fase, pedido.promptPath, pedido.promptSha256, {
|
|
806
|
+
slug,
|
|
807
|
+
runtime: alvo.runtime,
|
|
808
|
+
perfil: alvo.perfil ?? doPedido.perfil ?? null,
|
|
809
|
+
model: alvo.model,
|
|
810
|
+
effort: alvo.effort,
|
|
811
|
+
cwd: pedido.cwd,
|
|
812
|
+
origem: 'retry.rate-limit',
|
|
813
|
+
dryRun: opcoes.dryRun,
|
|
814
|
+
});
|
|
607
815
|
(0, ledger_1.registrar)(dir, thread.id, ledger_1.TIPOS_DE_EVENTO.retryTentado, {
|
|
608
816
|
fase: pedido.fase,
|
|
609
817
|
motivo: 'runtime.rate-limited',
|
|
@@ -638,6 +846,8 @@ function retomarPedido(carregado, pedidoOriginal, opcoes = {}) {
|
|
|
638
846
|
playbook: escolha.playbook,
|
|
639
847
|
slug,
|
|
640
848
|
sessionId: r.sessionId,
|
|
849
|
+
...(alvo.destino && alvo.runtime !== null ? { runtime: alvo.runtime } : {}),
|
|
850
|
+
...(r.perfil ? { perfil: r.perfil.id } : {}),
|
|
641
851
|
promptSha256: pedido.promptSha256,
|
|
642
852
|
esperouAte: pedido.liberaEm,
|
|
643
853
|
janelaEstimada: pedido.janelaEstimada,
|
|
@@ -666,12 +876,21 @@ function retomarPedido(carregado, pedidoOriginal, opcoes = {}) {
|
|
|
666
876
|
}
|
|
667
877
|
// Falhou de novo. Rate limit outra vez reagenda o MESMO pedido com a hora nova;
|
|
668
878
|
// qualquer outro motivo devolve o pedido para a fila com a tentativa contada.
|
|
669
|
-
|
|
879
|
+
// D15 (A4): pedido da conta reagenda no proximo prazo entre TODOS os runtimes candidatos, e o
|
|
880
|
+
// novo prazo e sempre posterior ao instante da retomada: nada volta a vencer na mesma chamada.
|
|
881
|
+
const instante = Math.max(Date.parse(quando), Date.now());
|
|
882
|
+
const prazoDaConta = alvo.contas ? (0, runtime_profiles_1.prazoDaFila)((0, runtime_profiles_1.lerPerfisComContas)(raiz), alvo.runtimes, (0, runtime_profiles_1.politicaDeRotacao)(carregado.manifesto), instante) : null;
|
|
883
|
+
let novaJanela = prazoDaConta ?? r.sinal?.resetEm ?? pedido.liberaEm;
|
|
884
|
+
let estimada = prazoDaConta ? false : r.sinal ? r.sinal.resetEm === null : pedido.janelaEstimada;
|
|
885
|
+
if (alvo.contas && !(Date.parse(novaJanela) > instante)) {
|
|
886
|
+
novaJanela = new Date(instante + (0, ratelimit_1.janelaPadraoMs)(carregado.manifesto)).toISOString();
|
|
887
|
+
estimada = true;
|
|
888
|
+
}
|
|
670
889
|
pedido = (0, ratelimit_1.gravarPedido)(raiz, {
|
|
671
890
|
...pedido,
|
|
672
891
|
tentativas: pedido.tentativas + 1,
|
|
673
892
|
liberaEm: novaJanela,
|
|
674
|
-
janelaEstimada:
|
|
893
|
+
janelaEstimada: estimada,
|
|
675
894
|
sinal: r.sinal ?? pedido.sinal,
|
|
676
895
|
detalhe: r.detalhe,
|
|
677
896
|
});
|
|
@@ -687,6 +906,36 @@ function retomarPedido(carregado, pedidoOriginal, opcoes = {}) {
|
|
|
687
906
|
dryRun: false,
|
|
688
907
|
};
|
|
689
908
|
}
|
|
909
|
+
/**
|
|
910
|
+
* D15 (A4): o destino da retomada. Pedido da conta tenta o runtime original e depois cada runtime da
|
|
911
|
+
* ordem de fallback do bloco, e fica com o primeiro cujo perfil da vez esta disponivel agora, pela
|
|
912
|
+
* politica da D14. Runtime original sem perfil configurado segue pelo ambiente do processo, como
|
|
913
|
+
* antes; pedido antigo (rate limit) segue no runtime gravado.
|
|
914
|
+
*/
|
|
915
|
+
function alvoDaRetomada(carregado, thread, pedido) {
|
|
916
|
+
const { raiz, manifesto } = carregado;
|
|
917
|
+
const original = { runtime: pedido.runtime ?? null, model: pedido.model, effort: pedido.effort };
|
|
918
|
+
if (pedido.motivo !== 'runtime.quota-exhausted' && pedido.motivo !== 'runtime.auth-missing')
|
|
919
|
+
return { ...original, destino: true, runtimes: original.runtime ? [original.runtime] : [], contas: false };
|
|
920
|
+
const doBloco = (0, setup_1.configDoBloco)((0, setup_1.lerSetup)(raiz), thread.modo, pedido.fase);
|
|
921
|
+
const principal = pedido.runtime ?? doBloco?.runtime ?? manifesto.runtime.adapter;
|
|
922
|
+
const candidatos = [{ runtime: principal, model: pedido.model, effort: pedido.effort },
|
|
923
|
+
...alvosDeFallback(doBloco, doBloco?.runtime ?? manifesto.runtime.adapter).filter(f => f.runtime !== principal)
|
|
924
|
+
.map(f => ({ runtime: f.runtime, model: f.model, effort: f.effort ?? pedido.effort }))];
|
|
925
|
+
const runtimes = candidatos.map(c => c.runtime);
|
|
926
|
+
const store = (0, runtime_profiles_1.lerPerfisComContas)(raiz), politica = (0, runtime_profiles_1.politicaDeRotacao)(manifesto);
|
|
927
|
+
for (const c of candidatos) {
|
|
928
|
+
if ((0, runtime_profiles_1.perfisDoRuntime)(store, c.runtime).length === 0) {
|
|
929
|
+
if (c.runtime === principal)
|
|
930
|
+
return { ...c, destino: true, perfil: null, runtimes, contas: true };
|
|
931
|
+
continue;
|
|
932
|
+
}
|
|
933
|
+
const p = (0, runtime_profiles_1.proximoPerfilDisponivel)(store, c.runtime, politica);
|
|
934
|
+
if (p)
|
|
935
|
+
return { ...c, destino: true, perfil: p.id, runtimes, contas: true };
|
|
936
|
+
}
|
|
937
|
+
return { destino: false, runtime: null, model: pedido.model, effort: pedido.effort, runtimes, contas: true };
|
|
938
|
+
}
|
|
690
939
|
/** Retoma todos os pedidos cuja janela ja liberou. */
|
|
691
940
|
function retomarFila(carregado, opcoes = {}) {
|
|
692
941
|
const quando = opcoes.quando ?? (0, util_1.agora)();
|
|
@@ -715,12 +964,123 @@ function cancelarPedido(carregado, id, motivo) {
|
|
|
715
964
|
});
|
|
716
965
|
return cancelado;
|
|
717
966
|
}
|
|
967
|
+
/**
|
|
968
|
+
* D6 (A13): a ordem de fallback do bloco, `runtime:modelo[:esforco]`, pelo parser unico do setup
|
|
969
|
+
* (domicilio da D6): entrada malformada, runtime nao homologado, repetido ou igual ao principal e
|
|
970
|
+
* descartada com as mesmas regras da edicao e da listagem.
|
|
971
|
+
*/
|
|
972
|
+
function alvosDeFallback(bloco, principal) {
|
|
973
|
+
return (0, setup_1.alvosDaOrdemDeFallback)(bloco?.fallback, principal);
|
|
974
|
+
}
|
|
975
|
+
/**
|
|
976
|
+
* D5, D14, D16: proximo destino do MESMO prompt. Primeiro o perfil da vez do mesmo runtime (outro
|
|
977
|
+
* perfil so com a troca do manifesto ligada para o motivo: por cota, ligada por padrao desde a
|
|
978
|
+
* decisao do dono em 19/09/2026); depois cada runtime da ordem de fallback (perfil da vez dele, ou o ambiente do
|
|
979
|
+
* processo quando ele nao tem perfil configurado e esse ambiente ainda nao falhou nesta rotacao).
|
|
980
|
+
* Sem destino, `null`.
|
|
981
|
+
*/
|
|
982
|
+
function proximoAlvo(raiz, atual, fallback, excluir, politica, agoraMs = Date.now()) {
|
|
983
|
+
const store = (0, runtime_profiles_1.lerPerfisComContas)(raiz, agoraMs);
|
|
984
|
+
const perfis = [...excluir.perfis, ...(atual.perfil ? [atual.perfil.id] : [])];
|
|
985
|
+
const mesmo = (0, runtime_profiles_1.proximoPerfilDisponivel)(store, atual.runtime, politica, { excluir: perfis, agoraMs });
|
|
986
|
+
if (mesmo)
|
|
987
|
+
return { runtime: atual.runtime, perfil: (0, runtime_profiles_1.perfilDeDespacho)(mesmo), model: null, effort: null };
|
|
988
|
+
for (const f of fallback) {
|
|
989
|
+
if (f.runtime === atual.runtime)
|
|
990
|
+
continue;
|
|
991
|
+
if ((0, runtime_profiles_1.perfisDoRuntime)(store, f.runtime).length > 0) {
|
|
992
|
+
const p = (0, runtime_profiles_1.proximoPerfilDisponivel)(store, f.runtime, politica, { excluir: perfis, agoraMs });
|
|
993
|
+
if (p)
|
|
994
|
+
return { runtime: f.runtime, perfil: (0, runtime_profiles_1.perfilDeDespacho)(p), model: f.model, effort: f.effort ?? null };
|
|
995
|
+
continue;
|
|
996
|
+
}
|
|
997
|
+
if (!excluir.runtimesImplicitos.includes(f.runtime))
|
|
998
|
+
return { runtime: f.runtime, perfil: null, model: f.model, effort: f.effort ?? null };
|
|
999
|
+
}
|
|
1000
|
+
return null;
|
|
1001
|
+
}
|
|
1002
|
+
/**
|
|
1003
|
+
* D11 (c): o intervalo do despacho produziu alguma coisa? Leitura de disco, do ledger e do git,
|
|
1004
|
+
* como a prova da I-34: artefato da fase gravado, commit registrado, entrega registrada ou, no
|
|
1005
|
+
* GO, HEAD movido ou worktree alterada. Duvida conta como producao (fail-closed): so o intervalo
|
|
1006
|
+
* provadamente vazio aceita redespacho do mesmo prompt.
|
|
1007
|
+
*/
|
|
1008
|
+
function producaoNoIntervalo(raiz, thread, sessao, eventos) {
|
|
1009
|
+
const fonte = (0, session_watcher_claude_1.fonteRegistrada)(eventos, sessao);
|
|
1010
|
+
const saida = (0, session_watcher_claude_1.saidaDoArtefato)(raiz, thread.id, sessao, fonte, eventos);
|
|
1011
|
+
if (saida?.produzido)
|
|
1012
|
+
return { produziu: true, evidencia: `${saida.arquivo} gravado no intervalo do despacho` };
|
|
1013
|
+
const intervalo = (0, session_watcher_claude_1.eventosDoIntervalo)(eventos, sessao);
|
|
1014
|
+
const commits = intervalo.filter(e => e.tipo === 'mcp_git_committed' || (e.tipo === 'commit' && e.sessionId === sessao.sessionId));
|
|
1015
|
+
if (commits.length)
|
|
1016
|
+
return { produziu: true, evidencia: `${commits.length} commit(s) registrado(s) no intervalo do despacho` };
|
|
1017
|
+
const entrega = intervalo.find(e => e.tipo === 'ship_done' || e.tipo === 'score_proposto');
|
|
1018
|
+
if (entrega)
|
|
1019
|
+
return { produziu: true, evidencia: `${entrega.tipo} registrado no intervalo do despacho` };
|
|
1020
|
+
if (sessao.fase === 'GO') {
|
|
1021
|
+
const despacho = eventos.filter(e => e.tipo === 'phase_dispatch' && e.sessionId === sessao.sessionId).at(-1);
|
|
1022
|
+
// I-33 (N1): o HEAD vem do registro do despacho em qualquer runtime (claude-bg e codex); commit feito
|
|
1023
|
+
// pelo shell nao passa pelo ledger, entao so o HEAD o revela.
|
|
1024
|
+
const registro = eventos.filter(e => e.tipo === 'session_sensor_registered' && e.sessionId === sessao.sessionId &&
|
|
1025
|
+
e.despachoEm === sessao.despachadaEm).at(-1);
|
|
1026
|
+
const cwd = typeof registro?.cwd === 'string' ? registro.cwd : typeof despacho?.cwd === 'string' ? despacho.cwd : thread.worktree ?? raiz;
|
|
1027
|
+
const head = registro?.head;
|
|
1028
|
+
if (typeof head !== 'string' || !/^(?:[a-f0-9]{40}|[a-f0-9]{64})$/.test(head))
|
|
1029
|
+
return { produziu: true, evidencia: 'HEAD da worktree no despacho desconhecido; producao nao descartada' };
|
|
1030
|
+
if ((0, session_watcher_claude_1.headDaWorktree)(cwd) !== head)
|
|
1031
|
+
return { produziu: true, evidencia: 'HEAD da worktree mudou desde o despacho' };
|
|
1032
|
+
const status = (0, util_1.exec)('git', ['status', '--porcelain', '--', '.', ':(exclude).orkastery'], cwd, 30000);
|
|
1033
|
+
if (!status.ok)
|
|
1034
|
+
return { produziu: true, evidencia: 'git status da worktree falhou; producao nao descartada' };
|
|
1035
|
+
if (status.stdout.trim() !== '')
|
|
1036
|
+
return { produziu: true, evidencia: 'worktree com alteracoes nao commitadas' };
|
|
1037
|
+
}
|
|
1038
|
+
return { produziu: false, evidencia: 'nenhum artefato, commit, entrega ou alteracao da worktree no intervalo do despacho' };
|
|
1039
|
+
}
|
|
1040
|
+
/** O despacho que falhou pela conta: o da sessao do gate (observador) ou o ultimo recusado na fase. */
|
|
1041
|
+
function despachoDaFalha(eventos, gate, fase) {
|
|
1042
|
+
if (gate && typeof gate.sessionId === 'string')
|
|
1043
|
+
return eventos.filter(e => e.tipo === ledger_1.TIPOS_DE_EVENTO.faseDespachada && e.sessionId === gate.sessionId).at(-1) ?? null;
|
|
1044
|
+
for (let i = eventos.length - 1; i >= 0; i--) {
|
|
1045
|
+
const e = eventos[i];
|
|
1046
|
+
if (e.fase === fase && e.tipo === ledger_1.TIPOS_DE_EVENTO.despachoFalhou)
|
|
1047
|
+
return e;
|
|
1048
|
+
if (e.fase === fase && e.tipo === ledger_1.TIPOS_DE_EVENTO.faseDespachada)
|
|
1049
|
+
return null;
|
|
1050
|
+
}
|
|
1051
|
+
return null;
|
|
1052
|
+
}
|
|
1053
|
+
function perfilDoEvento(e) {
|
|
1054
|
+
return e && e.perfil !== undefined && e.perfil !== null ? (0, runtime_profiles_1.validarPerfilDeDespacho)(e.perfil) : null;
|
|
1055
|
+
}
|
|
1056
|
+
/** O perfil ja esta fora do rodizio por esta falha (cota com prazo futuro, ou sem login)? */
|
|
1057
|
+
function jaMarcado(raiz, perfil, falha, agoraMs = Date.now()) {
|
|
1058
|
+
let atual;
|
|
1059
|
+
try {
|
|
1060
|
+
atual = (0, runtime_profiles_1.lerPerfis)(raiz).perfis.find(p => p.id === perfil.id);
|
|
1061
|
+
}
|
|
1062
|
+
catch {
|
|
1063
|
+
return false;
|
|
1064
|
+
}
|
|
1065
|
+
if (!atual)
|
|
1066
|
+
return false;
|
|
1067
|
+
return falha.motivo === 'runtime.quota-exhausted'
|
|
1068
|
+
? atual.estado === 'esgotado' && atual.esgotadoAte !== null && Date.parse(atual.esgotadoAte) > agoraMs
|
|
1069
|
+
: atual.estado === 'sem-auth';
|
|
1070
|
+
}
|
|
1071
|
+
function sinalDoGate(gate, motivo) {
|
|
1072
|
+
const f = gate?.falhaDeConta;
|
|
1073
|
+
return { motivo: motivo === 'runtime.auth-missing' ? 'runtime.auth-missing' : 'runtime.quota-exhausted',
|
|
1074
|
+
resetEm: typeof f?.resetEm === 'string' ? f.resetEm : null, fonte: f?.fonte ?? 'sem-horario',
|
|
1075
|
+
trecho: typeof f?.trecho === 'string' ? f.trecho : String(gate?.detalhe ?? motivo).slice(0, 200) };
|
|
1076
|
+
}
|
|
718
1077
|
/** O ultimo despacho que falhou nesta fase, de onde sai o prompt a redespachar. */
|
|
719
|
-
function ultimoDespachoFalho(raiz, threadId, fase) {
|
|
1078
|
+
function ultimoDespachoFalho(raiz, threadId, fase, silencio = false) {
|
|
720
1079
|
const eventos = (0, ledger_1.lerLedger)((0, thread_1.dirThread)(raiz, threadId));
|
|
721
1080
|
for (let i = eventos.length - 1; i >= 0; i--) {
|
|
722
1081
|
const e = eventos[i];
|
|
723
|
-
if (e.
|
|
1082
|
+
if (e.fase === fase && (e.tipo === ledger_1.TIPOS_DE_EVENTO.despachoFalhou ||
|
|
1083
|
+
(silencio && e.tipo === ledger_1.TIPOS_DE_EVENTO.faseDespachada)))
|
|
724
1084
|
return e;
|
|
725
1085
|
}
|
|
726
1086
|
return null;
|
|
@@ -733,7 +1093,18 @@ function ultimoDespachoFalho(raiz, threadId, fase) {
|
|
|
733
1093
|
*/
|
|
734
1094
|
function executarRetry(carregado, threadId, opcoes = {}) {
|
|
735
1095
|
const { raiz } = carregado;
|
|
736
|
-
|
|
1096
|
+
let plano = planejarRetry(carregado, threadId, { ...opcoes, estadoDaSessao: undefined });
|
|
1097
|
+
if (plano.motivo === 'runtime.silencio' && plano.fase && plano.tentativas < plano.limite) {
|
|
1098
|
+
const despacho = ultimoDespachoFalho(raiz, threadId, plano.fase, true);
|
|
1099
|
+
// O adapter Codex da baseline nao fornece prova terminal. I-04 adiciona esse contrato.
|
|
1100
|
+
if (despacho?.runtime === 'claude-bg' && typeof despacho.sessionId === 'string') {
|
|
1101
|
+
const consulta = (0, claude_bg_1.consultarSessoes)(undefined, true);
|
|
1102
|
+
const sessao = consulta.ok ? consulta.sessoes.find(s => s.sessionId === despacho.sessionId) : undefined;
|
|
1103
|
+
const estado = sessao?.state ?? sessao?.status;
|
|
1104
|
+
plano = planejarRetry(carregado, threadId, { ...opcoes,
|
|
1105
|
+
estadoDaSessao: typeof estado === 'string' ? { sessionId: despacho.sessionId, estado } : undefined });
|
|
1106
|
+
}
|
|
1107
|
+
}
|
|
737
1108
|
const thread = (0, thread_1.lerThread)(raiz, threadId);
|
|
738
1109
|
const dir = (0, thread_1.dirThread)(raiz, threadId);
|
|
739
1110
|
const vazio = {
|
|
@@ -798,12 +1169,23 @@ function executarRetry(carregado, threadId, opcoes = {}) {
|
|
|
798
1169
|
effortAnterior: plano.effortAnterior,
|
|
799
1170
|
dryRun: opcoes.dryRun === true,
|
|
800
1171
|
autorizadoPor: blocoPausa(thread, plano.fase)
|
|
801
|
-
? (
|
|
1172
|
+
? ((0, gates_2.aprovacoesHumanas)(raiz, threadId).some(e => e.fase === plano.fase && e.autorizadoPor === opcoes.autorizadoPor)
|
|
1173
|
+
? opcoes.autorizadoPor : `delegacao:${carregado.manifesto.conduction.delegation?.delegado ?? 'ausente'}`)
|
|
802
1174
|
: `politica de retry do bloco B3 (bloco sem pausa no modo ${thread.modo})`,
|
|
803
1175
|
ok,
|
|
804
1176
|
detalhe,
|
|
805
1177
|
});
|
|
806
1178
|
};
|
|
1179
|
+
// I-36 (T6): conducao em andamento nao e fila de rate limit. Nada e redespachado; o registro diz
|
|
1180
|
+
// quem conduz, e a vez chega quando essa conducao terminar.
|
|
1181
|
+
if (plano.motivo === 'conducao.em-andamento') {
|
|
1182
|
+
const atual = (0, conducao_1.conducaoDaThread)(raiz, threadId);
|
|
1183
|
+
const detalhe = atual
|
|
1184
|
+
? `${(0, conducao_texto_1.linhaDeConducao)(atual)}; nada foi redespachado, a vez chega quando essa conducao terminar`
|
|
1185
|
+
: 'ninguem conduz a thread agora: o proximo pedido segue normalmente';
|
|
1186
|
+
registrarTentativa(!atual, detalhe);
|
|
1187
|
+
return { ...vazio, executada: false, detalhe };
|
|
1188
|
+
}
|
|
807
1189
|
// `esperar-janela`: quem retoma e a fila, e ela ja esta gravada em disco.
|
|
808
1190
|
if (acaoBase === 'esperar-janela') {
|
|
809
1191
|
const fila = (0, ratelimit_1.lerFilaDeRetomada)(raiz).filter((p) => p.thread === threadId && p.estado === 'aguardando');
|
|
@@ -833,8 +1215,11 @@ function executarRetry(carregado, threadId, opcoes = {}) {
|
|
|
833
1215
|
registrarTentativa(rodada.correcoes.length > 0, detalhe);
|
|
834
1216
|
return { ...vazio, executada: rodada.correcoes.length > 0, rodada, reverify, detalhe };
|
|
835
1217
|
}
|
|
1218
|
+
if (plano.motivo === 'runtime.quota-exhausted' || plano.motivo === 'runtime.auth-missing') {
|
|
1219
|
+
return rotacionarConta(carregado, thread, plano, opcoes, vazio, registrarTentativa);
|
|
1220
|
+
}
|
|
836
1221
|
// `reexecutar` e `escalar-esforco`: o MESMO prompt volta ao runtime.
|
|
837
|
-
const falho = ultimoDespachoFalho(raiz, threadId, plano.fase);
|
|
1222
|
+
const falho = ultimoDespachoFalho(raiz, threadId, plano.fase, plano.motivo === 'runtime.silencio');
|
|
838
1223
|
if (!falho || typeof falho.promptPath !== 'string' || typeof falho.promptSha256 !== 'string') {
|
|
839
1224
|
const detalhe = `nao ha despacho falho registrado em ${plano.fase} com prompt gravado: ` +
|
|
840
1225
|
`rode a fase de novo com \`ork phase run ${threadId} ${plano.fase} --prompt "..."\``;
|
|
@@ -843,6 +1228,7 @@ function executarRetry(carregado, threadId, opcoes = {}) {
|
|
|
843
1228
|
}
|
|
844
1229
|
const redespacho = redespachar(carregado, thread, plano.fase, falho.promptPath, falho.promptSha256, {
|
|
845
1230
|
effort: plano.effort,
|
|
1231
|
+
runtime: typeof falho.runtime === 'string' ? falho.runtime : null,
|
|
846
1232
|
model: typeof falho.model === 'string' ? falho.model : null,
|
|
847
1233
|
origem: 'retry.run',
|
|
848
1234
|
dryRun: opcoes.dryRun,
|
|
@@ -855,6 +1241,134 @@ function executarRetry(carregado, threadId, opcoes = {}) {
|
|
|
855
1241
|
detalhe: redespacho.detalhe,
|
|
856
1242
|
};
|
|
857
1243
|
}
|
|
1244
|
+
/**
|
|
1245
|
+
* D5 + D11: rotacao depois de falha da conta. Com sessao no gate (o observador classificou a
|
|
1246
|
+
* morte), a prova do `ork` decide antes: producao parcial vira `human.pending` com diagnostico.
|
|
1247
|
+
* Sem producao, o perfil sai do rodizio e o MESMO prompt segue no proximo destino; recusa da
|
|
1248
|
+
* conta no redespacho (nada rodou) continua a rotacao na mesma chamada, dentro do limite de
|
|
1249
|
+
* tentativas. Sem destino: fila ate o menor prazo, ou o humano quando nenhum prazo existe.
|
|
1250
|
+
*/
|
|
1251
|
+
function rotacionarConta(carregado, thread, plano, opcoes, vazio, registrarTentativa) {
|
|
1252
|
+
const { raiz, manifesto } = carregado;
|
|
1253
|
+
const dir = (0, thread_1.dirThread)(raiz, thread.id);
|
|
1254
|
+
const fase = plano.fase;
|
|
1255
|
+
const motivo = plano.motivo;
|
|
1256
|
+
const eventos = (0, ledger_1.lerLedger)(dir);
|
|
1257
|
+
const gate = ultimaReprovacao(raiz, thread.id);
|
|
1258
|
+
const despacho = despachoDaFalha(eventos, gate, fase);
|
|
1259
|
+
const escalar = (razao, diagnostico) => {
|
|
1260
|
+
if (!opcoes.dryRun) {
|
|
1261
|
+
(0, gates_1.registrarGateBloqueado)(dir, thread.id, { gate: 'phase.dispatch', motivo: 'human.pending', modo: thread.modo, detalhe: diagnostico,
|
|
1262
|
+
diagnostico, correcao: `ork gate approve ${thread.id} retomada --por <quem>`, fase, origem: 'retry.rotacao', pausaQualquerModo: true });
|
|
1263
|
+
(0, ledger_1.registrar)(dir, thread.id, ledger_1.TIPOS_DE_EVENTO.retryEscalado, { fase, motivo, origem: 'retry.rotacao', acao: plano.acao,
|
|
1264
|
+
tentativas: plano.tentativas, limite: plano.limite, modo: thread.modo, razao });
|
|
1265
|
+
}
|
|
1266
|
+
return { ...vazio, detalhe: diagnostico };
|
|
1267
|
+
};
|
|
1268
|
+
if (!despacho || typeof despacho.promptPath !== 'string' || typeof despacho.promptSha256 !== 'string') {
|
|
1269
|
+
const detalhe = `nao ha despacho com prompt gravado para ${motivo} em ${fase}: rode a fase de novo com ork phase run`;
|
|
1270
|
+
registrarTentativa(false, detalhe);
|
|
1271
|
+
return { ...vazio, detalhe };
|
|
1272
|
+
}
|
|
1273
|
+
const runtime = typeof despacho.runtime === 'string' ? despacho.runtime : manifesto.runtime.adapter;
|
|
1274
|
+
let perfil;
|
|
1275
|
+
try {
|
|
1276
|
+
perfil = typeof gate?.sessionId === 'string'
|
|
1277
|
+
? (0, runtime_profiles_1.perfilDoRegistro)(eventos, { sessionId: gate.sessionId, despachadaEm: typeof gate.despachoEm === 'string' ? gate.despachoEm : undefined })
|
|
1278
|
+
: perfilDoEvento(despacho);
|
|
1279
|
+
}
|
|
1280
|
+
catch (e) {
|
|
1281
|
+
return escalar('perfil registrado invalido', `rotacao recusada: ${e.message}`);
|
|
1282
|
+
}
|
|
1283
|
+
// D11 (c): sessao que morreu por cota depois de produzir nao e redespachada.
|
|
1284
|
+
if (typeof gate?.sessionId === 'string' && typeof gate.despachoEm === 'string') {
|
|
1285
|
+
const producao = producaoNoIntervalo(raiz, thread, { sessionId: gate.sessionId, fase, despachadaEm: gate.despachoEm }, eventos);
|
|
1286
|
+
if (producao.produziu) {
|
|
1287
|
+
return escalar('producao parcial sob falha da conta', `producao parcial sob ${motivo === 'runtime.quota-exhausted' ? 'cota esgotada' : 'auth ausente'}: ${producao.evidencia}; ` +
|
|
1288
|
+
'a sessao nao e redespachada sobre a worktree alterada e a fase nao conclui sem o humano');
|
|
1289
|
+
}
|
|
1290
|
+
}
|
|
1291
|
+
const doBloco = (0, setup_1.configDoBloco)((0, setup_1.lerSetup)(raiz), thread.modo, fase);
|
|
1292
|
+
const fallback = alvosDeFallback(doBloco, doBloco?.runtime ?? manifesto.runtime.adapter);
|
|
1293
|
+
const politica = (0, runtime_profiles_1.politicaDeRotacao)(manifesto);
|
|
1294
|
+
const falha = sinalDoGate(gate, motivo);
|
|
1295
|
+
// I-33 (D12): o observador ja marca o perfil no caminho terminal; remarcar empurraria o prazo a cada retry.
|
|
1296
|
+
if (!opcoes.dryRun && perfil && !jaMarcado(raiz, perfil, falha)) {
|
|
1297
|
+
try {
|
|
1298
|
+
(0, ratelimit_1.marcarContaDaFalha)(carregado, perfil, falha);
|
|
1299
|
+
}
|
|
1300
|
+
catch { /* o store pode ja estar marcado */ }
|
|
1301
|
+
}
|
|
1302
|
+
const tentados = [];
|
|
1303
|
+
const implicitos = perfil ? [] : [runtime];
|
|
1304
|
+
let atual = { runtime, perfil };
|
|
1305
|
+
let tentativas = plano.tentativas;
|
|
1306
|
+
let ultimo = null;
|
|
1307
|
+
let falhaAtual = falha;
|
|
1308
|
+
const emitir = (para, razao) => {
|
|
1309
|
+
if (!opcoes.dryRun)
|
|
1310
|
+
(0, ledger_1.registrar)(dir, thread.id, ledger_1.TIPOS_DE_EVENTO.perfilRotacionado, { fase, motivo: falhaAtual.motivo, origem: 'retry.rotacao',
|
|
1311
|
+
de: { runtime: atual.runtime, perfil: atual.perfil?.id ?? null },
|
|
1312
|
+
para: para ? { runtime: para.runtime, perfil: para.perfil?.id ?? null } : null,
|
|
1313
|
+
evidencia: falhaAtual.trecho, razao, promptSha256: despacho.promptSha256, modo: thread.modo,
|
|
1314
|
+
autorizadoPor: `politica de retry da I-33 (D5), bloco sem pausa ou delegado no modo ${thread.modo}` });
|
|
1315
|
+
};
|
|
1316
|
+
for (;;) {
|
|
1317
|
+
const alvo = proximoAlvo(raiz, atual, fallback, { perfis: tentados, runtimesImplicitos: implicitos }, politica);
|
|
1318
|
+
if (!alvo)
|
|
1319
|
+
break;
|
|
1320
|
+
emitir(alvo, alvo.runtime === atual.runtime ? 'proximo perfil ativo do mesmo runtime' : 'fallback de runtime pela ordem do bloco');
|
|
1321
|
+
const mudouRuntime = alvo.runtime !== runtime;
|
|
1322
|
+
ultimo = redespachar(carregado, thread, fase, despacho.promptPath, despacho.promptSha256, {
|
|
1323
|
+
runtime: alvo.runtime, perfil: alvo.perfil?.id ?? null,
|
|
1324
|
+
model: mudouRuntime ? alvo.model : typeof despacho.model === 'string' ? despacho.model : null,
|
|
1325
|
+
effort: mudouRuntime ? alvo.effort ?? (typeof despacho.effort === 'string' ? despacho.effort : null) : plano.effort,
|
|
1326
|
+
origem: 'retry.rotacao', dryRun: opcoes.dryRun,
|
|
1327
|
+
});
|
|
1328
|
+
registrarTentativa(ultimo.ok, ultimo.detalhe);
|
|
1329
|
+
tentativas += 1;
|
|
1330
|
+
if (ultimo.ok || opcoes.dryRun)
|
|
1331
|
+
return { ...vazio, executada: ultimo.ok, redespacho: ultimo, detalhe: ultimo.detalhe };
|
|
1332
|
+
// So a recusa da CONTA no redespacho (nada rodou) continua a rotacao; outra falha para aqui.
|
|
1333
|
+
if (!ultimo.falhaDeConta && ultimo.motivo !== 'runtime.auth-missing' && ultimo.motivo !== 'runtime.quota-exhausted')
|
|
1334
|
+
return { ...vazio, redespacho: ultimo, detalhe: ultimo.detalhe };
|
|
1335
|
+
if (alvo.perfil)
|
|
1336
|
+
tentados.push(alvo.perfil.id);
|
|
1337
|
+
else
|
|
1338
|
+
implicitos.push(alvo.runtime);
|
|
1339
|
+
atual = { runtime: alvo.runtime, perfil: alvo.perfil };
|
|
1340
|
+
falhaAtual = ultimo.falhaDeConta ?? falhaAtual;
|
|
1341
|
+
if (tentativas >= plano.limite) {
|
|
1342
|
+
return escalar('limite de tentativas na rotacao', `${tentativas} tentativa(s) de rotacao por ${motivo} em ${fase}, no limite de ` +
|
|
1343
|
+
`${plano.limite} do manifesto: escalacao tipada pausa qualquer modo`);
|
|
1344
|
+
}
|
|
1345
|
+
}
|
|
1346
|
+
// Sem destino: a fila so faz sentido quando algum perfil tem prazo para voltar. Sem perfil (ambiente do
|
|
1347
|
+
// processo), o prazo e o horario dito pelo proprio runtime, quando ainda esta no futuro.
|
|
1348
|
+
const runtimes = [runtime, ...fallback.map(f => f.runtime)];
|
|
1349
|
+
const dito = !perfil && falhaAtual.resetEm !== null && Date.parse(falhaAtual.resetEm) > Date.now() ? falhaAtual.resetEm : null;
|
|
1350
|
+
const prazo = (0, runtime_profiles_1.prazoDaFila)((0, runtime_profiles_1.lerPerfisComContas)(raiz), runtimes, politica) ?? dito;
|
|
1351
|
+
if (!prazo && falhaAtual.motivo === 'runtime.auth-missing') {
|
|
1352
|
+
emitir(null, 'nenhum perfil com login em nenhum runtime da ordem de fallback');
|
|
1353
|
+
return escalar('auth ausente sem alternativa', 'nenhum perfil com login conferido em nenhum runtime da ordem de fallback: ' +
|
|
1354
|
+
'refaca o login com ork accounts add ou ork accounts check antes de retomar');
|
|
1355
|
+
}
|
|
1356
|
+
const liberaEm = prazo ?? new Date(Date.now() + (0, ratelimit_1.janelaPadraoMs)(manifesto)).toISOString();
|
|
1357
|
+
emitir(null, `nenhum perfil ativo em ${runtimes.join(', ')}: fila duravel ate ${liberaEm}`);
|
|
1358
|
+
if (opcoes.dryRun)
|
|
1359
|
+
return { ...vazio, detalhe: `ensaio: entraria na fila duravel ate ${liberaEm}` };
|
|
1360
|
+
const pedido = (0, ratelimit_1.enfileirar)(carregado, { thread: thread.id, fase, slug: typeof despacho.slug === 'string' ? despacho.slug : (0, phase_1.slugDaSessao)(thread, fase),
|
|
1361
|
+
promptPath: despacho.promptPath, promptSha256: despacho.promptSha256,
|
|
1362
|
+
cwd: typeof despacho.cwd === 'string' ? despacho.cwd : thread.worktree ?? raiz,
|
|
1363
|
+
model: typeof despacho.model === 'string' ? despacho.model : null, effort: typeof despacho.effort === 'string' ? despacho.effort : null,
|
|
1364
|
+
sinal: { resetEm: prazo, fonte: prazo ? 'iso' : 'sem-horario', trecho: falhaAtual.trecho },
|
|
1365
|
+
detalhe: `${falhaAtual.motivo}: nenhum perfil ativo em ${runtimes.join(', ')}`, runtime, perfil: null, motivo: falhaAtual.motivo });
|
|
1366
|
+
(0, ledger_1.registrar)(dir, thread.id, ledger_1.TIPOS_DE_EVENTO.rateLimitEnfileirado, { fase, slug: pedido.slug, pedido: pedido.id, liberaEm: pedido.liberaEm,
|
|
1367
|
+
janelaEstimada: pedido.janelaEstimada, motivo: falhaAtual.motivo, promptSha256: despacho.promptSha256,
|
|
1368
|
+
correcao: `ork retry resume (ou aguarde ate ${pedido.liberaEm})` });
|
|
1369
|
+
registrarTentativa(true, `fila duravel: pedido ${pedido.id} libera em ${pedido.liberaEm}`);
|
|
1370
|
+
return { ...vazio, executada: true, fila: [pedido], redespacho: ultimo, detalhe: `pedido ${pedido.id} na fila ate ${pedido.liberaEm}` };
|
|
1371
|
+
}
|
|
858
1372
|
/** Texto de `ork retry plan`. */
|
|
859
1373
|
function textoDoPlano(p) {
|
|
860
1374
|
const linhas = [];
|
|
@@ -863,7 +1377,7 @@ function textoDoPlano(p) {
|
|
|
863
1377
|
linhas.push(` fase ${p.fase ?? '(nenhuma)'}`);
|
|
864
1378
|
linhas.push(` motivo tipado ${p.motivo ?? '(nenhuma reprovacao pendente)'}`);
|
|
865
1379
|
if (p.detalhe)
|
|
866
|
-
linhas.push(` detalhe ${p.detalhe}`);
|
|
1380
|
+
linhas.push(` detalhe ${(0, horario_1.localizarTexto)(p.detalhe)}`);
|
|
867
1381
|
linhas.push(` acao ${p.acao}`);
|
|
868
1382
|
linhas.push(` tentativas ${p.tentativas} de ${p.limite} antes da escalacao`);
|
|
869
1383
|
linhas.push(` esforco ${p.effort}${p.effort !== p.effortAnterior ? ` (escalado de ${p.effortAnterior})` : ''}`);
|
|
@@ -873,13 +1387,16 @@ function textoDoPlano(p) {
|
|
|
873
1387
|
linhas.push(` razao ${p.razao}`);
|
|
874
1388
|
if (p.politica && !p.automatica)
|
|
875
1389
|
linhas.push(` correcao ${p.politica.correcao}`);
|
|
1390
|
+
if (p.detalhe && (0, horario_1.localizarTexto)(p.detalhe) !== p.detalhe)
|
|
1391
|
+
linhas.push((0, horario_1.legendaDoFuso)());
|
|
876
1392
|
return linhas.join('\n');
|
|
877
1393
|
}
|
|
878
1394
|
/** Texto de `ork retry run`. */
|
|
879
1395
|
function textoDoRetry(r) {
|
|
880
|
-
const
|
|
1396
|
+
const plano = textoDoPlano(r.plano);
|
|
1397
|
+
const linhas = [plano, ''];
|
|
881
1398
|
linhas.push(`Execucao: ${r.executada ? 'acao executada' : 'nada executado'}`);
|
|
882
|
-
linhas.push(` ${r.detalhe}`);
|
|
1399
|
+
linhas.push(` ${(0, horario_1.localizarTexto)(r.detalhe)}`);
|
|
883
1400
|
if (r.rodada && r.rodada.correcoes.length > 0) {
|
|
884
1401
|
linhas.push('');
|
|
885
1402
|
linhas.push(`GO-FIX rodada ${r.rodada.rodada}: ` +
|
|
@@ -892,9 +1409,12 @@ function textoDoRetry(r) {
|
|
|
892
1409
|
linhas.push('');
|
|
893
1410
|
linhas.push('Fila de rate limit desta thread:');
|
|
894
1411
|
for (const p of r.fila) {
|
|
895
|
-
linhas.push(` ${p.id} ${p.fase} libera em ${p.liberaEm}${p.janelaEstimada ? ' (janela estimada)' : ''}`);
|
|
1412
|
+
linhas.push(` ${p.id} ${p.fase} libera em ${(0, horario_1.formatarDataHora)(p.liberaEm)}${p.janelaEstimada ? ' (janela estimada)' : ''}`);
|
|
896
1413
|
}
|
|
897
1414
|
}
|
|
1415
|
+
if ((r.fila.length > 0 || (0, horario_1.localizarTexto)(r.detalhe) !== r.detalhe) && !plano.includes((0, horario_1.legendaDoFuso)())) {
|
|
1416
|
+
linhas.push((0, horario_1.legendaDoFuso)());
|
|
1417
|
+
}
|
|
898
1418
|
return linhas.join('\n');
|
|
899
1419
|
}
|
|
900
1420
|
/** Texto de `ork retry resume`. */
|
|
@@ -910,8 +1430,10 @@ function textoDaRetomada(rs) {
|
|
|
910
1430
|
linhas.push(` retomada ${r.despachada ? `sim (sessao ${r.sessionId})` : 'nao'}`);
|
|
911
1431
|
if (r.motivo)
|
|
912
1432
|
linhas.push(` motivo ${r.motivo}`);
|
|
913
|
-
linhas.push(` detalhe ${r.detalhe}`);
|
|
1433
|
+
linhas.push(` detalhe ${(0, horario_1.localizarTexto)(r.detalhe)}`);
|
|
914
1434
|
linhas.push(` estado ${r.pedido.estado}`);
|
|
915
1435
|
}
|
|
1436
|
+
if (rs.some((r) => (0, horario_1.localizarTexto)(r.detalhe) !== r.detalhe))
|
|
1437
|
+
linhas.push((0, horario_1.legendaDoFuso)());
|
|
916
1438
|
return linhas.join('\n');
|
|
917
1439
|
}
|