@orkastery/cli 0.2.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 +21 -0
- package/README.md +87 -0
- package/adapters/README.md +22 -0
- package/adapters/claude-code/.claude-plugin/marketplace.json +15 -0
- package/adapters/claude-code/.claude-plugin/plugin.json +31 -0
- package/adapters/claude-code/README.md +102 -0
- package/adapters/claude-code/agents/ork-check.md +32 -0
- package/adapters/claude-code/agents/ork-go.md +32 -0
- package/adapters/claude-code/agents/ork-goal.md +33 -0
- package/adapters/claude-code/agents/ork-master.md +32 -0
- package/adapters/claude-code/agents/ork-plan.md +32 -0
- package/adapters/claude-code/agents/ork-ship.md +32 -0
- package/adapters/claude-code/commands/check.md +45 -0
- package/adapters/claude-code/commands/go.md +46 -0
- package/adapters/claude-code/commands/goal.md +54 -0
- package/adapters/claude-code/commands/master.md +42 -0
- package/adapters/claude-code/commands/ork.md +37 -0
- package/adapters/claude-code/commands/plan.md +47 -0
- package/adapters/claude-code/commands/ship.md +45 -0
- package/adapters/claude-code/hooks/hooks.json +17 -0
- package/adapters/claude-code/hooks/ork-guard.js +130 -0
- package/adapters/hermes/README.md +45 -0
- package/adapters/hermes/bin/ork-abrir-thread.sh +25 -0
- package/adapters/hermes/hermes.plugin.json +21 -0
- package/adapters/hermes/skills/orkastery-devmaster/SKILL.md +116 -0
- package/adapters/openclaw/README.md +63 -0
- package/adapters/openclaw/bin/ork-abrir-thread.sh +24 -0
- package/adapters/openclaw/openclaw.plugin.json +138 -0
- package/dist/adapters/claude-bg.js +308 -0
- package/dist/auditoria.js +848 -0
- package/dist/auditrun.js +976 -0
- package/dist/board.js +314 -0
- package/dist/canarios.js +271 -0
- package/dist/catalogo.js +124 -0
- package/dist/ciclos.js +156 -0
- package/dist/claims.js +226 -0
- package/dist/divida.js +374 -0
- package/dist/doctor.js +246 -0
- package/dist/evalrunner.js +458 -0
- package/dist/fix.js +450 -0
- package/dist/gates.js +92 -0
- package/dist/handoff.js +521 -0
- package/dist/hosts.js +331 -0
- package/dist/index.js +1910 -0
- package/dist/init.js +231 -0
- package/dist/leases.js +508 -0
- package/dist/ledger.js +138 -0
- package/dist/manifest.js +255 -0
- package/dist/master.js +453 -0
- package/dist/memoria.js +773 -0
- package/dist/modos.js +220 -0
- package/dist/orkmind.js +487 -0
- package/dist/orquestracao.js +559 -0
- package/dist/phase.js +572 -0
- package/dist/policies.js +176 -0
- package/dist/prompts.js +406 -0
- package/dist/ratelimit.js +179 -0
- package/dist/recall.js +252 -0
- package/dist/retry.js +917 -0
- package/dist/sandbox.js +94 -0
- package/dist/sessoes.js +104 -0
- package/dist/ship.js +551 -0
- package/dist/slug.js +100 -0
- package/dist/superficie.js +1347 -0
- package/dist/thread.js +333 -0
- package/dist/tokens.js +228 -0
- package/dist/types.js +20 -0
- package/dist/util.js +156 -0
- package/dist/verify.js +262 -0
- package/dist/worktree.js +576 -0
- package/dist/yaml.js +112 -0
- package/eval/README.md +85 -0
- package/eval/casos/check-quality.json +103 -0
- package/eval/casos/code-reviewer.json +102 -0
- package/eval/casos/decision-triage.json +103 -0
- package/eval/casos/go-implementation.json +103 -0
- package/eval/casos/goal-definition.json +103 -0
- package/eval/casos/master-metrics.json +103 -0
- package/eval/casos/narrative-guardian.json +163 -0
- package/eval/casos/orkastery-bootstrap.json +102 -0
- package/eval/casos/plan-specification.json +102 -0
- package/eval/casos/roadmap-keeper.json +103 -0
- package/eval/casos/scope-check-capability-map.json +83 -0
- package/eval/casos/security-auditor.json +102 -0
- package/eval/casos/ship-release.json +122 -0
- package/eval/casos/test-engineer.json +122 -0
- package/eval/casos/thread-state.json +82 -0
- package/eval/casos/thread-tracing.json +83 -0
- package/eval/casos/web-performance-auditor.json +102 -0
- package/eval/fixtures/b0-slug-e-modos/caso.json +56 -0
- package/eval/fixtures/b2-master-log/caso.json +91 -0
- package/eval/fixtures/fx-concurrency/caso.json +15 -0
- package/eval/fixtures/fx-hallucination/caso.json +12 -0
- package/eval/fixtures/fx-happy/caso.json +16 -0
- package/eval/fixtures/fx-schema-drift/caso.json +15 -0
- package/eval/fixtures/fx-stale-base/caso.json +12 -0
- package/eval/fixtures/fx-wiki-destroy/caso.json +16 -0
- package/eval/fixtures/superficie-de-rede/README.md +22 -0
- package/eval/fixtures/superficie-de-rede/api-express.js +30 -0
- package/eval/fixtures/superficie-de-rede/api_fastapi.py +17 -0
- package/eval/fixtures/superficie-de-rede/api_gin.go +18 -0
- package/package.json +56 -0
- package/references/README.md +25 -0
- package/references/code-review-axes.md +82 -0
- package/references/definition-of-done.md +74 -0
- package/references/performance-checklist.md +53 -0
- package/references/security-checklist.md +101 -0
- package/references/testing-patterns.md +51 -0
- package/skills/README.md +43 -0
- package/skills/core/orkastery-bootstrap/SKILL.md +89 -0
- package/skills/core/thread-state/SKILL.md +86 -0
- package/skills/governance/decision-triage/SKILL.md +65 -0
- package/skills/governance/narrative-guardian/SKILL.md +66 -0
- package/skills/governance/roadmap-keeper/SKILL.md +60 -0
- package/skills/governance/scope-check-capability-map/SKILL.md +61 -0
- package/skills/observability/thread-tracing/SKILL.md +63 -0
- package/skills/phases/check-quality/SKILL.md +87 -0
- package/skills/phases/go-implementation/SKILL.md +70 -0
- package/skills/phases/goal-definition/SKILL.md +69 -0
- package/skills/phases/master-metrics/SKILL.md +65 -0
- package/skills/phases/plan-specification/SKILL.md +67 -0
- package/skills/phases/ship-release/SKILL.md +68 -0
- package/skills/reviewers/code-reviewer/SKILL.md +61 -0
- package/skills/reviewers/security-auditor/SKILL.md +68 -0
- package/skills/reviewers/test-engineer/SKILL.md +66 -0
- package/skills/reviewers/web-performance-auditor/SKILL.md +63 -0
|
@@ -0,0 +1,848 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Os 7 packs de auditoria periodica e o hardening por estagio (bloco B5).
|
|
4
|
+
*
|
|
5
|
+
* A feature mandatoria do PO realiza a premissa (b) da visao: o builder cria em sessoes
|
|
6
|
+
* despreocupadas, e quem carrega o peso das boas praticas sao os auditores. A divisao de
|
|
7
|
+
* responsabilidade da visao (secao 5.1) e inegociavel e esta codificada aqui:
|
|
8
|
+
*
|
|
9
|
+
* - QUEM DISPARA e o orquestrador (cron/schedule do Hermes, OpenClaw ou Claude Code)
|
|
10
|
+
* chamando `ork audit run <pack> --profile <p> [--since Nd]`;
|
|
11
|
+
* - QUEM EXECUTA e o runtime adapter que JA existe (`claude-bg`), sem mecanismo novo;
|
|
12
|
+
* - O QUE SAI e sempre PROPOSTA DE AJUSTE para o roadmap do produto, nunca correcao
|
|
13
|
+
* aplicada direto;
|
|
14
|
+
* - O QUE O HUMANO FAZ e decidir o que vira thread (`ork thread new --from-finding`).
|
|
15
|
+
*
|
|
16
|
+
* Este modulo e o catalogo e as regras deterministicas em volta dele (estagio, postura,
|
|
17
|
+
* janela de custo, escopo incremental, template do prompt). Quem despacha e colhe achado
|
|
18
|
+
* e o `auditrun.ts`; quem guarda a divida e o `divida.ts`.
|
|
19
|
+
*/
|
|
20
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
21
|
+
if (k2 === undefined) k2 = k;
|
|
22
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
23
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
24
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
25
|
+
}
|
|
26
|
+
Object.defineProperty(o, k2, desc);
|
|
27
|
+
}) : (function(o, m, k, k2) {
|
|
28
|
+
if (k2 === undefined) k2 = k;
|
|
29
|
+
o[k2] = m[k];
|
|
30
|
+
}));
|
|
31
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
32
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
33
|
+
}) : function(o, v) {
|
|
34
|
+
o["default"] = v;
|
|
35
|
+
});
|
|
36
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
37
|
+
var ownKeys = function(o) {
|
|
38
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
39
|
+
var ar = [];
|
|
40
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
41
|
+
return ar;
|
|
42
|
+
};
|
|
43
|
+
return ownKeys(o);
|
|
44
|
+
};
|
|
45
|
+
return function (mod) {
|
|
46
|
+
if (mod && mod.__esModule) return mod;
|
|
47
|
+
var result = {};
|
|
48
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
49
|
+
__setModuleDefault(result, mod);
|
|
50
|
+
return result;
|
|
51
|
+
};
|
|
52
|
+
})();
|
|
53
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
54
|
+
exports.CONTRATO_DE_AUDITORIA = exports.REGRA_CENTRAL_DA_AUDITORIA = exports.SECOES_OBRIGATORIAS_DE_AUDITORIA = exports.REGRAS_DE_EVIDENCIA_DO_AUDITOR = exports.TEMPLATES_DE_AUDITORIA_EMBUTIDOS = exports.TEMPLATE_AUDITORIA_PADRAO = exports.ORDEM_DOS_PACKS = exports.PACKS = exports.DESCRICAO_DA_POSTURA = exports.POSTURA_DO_ESTAGIO = exports.ORDEM_DOS_ESTAGIOS = exports.DESCRICAO_DO_MOTIVO_DE_AUDITORIA = void 0;
|
|
55
|
+
exports.descreverMotivoDeAuditoria = descreverMotivoDeAuditoria;
|
|
56
|
+
exports.parseEstagio = parseEstagio;
|
|
57
|
+
exports.alcancou = alcancou;
|
|
58
|
+
exports.posturaDoPack = posturaDoPack;
|
|
59
|
+
exports.parsePack = parsePack;
|
|
60
|
+
exports.packsAtivos = packsAtivos;
|
|
61
|
+
exports.packAtivo = packAtivo;
|
|
62
|
+
exports.tabelaDePacks = tabelaDePacks;
|
|
63
|
+
exports.textoDoPack = textoDoPack;
|
|
64
|
+
exports.minutosDoHorario = minutosDoHorario;
|
|
65
|
+
exports.janelaDeCusto = janelaDeCusto;
|
|
66
|
+
exports.graphifyDisponivel = graphifyDisponivel;
|
|
67
|
+
exports.sinceParaGit = sinceParaGit;
|
|
68
|
+
exports.escopoDaRodada = escopoDaRodada;
|
|
69
|
+
exports.filtrarPelaFonte = filtrarPelaFonte;
|
|
70
|
+
exports.dirDeAuditores = dirDeAuditores;
|
|
71
|
+
exports.carregarTemplatesDeAuditoria = carregarTemplatesDeAuditoria;
|
|
72
|
+
exports.templateDoPack = templateDoPack;
|
|
73
|
+
exports.lintTemplateDeAuditoria = lintTemplateDeAuditoria;
|
|
74
|
+
exports.valoresDoPromptDeAuditoria = valoresDoPromptDeAuditoria;
|
|
75
|
+
exports.montarPromptDeAuditoria = montarPromptDeAuditoria;
|
|
76
|
+
const path = __importStar(require("node:path"));
|
|
77
|
+
const gates_1 = require("./gates");
|
|
78
|
+
const prompts_1 = require("./prompts");
|
|
79
|
+
const util_1 = require("./util");
|
|
80
|
+
// ---------------------------------------------------------------------------
|
|
81
|
+
// Motivos tipados da auditoria
|
|
82
|
+
// ---------------------------------------------------------------------------
|
|
83
|
+
/**
|
|
84
|
+
* O que cada motivo SO DA AUDITORIA significa. Os demais vem do catalogo do B1: o auditor
|
|
85
|
+
* reprova pelos mesmos motivos tipados de qualquer fase, porque ele nao tem regime proprio.
|
|
86
|
+
*/
|
|
87
|
+
exports.DESCRICAO_DO_MOTIVO_DE_AUDITORIA = {
|
|
88
|
+
...gates_1.DESCRICAO_DO_MOTIVO,
|
|
89
|
+
'custo.fora-da-janela': 'a rodada cairia fora da janela ociosa declarada no manifesto (governanca de custo)',
|
|
90
|
+
'pack.inativo-no-estagio': 'o pack ainda nao esta ativo no estagio declarado do produto',
|
|
91
|
+
'achado.sem-proposta': 'achado sem proposta de ajuste completa para o roadmap do produto',
|
|
92
|
+
'achado.duplicado-na-rodada': 'a mesma rodada ja registrou este achado (mesma regra, mesma evidencia)',
|
|
93
|
+
'achado.ja-virou-thread': 'o achado ja originou uma thread e nao pode originar outra',
|
|
94
|
+
};
|
|
95
|
+
/** Linha de saida do CLI para um motivo tipado de auditoria. */
|
|
96
|
+
function descreverMotivoDeAuditoria(motivo, detalhe) {
|
|
97
|
+
return `motivo tipado: ${motivo} (${exports.DESCRICAO_DO_MOTIVO_DE_AUDITORIA[motivo]})\n detalhe: ${detalhe}`;
|
|
98
|
+
}
|
|
99
|
+
// ---------------------------------------------------------------------------
|
|
100
|
+
// Estagios e postura (tabela da visao, secao 5.2)
|
|
101
|
+
// ---------------------------------------------------------------------------
|
|
102
|
+
/** Os estagios em ordem de maturidade. O roadmap promove; o pack acompanha. */
|
|
103
|
+
exports.ORDEM_DOS_ESTAGIOS = ['nascente', 'crescendo', 'maduro'];
|
|
104
|
+
/** Estagio valido a partir do texto do usuario, ou null. */
|
|
105
|
+
function parseEstagio(bruto) {
|
|
106
|
+
const alvo = (bruto ?? '').trim().toLowerCase();
|
|
107
|
+
return exports.ORDEM_DOS_ESTAGIOS.includes(alvo) ? alvo : null;
|
|
108
|
+
}
|
|
109
|
+
/** O estagio `a` ja alcancou o estagio `b`? */
|
|
110
|
+
function alcancou(a, b) {
|
|
111
|
+
return exports.ORDEM_DOS_ESTAGIOS.indexOf(a) >= exports.ORDEM_DOS_ESTAGIOS.indexOf(b);
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* A postura do estagio, na letra da tabela da visao (secao 5.2):
|
|
115
|
+
* nascente -> so `warn`: o builder cria livre, o auditor anota;
|
|
116
|
+
* crescendo -> achado critico vira proposta prioritaria no roadmap;
|
|
117
|
+
* maduro -> a recorrencia PROPOE promover a policy de `warn` para `block`.
|
|
118
|
+
*/
|
|
119
|
+
exports.POSTURA_DO_ESTAGIO = {
|
|
120
|
+
nascente: 'warn',
|
|
121
|
+
crescendo: 'proposta-prioritaria',
|
|
122
|
+
maduro: 'promove-policy',
|
|
123
|
+
};
|
|
124
|
+
/** O que cada postura significa, em uma linha, para a saida do CLI. */
|
|
125
|
+
exports.DESCRICAO_DA_POSTURA = {
|
|
126
|
+
warn: 'so avisa: o builder cria livre e o auditor anota',
|
|
127
|
+
'proposta-prioritaria': 'achado critico vira proposta prioritaria no roadmap do produto',
|
|
128
|
+
'promove-policy': 'a recorrencia propoe promover a policy de warn para block (2 propoem controle, 3 propoem bloqueante)',
|
|
129
|
+
};
|
|
130
|
+
/** A postura que vale para este pack neste estagio. */
|
|
131
|
+
function posturaDoPack(estagio) {
|
|
132
|
+
return exports.POSTURA_DO_ESTAGIO[estagio];
|
|
133
|
+
}
|
|
134
|
+
// ---------------------------------------------------------------------------
|
|
135
|
+
// Os 7 packs
|
|
136
|
+
// ---------------------------------------------------------------------------
|
|
137
|
+
/**
|
|
138
|
+
* O catalogo dos packs. Cada regra declara O QUE audita e QUE EVIDENCIA a comprova, porque
|
|
139
|
+
* e a evidencia que vai virar claim: um achado sem comando que o reexecute nao passa no
|
|
140
|
+
* `ork audit verify`, exatamente como uma alegacao de fase sem comando nao passa no gate.
|
|
141
|
+
*/
|
|
142
|
+
exports.PACKS = {
|
|
143
|
+
'clean-code': {
|
|
144
|
+
id: 'clean-code',
|
|
145
|
+
titulo: 'Clean code',
|
|
146
|
+
objetivo: 'Legibilidade e manutenibilidade do codigo novo, sem reescrever o que ja funciona.',
|
|
147
|
+
estagioMinimo: 'nascente',
|
|
148
|
+
fonte: 'codigo',
|
|
149
|
+
referencias: ['references/code-review-axes.md', 'references/definition-of-done.md'],
|
|
150
|
+
evidencias: [
|
|
151
|
+
'diff do escopo da rodada (`git diff --stat` da janela do --since)',
|
|
152
|
+
'caminho:linha de cada ocorrencia, nunca "varios arquivos"',
|
|
153
|
+
],
|
|
154
|
+
regras: [
|
|
155
|
+
{
|
|
156
|
+
id: 'CC1',
|
|
157
|
+
regra: 'Funcao ou arquivo muito acima da mediana do proprio repositorio, sem razao declarada.',
|
|
158
|
+
evidencia: 'comando que conta as linhas do alvo e mostra o numero (wc -l, awk sobre o arquivo)',
|
|
159
|
+
},
|
|
160
|
+
{
|
|
161
|
+
id: 'CC2',
|
|
162
|
+
regra: 'Bloco identico repetido em 3 ou mais lugares (candidato obvio a extracao).',
|
|
163
|
+
evidencia: 'grep -n do bloco mostrando as 3 ocorrencias com arquivo e linha',
|
|
164
|
+
},
|
|
165
|
+
{
|
|
166
|
+
id: 'CC3',
|
|
167
|
+
regra: 'Nome que mente: a funcao faz o que o nome nao diz, ou faz mais do que ele promete.',
|
|
168
|
+
evidencia: 'trecho citado com arquivo:linha e o efeito colateral nao anunciado pelo nome',
|
|
169
|
+
},
|
|
170
|
+
{
|
|
171
|
+
id: 'CC4',
|
|
172
|
+
regra: 'Erro engolido: catch vazio, promise sem tratamento, codigo de saida ignorado.',
|
|
173
|
+
evidencia: 'grep -n do catch ou da chamada sem checagem de retorno',
|
|
174
|
+
},
|
|
175
|
+
{
|
|
176
|
+
id: 'CC5',
|
|
177
|
+
regra: 'Comentario que descreve o "o que" (ja obvio no codigo) em vez do "por que".',
|
|
178
|
+
evidencia: 'comentario citado com arquivo:linha',
|
|
179
|
+
},
|
|
180
|
+
],
|
|
181
|
+
},
|
|
182
|
+
reuse: {
|
|
183
|
+
id: 'reuse',
|
|
184
|
+
titulo: 'Reuso',
|
|
185
|
+
objetivo: 'Impedir que o produto cresca reimplementando o que ele mesmo ja tem (a divida mais cara e a mais silenciosa).',
|
|
186
|
+
estagioMinimo: 'nascente',
|
|
187
|
+
fonte: 'codigo',
|
|
188
|
+
referencias: ['references/code-review-axes.md'],
|
|
189
|
+
evidencias: [
|
|
190
|
+
'os DOIS lados da duplicacao com caminho:linha (o novo e o que ja existia)',
|
|
191
|
+
'comando que prova que os dois existem ao mesmo tempo no HEAD',
|
|
192
|
+
],
|
|
193
|
+
regras: [
|
|
194
|
+
{
|
|
195
|
+
id: 'RU1',
|
|
196
|
+
regra: 'Utilitario novo que reimplementa um utilitario ja existente no proprio repositorio.',
|
|
197
|
+
evidencia: 'grep -n dos dois simbolos, com os dois caminhos',
|
|
198
|
+
},
|
|
199
|
+
{
|
|
200
|
+
id: 'RU2',
|
|
201
|
+
regra: 'Componente de interface duplicado fora do design system do produto.',
|
|
202
|
+
evidencia: 'caminho do componente novo e o caminho do equivalente no design system',
|
|
203
|
+
},
|
|
204
|
+
{
|
|
205
|
+
id: 'RU3',
|
|
206
|
+
regra: 'Dependencia nova para fazer o que a stack ja instalada faz.',
|
|
207
|
+
evidencia: 'a entrada no manifesto de pacotes e o modulo da stack que ja resolvia',
|
|
208
|
+
},
|
|
209
|
+
{
|
|
210
|
+
id: 'RU4',
|
|
211
|
+
regra: 'Regra de negocio repetida em dois modulos (fonte dupla de verdade).',
|
|
212
|
+
evidencia: 'grep -n da mesma regra nos dois modulos',
|
|
213
|
+
},
|
|
214
|
+
],
|
|
215
|
+
},
|
|
216
|
+
architecture: {
|
|
217
|
+
id: 'architecture',
|
|
218
|
+
titulo: 'Arquitetura',
|
|
219
|
+
objetivo: 'Manter as fronteiras do produto legiveis enquanto o MVP cresce.',
|
|
220
|
+
estagioMinimo: 'crescendo',
|
|
221
|
+
fonte: 'codigo',
|
|
222
|
+
referencias: ['references/code-review-axes.md', 'references/definition-of-done.md'],
|
|
223
|
+
evidencias: [
|
|
224
|
+
'o grafo de dependencia do escopo (Graphify quando disponivel, senao grep dirigido de imports)',
|
|
225
|
+
'a fronteira violada nomeada, com o import que a viola',
|
|
226
|
+
],
|
|
227
|
+
regras: [
|
|
228
|
+
{
|
|
229
|
+
id: 'AR1',
|
|
230
|
+
regra: 'Dependencia ciclica entre modulos.',
|
|
231
|
+
evidencia: 'os imports dos dois lados do ciclo, com arquivo:linha',
|
|
232
|
+
},
|
|
233
|
+
{
|
|
234
|
+
id: 'AR2',
|
|
235
|
+
regra: 'Camada violada: o nucleo importando adaptador, ou a interface importando implementacao.',
|
|
236
|
+
evidencia: 'grep -n do import proibido',
|
|
237
|
+
},
|
|
238
|
+
{
|
|
239
|
+
id: 'AR3',
|
|
240
|
+
regra: 'Responsabilidade sem dono unico: a mesma decisao tomada em dois lugares.',
|
|
241
|
+
evidencia: 'os dois pontos de decisao com arquivo:linha',
|
|
242
|
+
},
|
|
243
|
+
{
|
|
244
|
+
id: 'AR4',
|
|
245
|
+
regra: 'Acoplamento por estado global mutavel entre modulos que deveriam ser independentes.',
|
|
246
|
+
evidencia: 'a variavel de modulo e os pontos de escrita',
|
|
247
|
+
},
|
|
248
|
+
{
|
|
249
|
+
id: 'AR5',
|
|
250
|
+
regra: 'Fronteira externa sem contrato tipado (entrada ou saida em `any`/dicionario solto).',
|
|
251
|
+
evidencia: 'a assinatura no arquivo:linha',
|
|
252
|
+
},
|
|
253
|
+
],
|
|
254
|
+
},
|
|
255
|
+
'data-model': {
|
|
256
|
+
id: 'data-model',
|
|
257
|
+
titulo: 'Modelo de dados',
|
|
258
|
+
objetivo: 'Evitar que o esquema fique impossivel de corrigir depois que ha dado real dentro.',
|
|
259
|
+
estagioMinimo: 'crescendo',
|
|
260
|
+
fonte: 'codigo',
|
|
261
|
+
referencias: ['references/definition-of-done.md', 'references/testing-patterns.md'],
|
|
262
|
+
evidencias: [
|
|
263
|
+
'o DDL ou a migracao citada com caminho:linha',
|
|
264
|
+
'o passo irreversivel destacado quando o fix tocar dado existente',
|
|
265
|
+
],
|
|
266
|
+
regras: [
|
|
267
|
+
{
|
|
268
|
+
id: 'DM1',
|
|
269
|
+
regra: 'Indice unico que ignora soft-delete (a linha apagada continua bloqueando a nova).',
|
|
270
|
+
evidencia: 'o indice na migracao e a coluna de soft-delete que ele nao considera',
|
|
271
|
+
},
|
|
272
|
+
{
|
|
273
|
+
id: 'DM2',
|
|
274
|
+
regra: 'Migracao sem rollback declarado.',
|
|
275
|
+
evidencia: 'o arquivo de migracao sem o passo de volta',
|
|
276
|
+
},
|
|
277
|
+
{
|
|
278
|
+
id: 'DM3',
|
|
279
|
+
regra: 'Relacao sem integridade referencial declarada no banco.',
|
|
280
|
+
evidencia: 'a coluna de chave e a ausencia da constraint na migracao',
|
|
281
|
+
},
|
|
282
|
+
{
|
|
283
|
+
id: 'DM4',
|
|
284
|
+
regra: 'Coluna nullable que o codigo trata como obrigatoria (ou o contrario).',
|
|
285
|
+
evidencia: 'o DDL e o uso no codigo, os dois com arquivo:linha',
|
|
286
|
+
},
|
|
287
|
+
{
|
|
288
|
+
id: 'DM5',
|
|
289
|
+
regra: 'Desnormalizacao sem dono declarado da sincronizacao.',
|
|
290
|
+
evidencia: 'os dois lugares onde o mesmo dado e escrito',
|
|
291
|
+
},
|
|
292
|
+
],
|
|
293
|
+
},
|
|
294
|
+
ux: {
|
|
295
|
+
id: 'ux',
|
|
296
|
+
titulo: 'UX',
|
|
297
|
+
objetivo: 'Cobrir os estados que o builder nao ve na sessao feliz de criacao.',
|
|
298
|
+
estagioMinimo: 'crescendo',
|
|
299
|
+
fonte: 'codigo',
|
|
300
|
+
referencias: ['references/definition-of-done.md', 'references/performance-checklist.md'],
|
|
301
|
+
evidencias: [
|
|
302
|
+
'a tela ou componente com caminho:linha',
|
|
303
|
+
'o estado ausente nomeado (vazio, erro, carregando, sem permissao)',
|
|
304
|
+
],
|
|
305
|
+
regras: [
|
|
306
|
+
{
|
|
307
|
+
id: 'UX1',
|
|
308
|
+
regra: 'Estado vazio ausente: a lista sem itens nao explica nada ao usuario.',
|
|
309
|
+
evidencia: 'o componente de lista sem ramo para colecao vazia',
|
|
310
|
+
},
|
|
311
|
+
{
|
|
312
|
+
id: 'UX2',
|
|
313
|
+
regra: 'Estado de erro sem acao de saida (o usuario ve o erro e nao tem o que fazer).',
|
|
314
|
+
evidencia: 'o tratamento de erro sem acao de recuperacao',
|
|
315
|
+
},
|
|
316
|
+
{
|
|
317
|
+
id: 'UX3',
|
|
318
|
+
regra: 'Acao demorada sem retorno visual de progresso.',
|
|
319
|
+
evidencia: 'a chamada assincrona sem estado de carregamento associado',
|
|
320
|
+
},
|
|
321
|
+
{
|
|
322
|
+
id: 'UX4',
|
|
323
|
+
regra: 'Acessibilidade abaixo do minimo: foco invisivel, alvo sem rotulo, contraste insuficiente.',
|
|
324
|
+
evidencia: 'o elemento com arquivo:linha e o atributo ausente',
|
|
325
|
+
},
|
|
326
|
+
{
|
|
327
|
+
id: 'UX5',
|
|
328
|
+
regra: 'Acao destrutiva sem confirmacao nem desfazer.',
|
|
329
|
+
evidencia: 'o handler da acao destrutiva',
|
|
330
|
+
},
|
|
331
|
+
],
|
|
332
|
+
},
|
|
333
|
+
'security-privacy': {
|
|
334
|
+
id: 'security-privacy',
|
|
335
|
+
titulo: 'Seguranca e privacidade (inclui LGPD e superficie de ataque de rede)',
|
|
336
|
+
objetivo: 'O pack que so entra quando ha usuario real, porque e quando o dado de gente de verdade passa a estar em jogo. Cobre seguranca de codigo, LGPD e a SUPERFICIE DE ATAQUE DE REDE que o produto publica (rotas e endpoints expostos).',
|
|
337
|
+
estagioMinimo: 'maduro',
|
|
338
|
+
fonte: 'codigo',
|
|
339
|
+
referencias: ['references/security-checklist.md', 'references/definition-of-done.md'],
|
|
340
|
+
evidencias: [
|
|
341
|
+
'caminho:linha do ponto exato, NUNCA o segredo ou o dado pessoal em si',
|
|
342
|
+
'o titular do dado e a base legal, quando o achado for de LGPD',
|
|
343
|
+
'nas regras de superficie de rede (SP8..SP12), a saida da varredura deterministica do proprio `ork` (`ork audit surface`), com o framework reconhecido e o nivel de confianca de cada achado',
|
|
344
|
+
],
|
|
345
|
+
regras: [
|
|
346
|
+
{
|
|
347
|
+
id: 'SP1',
|
|
348
|
+
regra: 'Segredo em codigo, em log ou em arquivo versionado.',
|
|
349
|
+
evidencia: 'o NOME do padrao e o arquivo:linha, com o trecho omitido de proposito',
|
|
350
|
+
},
|
|
351
|
+
{
|
|
352
|
+
id: 'SP2',
|
|
353
|
+
regra: 'LGPD: dado pessoal em log, em telemetria ou em mensagem de erro.',
|
|
354
|
+
evidencia: 'a chamada de log e o campo pessoal que ela carrega',
|
|
355
|
+
},
|
|
356
|
+
{
|
|
357
|
+
id: 'SP3',
|
|
358
|
+
regra: 'LGPD: dado pessoal armazenado sem prazo de retencao declarado.',
|
|
359
|
+
evidencia: 'a tabela ou colecao e a ausencia de politica de expurgo',
|
|
360
|
+
},
|
|
361
|
+
{
|
|
362
|
+
id: 'SP4',
|
|
363
|
+
regra: 'LGPD: coleta sem base legal registrada (consentimento sem registro de quando e do que).',
|
|
364
|
+
evidencia: 'o ponto de coleta e a ausencia do registro de consentimento',
|
|
365
|
+
},
|
|
366
|
+
{
|
|
367
|
+
id: 'SP5',
|
|
368
|
+
regra: 'LGPD: direito de exclusao sem caminho executavel (nao ha como apagar o titular).',
|
|
369
|
+
evidencia: 'a ausencia da rotina de exclusao para os dados do titular',
|
|
370
|
+
},
|
|
371
|
+
{
|
|
372
|
+
id: 'SP6',
|
|
373
|
+
regra: 'Entrada de fronteira externa usada sem validacao.',
|
|
374
|
+
evidencia: 'o handler e o uso direto do dado de entrada',
|
|
375
|
+
},
|
|
376
|
+
{
|
|
377
|
+
id: 'SP7',
|
|
378
|
+
regra: 'Dependencia com vulnerabilidade conhecida no manifesto de pacotes.',
|
|
379
|
+
evidencia: 'a saida real do auditor de dependencias da stack',
|
|
380
|
+
},
|
|
381
|
+
{
|
|
382
|
+
id: 'SP8',
|
|
383
|
+
regra: 'Superficie de rede: rota de servidor HTTP/API declarada em producao sem camada de autenticacao/autorizacao.',
|
|
384
|
+
evidencia: 'a definicao da rota com arquivo:linha, o framework reconhecido e o comando que prova a ausencia de guarda no bloco da rota (ou no arquivo inteiro)',
|
|
385
|
+
},
|
|
386
|
+
{
|
|
387
|
+
id: 'SP9',
|
|
388
|
+
regra: 'Superficie de rede: endpoint privado de administracao ou operacao (admin, console, debug, swagger/openapi, health detalhado, metadados de cluster) exposto sem restricao de rede nem oAuth.',
|
|
389
|
+
evidencia: 'o endpoint administrativo com arquivo:linha e o comando que prova a ausencia de allowlist de rede, basic auth ou oAuth',
|
|
390
|
+
},
|
|
391
|
+
{
|
|
392
|
+
id: 'SP10',
|
|
393
|
+
regra: 'Superficie de rede: rota sem limite de taxa, sujeita a brute-force, enumeracao e DDoS de aplicacao.',
|
|
394
|
+
evidencia: 'a rota com arquivo:linha e o comando que prova a ausencia de middleware de limite, cota ou rpm no bloco e no arquivo',
|
|
395
|
+
},
|
|
396
|
+
{
|
|
397
|
+
id: 'SP11',
|
|
398
|
+
regra: 'Superficie de rede: CORS permissivo demais (origem global com credenciais habilitadas, ou origem aberta em arquivo que serve rota de dado sensivel).',
|
|
399
|
+
evidencia: 'a configuracao de CORS com arquivo:linha, o curinga de origem e a flag de credenciais, cada um com o comando que o reexecuta',
|
|
400
|
+
},
|
|
401
|
+
{
|
|
402
|
+
id: 'SP12',
|
|
403
|
+
regra: 'Superficie de rede: definicao de rota sem esquema/validacao do payload na borda (complementa o SP6, que olha o USO do dado dentro do handler).',
|
|
404
|
+
evidencia: 'a definicao da rota com arquivo:linha e o comando que prova a ausencia de schema/validador na definicao',
|
|
405
|
+
},
|
|
406
|
+
],
|
|
407
|
+
},
|
|
408
|
+
process: {
|
|
409
|
+
id: 'process',
|
|
410
|
+
titulo: 'Processo (meta-auditor)',
|
|
411
|
+
objetivo: 'O unico pack que audita o METODO e nao o produto: le o ledger, os POSTMORTEMs e os MASTER logs e propoe mudanca no proprio Orkastery.',
|
|
412
|
+
estagioMinimo: 'maduro',
|
|
413
|
+
fonte: 'ledger',
|
|
414
|
+
referencias: ['references/definition-of-done.md'],
|
|
415
|
+
evidencias: [
|
|
416
|
+
'.orkastery/threads/<id>/ledger.jsonl com o evento citado',
|
|
417
|
+
'.orkastery/threads/<id>/POSTMORTEM.json e master-log.json quando houver',
|
|
418
|
+
],
|
|
419
|
+
regras: [
|
|
420
|
+
{
|
|
421
|
+
id: 'PR1',
|
|
422
|
+
regra: 'Entrega sem MASTER log (uma entrega sem MASTER log nao aconteceu).',
|
|
423
|
+
evidencia: 'o evento ship_done no ledger e a ausencia do master-log.json da mesma thread',
|
|
424
|
+
},
|
|
425
|
+
{
|
|
426
|
+
id: 'PR2',
|
|
427
|
+
regra: 'Thread entregue sem score humano registrado, parada na fila de batch.',
|
|
428
|
+
evidencia: 'o thread.json com score null e o ship_done correspondente',
|
|
429
|
+
},
|
|
430
|
+
{
|
|
431
|
+
id: 'PR3',
|
|
432
|
+
regra: 'O mesmo motivo tipado de gate reprovando de novo em threads diferentes.',
|
|
433
|
+
evidencia: 'os eventos gate_blocked com o mesmo motivo, em threads distintas',
|
|
434
|
+
},
|
|
435
|
+
{
|
|
436
|
+
id: 'PR4',
|
|
437
|
+
regra: 'Claim nao-verificavel recorrente: a fase alega e nao declara como comprovar.',
|
|
438
|
+
evidencia: 'as claims com estado nao-verificavel no claims.jsonl das threads',
|
|
439
|
+
},
|
|
440
|
+
{
|
|
441
|
+
id: 'PR5',
|
|
442
|
+
regra: 'Decisao autonoma sem evidencia declarada no ledger.',
|
|
443
|
+
evidencia: 'o evento autonomous_decision sem campo de evidencia',
|
|
444
|
+
},
|
|
445
|
+
{
|
|
446
|
+
id: 'PR6',
|
|
447
|
+
regra: 'Classe de falha recorrente no POSTMORTEM sem controle correspondente.',
|
|
448
|
+
evidencia: 'as classes de falha repetidas nos POSTMORTEMs, com as threads que as levaram',
|
|
449
|
+
},
|
|
450
|
+
],
|
|
451
|
+
},
|
|
452
|
+
};
|
|
453
|
+
/** Ordem canonica dos packs: a ordem em que os estagios os ativam. */
|
|
454
|
+
exports.ORDEM_DOS_PACKS = [
|
|
455
|
+
'clean-code',
|
|
456
|
+
'reuse',
|
|
457
|
+
'architecture',
|
|
458
|
+
'data-model',
|
|
459
|
+
'ux',
|
|
460
|
+
'security-privacy',
|
|
461
|
+
'process',
|
|
462
|
+
];
|
|
463
|
+
/** Pack valido a partir do texto do usuario, ou null. */
|
|
464
|
+
function parsePack(bruto) {
|
|
465
|
+
const alvo = (bruto ?? '').trim().toLowerCase();
|
|
466
|
+
return exports.ORDEM_DOS_PACKS.includes(alvo) ? alvo : null;
|
|
467
|
+
}
|
|
468
|
+
/** Os packs ativos no estagio informado (a coluna "Packs ativos" da visao 5.2). */
|
|
469
|
+
function packsAtivos(estagio) {
|
|
470
|
+
return exports.ORDEM_DOS_PACKS.filter((p) => alcancou(estagio, exports.PACKS[p].estagioMinimo));
|
|
471
|
+
}
|
|
472
|
+
/** O pack ja esta ativo neste estagio? */
|
|
473
|
+
function packAtivo(pack, estagio) {
|
|
474
|
+
return alcancou(estagio, exports.PACKS[pack].estagioMinimo);
|
|
475
|
+
}
|
|
476
|
+
/** Tabela de `ork audit packs`. */
|
|
477
|
+
function tabelaDePacks(estagio) {
|
|
478
|
+
const linhas = exports.ORDEM_DOS_PACKS.map((id) => {
|
|
479
|
+
const p = exports.PACKS[id];
|
|
480
|
+
const ativo = estagio ? (packAtivo(id, estagio) ? 'sim' : 'nao') : '-';
|
|
481
|
+
return [
|
|
482
|
+
p.id,
|
|
483
|
+
p.estagioMinimo,
|
|
484
|
+
ativo,
|
|
485
|
+
p.fonte,
|
|
486
|
+
String(p.regras.length),
|
|
487
|
+
estagio && packAtivo(id, estagio) ? posturaDoPack(estagio) : '-',
|
|
488
|
+
p.titulo,
|
|
489
|
+
];
|
|
490
|
+
});
|
|
491
|
+
const cabecalho = (0, util_1.tabela)(['PACK', 'ATIVO A PARTIR DE', 'ATIVO AQUI', 'FONTE', 'REGRAS', 'POSTURA', 'TITULO'], linhas);
|
|
492
|
+
const rodape = ['', 'Hardening por estagio (visao, secao 5.2):'];
|
|
493
|
+
for (const e of exports.ORDEM_DOS_ESTAGIOS) {
|
|
494
|
+
rodape.push(` ${e.padEnd(10)} ${packsAtivos(e).join(', ')}` +
|
|
495
|
+
`\n ${' '.repeat(10)} postura: ${exports.DESCRICAO_DA_POSTURA[exports.POSTURA_DO_ESTAGIO[e]]}`);
|
|
496
|
+
}
|
|
497
|
+
return cabecalho + '\n' + rodape.join('\n');
|
|
498
|
+
}
|
|
499
|
+
/** Detalhe de um pack: as regras e as evidencias que ele exige. */
|
|
500
|
+
function textoDoPack(pack, estagio) {
|
|
501
|
+
const p = exports.PACKS[pack];
|
|
502
|
+
const linhas = [];
|
|
503
|
+
linhas.push(`Pack ${p.id}: ${p.titulo}`);
|
|
504
|
+
linhas.push(` ${p.objetivo}`);
|
|
505
|
+
linhas.push(` ativo a partir do estagio: ${p.estagioMinimo}`);
|
|
506
|
+
linhas.push(` fonte de evidencia: ${p.fonte === 'ledger' ? 'ledger e MASTER logs' : 'arvore de codigo'}`);
|
|
507
|
+
if (estagio) {
|
|
508
|
+
linhas.push(` neste projeto (stage ${estagio}): ${packAtivo(pack, estagio) ? 'ATIVO' : 'inativo'}` +
|
|
509
|
+
(packAtivo(pack, estagio) ? `, postura ${posturaDoPack(estagio)}` : ''));
|
|
510
|
+
}
|
|
511
|
+
linhas.push('');
|
|
512
|
+
linhas.push(' Regras auditadas:');
|
|
513
|
+
for (const r of p.regras) {
|
|
514
|
+
linhas.push(` ${r.id} ${r.regra}`);
|
|
515
|
+
linhas.push(` evidencia: ${r.evidencia}`);
|
|
516
|
+
}
|
|
517
|
+
linhas.push('');
|
|
518
|
+
linhas.push(' Evidencias da rodada:');
|
|
519
|
+
for (const e of p.evidencias)
|
|
520
|
+
linhas.push(` - ${e}`);
|
|
521
|
+
linhas.push('');
|
|
522
|
+
linhas.push(` Checklists normativas citaveis: ${p.referencias.join(', ')}`);
|
|
523
|
+
return linhas.join('\n');
|
|
524
|
+
}
|
|
525
|
+
// ---------------------------------------------------------------------------
|
|
526
|
+
// Governanca de custo (visao, secao 5.3)
|
|
527
|
+
// ---------------------------------------------------------------------------
|
|
528
|
+
/** `HH:MM` para minutos desde a meia-noite, ou null quando o texto nao e um horario. */
|
|
529
|
+
function minutosDoHorario(bruto) {
|
|
530
|
+
const casado = /^(\d{1,2}):(\d{2})$/.exec(bruto.trim());
|
|
531
|
+
if (!casado)
|
|
532
|
+
return null;
|
|
533
|
+
const h = Number(casado[1]);
|
|
534
|
+
const m = Number(casado[2]);
|
|
535
|
+
if (h > 23 || m > 59)
|
|
536
|
+
return null;
|
|
537
|
+
return h * 60 + m;
|
|
538
|
+
}
|
|
539
|
+
/**
|
|
540
|
+
* A janela ociosa declarada no manifesto, avaliada contra o horario informado.
|
|
541
|
+
*
|
|
542
|
+
* Janela que atravessa a meia-noite (`22:00-06:00`) e o caso comum, entao ela e tratada
|
|
543
|
+
* como intervalo circular. Janela nao declarada NAO vira "sempre pode": ela vira
|
|
544
|
+
* `declarada: false`, e o CLI diz em voz alta que so `eco` e o escopo incremental estao
|
|
545
|
+
* governando o custo daquela rodada.
|
|
546
|
+
*/
|
|
547
|
+
function janelaDeCusto(manifesto, quando = new Date()) {
|
|
548
|
+
const hh = String(quando.getHours()).padStart(2, '0');
|
|
549
|
+
const mm = String(quando.getMinutes()).padStart(2, '0');
|
|
550
|
+
const agora = `${hh}:${mm}`;
|
|
551
|
+
const bruta = (manifesto.audit?.janela_ociosa ?? '').trim();
|
|
552
|
+
if (bruta === '') {
|
|
553
|
+
return {
|
|
554
|
+
declarada: false,
|
|
555
|
+
inicio: '',
|
|
556
|
+
fim: '',
|
|
557
|
+
dentro: true,
|
|
558
|
+
agora,
|
|
559
|
+
detalhe: 'audit.janela_ociosa nao declarada no manifesto: o custo desta rodada e governado apenas por effort eco e escopo incremental',
|
|
560
|
+
};
|
|
561
|
+
}
|
|
562
|
+
const partes = bruta.split('-');
|
|
563
|
+
const inicio = minutosDoHorario(partes[0] ?? '');
|
|
564
|
+
const fim = minutosDoHorario(partes[1] ?? '');
|
|
565
|
+
if (inicio === null || fim === null) {
|
|
566
|
+
return {
|
|
567
|
+
declarada: false,
|
|
568
|
+
inicio: '',
|
|
569
|
+
fim: '',
|
|
570
|
+
dentro: true,
|
|
571
|
+
agora,
|
|
572
|
+
detalhe: `audit.janela_ociosa invalida ("${bruta}"): esperado HH:MM-HH:MM`,
|
|
573
|
+
};
|
|
574
|
+
}
|
|
575
|
+
const minutosAgora = quando.getHours() * 60 + quando.getMinutes();
|
|
576
|
+
const dentro = inicio <= fim
|
|
577
|
+
? minutosAgora >= inicio && minutosAgora < fim
|
|
578
|
+
: minutosAgora >= inicio || minutosAgora < fim;
|
|
579
|
+
return {
|
|
580
|
+
declarada: true,
|
|
581
|
+
inicio: partes[0].trim(),
|
|
582
|
+
fim: partes[1].trim(),
|
|
583
|
+
dentro,
|
|
584
|
+
agora,
|
|
585
|
+
detalhe: dentro
|
|
586
|
+
? `${agora} esta dentro da janela ociosa ${bruta}`
|
|
587
|
+
: `${agora} esta FORA da janela ociosa ${bruta}`,
|
|
588
|
+
};
|
|
589
|
+
}
|
|
590
|
+
/** O Graphify existe nesta maquina? Fonte externa, nunca suposicao. */
|
|
591
|
+
function graphifyDisponivel() {
|
|
592
|
+
return (0, util_1.noPath)('graphify') !== null;
|
|
593
|
+
}
|
|
594
|
+
/**
|
|
595
|
+
* Traduz a janela do contrato (`7d`, `24h`, `2w`) para o que o git entende.
|
|
596
|
+
*
|
|
597
|
+
* MEDIDO: `git log --since=30d` devolve VAZIO, porque a approxidate do git nao le `30d`;
|
|
598
|
+
* `--since="30 days ago"` devolve os commits. Sem esta traducao, `--since 7d` produziria
|
|
599
|
+
* escopo vazio em silencio, e uma auditoria que nao le nada passaria por auditoria limpa,
|
|
600
|
+
* que e o pior defeito possivel neste bloco. Formato que o git ja entende passa direto.
|
|
601
|
+
*/
|
|
602
|
+
function sinceParaGit(bruto) {
|
|
603
|
+
const casado = /^(\d+)\s*([dhwm])$/i.exec(bruto.trim());
|
|
604
|
+
if (!casado)
|
|
605
|
+
return bruto.trim();
|
|
606
|
+
const unidade = { d: 'days', h: 'hours', w: 'weeks', m: 'months' }[casado[2].toLowerCase()];
|
|
607
|
+
return `${casado[1]} ${unidade} ago`;
|
|
608
|
+
}
|
|
609
|
+
/**
|
|
610
|
+
* O escopo da rodada.
|
|
611
|
+
*
|
|
612
|
+
* Escopo incremental e a principal alavanca de custo: `--since 7d` faz o auditor ler o que
|
|
613
|
+
* mudou na janela, e nao o repositorio inteiro. Quando o git nao devolve nada (repo novo,
|
|
614
|
+
* janela sem commit), a rodada declara escopo vazio em vez de silenciosamente virar total.
|
|
615
|
+
*/
|
|
616
|
+
function escopoDaRodada(raiz, manifesto, opcoes = {}) {
|
|
617
|
+
const graphifyLigado = (manifesto.audit?.graphify ?? 'auto') !== 'off';
|
|
618
|
+
const graphify = !graphifyLigado
|
|
619
|
+
? 'desligado'
|
|
620
|
+
: graphifyDisponivel()
|
|
621
|
+
? 'disponivel'
|
|
622
|
+
: 'ausente';
|
|
623
|
+
if (opcoes.tudo) {
|
|
624
|
+
return {
|
|
625
|
+
since: null,
|
|
626
|
+
incremental: false,
|
|
627
|
+
arquivos: [],
|
|
628
|
+
total: 0,
|
|
629
|
+
graphify,
|
|
630
|
+
detalhe: 'escopo TOTAL pedido com --tudo: a rodada le o produto inteiro (custo maximo)',
|
|
631
|
+
};
|
|
632
|
+
}
|
|
633
|
+
const since = (opcoes.since ?? manifesto.audit?.since_padrao ?? '').trim();
|
|
634
|
+
if (since === '') {
|
|
635
|
+
return {
|
|
636
|
+
since: null,
|
|
637
|
+
incremental: false,
|
|
638
|
+
arquivos: [],
|
|
639
|
+
total: 0,
|
|
640
|
+
graphify,
|
|
641
|
+
detalhe: 'sem --since e sem audit.since_padrao: escopo total por ausencia de janela declarada',
|
|
642
|
+
};
|
|
643
|
+
}
|
|
644
|
+
const r = (0, util_1.exec)('git', ['log', `--since=${sinceParaGit(since)}`, '--name-only', '--pretty=format:'], raiz);
|
|
645
|
+
const tocados = [
|
|
646
|
+
...new Set(r.stdout
|
|
647
|
+
.split('\n')
|
|
648
|
+
.map((l) => l.trim())
|
|
649
|
+
.filter((l) => l !== '')),
|
|
650
|
+
].sort();
|
|
651
|
+
const arquivos = filtrarPelaFonte(tocados, opcoes.pack);
|
|
652
|
+
const cortados = tocados.length - arquivos.length;
|
|
653
|
+
return {
|
|
654
|
+
since,
|
|
655
|
+
incremental: true,
|
|
656
|
+
arquivos,
|
|
657
|
+
total: arquivos.length,
|
|
658
|
+
graphify,
|
|
659
|
+
detalhe: arquivos.length > 0
|
|
660
|
+
? `escopo incremental: ${arquivos.length} arquivo(s) tocado(s) nos ultimos ${since}` +
|
|
661
|
+
(cortados > 0 ? ` (${cortados} fora da fonte do pack)` : '')
|
|
662
|
+
: `escopo incremental vazio: nenhum arquivo da fonte do pack mudou nos ultimos ${since}`,
|
|
663
|
+
};
|
|
664
|
+
}
|
|
665
|
+
/**
|
|
666
|
+
* Corta do escopo o que nao pertence a FONTE declarada do pack.
|
|
667
|
+
*
|
|
668
|
+
* Um pack de codigo nao audita o estado do proprio motor (`.orkastery/`), e o meta-auditor
|
|
669
|
+
* `process` audita EXATAMENTE esse estado e nada mais. Sem este corte, uma rodada de
|
|
670
|
+
* clean-code gastaria janela lendo ledger, e o `process` gastaria lendo codigo de produto.
|
|
671
|
+
*/
|
|
672
|
+
function filtrarPelaFonte(arquivos, pack) {
|
|
673
|
+
if (!pack)
|
|
674
|
+
return arquivos;
|
|
675
|
+
const doMotor = (a) => a.startsWith('.orkastery/') || a.startsWith('docs/audit/');
|
|
676
|
+
return exports.PACKS[pack].fonte === 'ledger' ? arquivos.filter(doMotor) : arquivos.filter((a) => !doMotor(a));
|
|
677
|
+
}
|
|
678
|
+
// ---------------------------------------------------------------------------
|
|
679
|
+
// O template do prompt do auditor
|
|
680
|
+
// ---------------------------------------------------------------------------
|
|
681
|
+
/** Onde um projeto versiona os prompts dos seus packs (diretorio reservado desde o B0). */
|
|
682
|
+
function dirDeAuditores(raiz) {
|
|
683
|
+
return path.join(raiz, 'auditors');
|
|
684
|
+
}
|
|
685
|
+
/**
|
|
686
|
+
* O template embutido do prompt de auditoria.
|
|
687
|
+
*
|
|
688
|
+
* Ele nao vive em `TEMPLATES_EMBUTIDOS` de proposito: um prompt de auditoria nao tem fase,
|
|
689
|
+
* nem bloco, nem pausa, e o lint de `ork prompt lint` cobra secoes que so fazem sentido em
|
|
690
|
+
* prompt de fase. O que ele reusa e a maquinaria de template (parse, render, lint), nao o
|
|
691
|
+
* contrato do prompt de fase.
|
|
692
|
+
*/
|
|
693
|
+
exports.TEMPLATE_AUDITORIA_PADRAO = `---
|
|
694
|
+
id: auditoria-padrao
|
|
695
|
+
versao: 1
|
|
696
|
+
descricao: Prompt canonico de uma rodada de auditoria periodica, com as regras do pack, o escopo, a governanca de custo e o bloco obrigatorio de propostas.
|
|
697
|
+
variaveis: [pack, titulo, objetivo, produto, perfil, estagio, postura, descricao_da_postura, fonte, rodada, dir_da_rodada, regras, evidencias, referencias, escopo, linha_graphify, effort, linha_janela, comando_de_registro, regras_de_evidencia]
|
|
698
|
+
---
|
|
699
|
+
# Orkastery, auditoria periodica: pack {{pack}} ({{titulo}})
|
|
700
|
+
|
|
701
|
+
Voce conduz a rodada {{rodada}} do pack {{pack}} sobre o produto "{{produto}}" (perfil {{perfil}}).
|
|
702
|
+
|
|
703
|
+
## Objetivo do pack
|
|
704
|
+
{{objetivo}}
|
|
705
|
+
|
|
706
|
+
## Estagio e postura
|
|
707
|
+
- estagio declarado do produto: {{estagio}}
|
|
708
|
+
- postura desta rodada: {{postura}} ({{descricao_da_postura}})
|
|
709
|
+
- fonte de evidencia: {{fonte}}
|
|
710
|
+
|
|
711
|
+
REGRA CENTRAL DA AUDITORIA: a saida e sempre PROPOSTA DE AJUSTE para o roadmap do produto.
|
|
712
|
+
Voce NAO corrige nada, nao commita, nao abre branch e nao roda passo irreversivel.
|
|
713
|
+
|
|
714
|
+
## Regras auditadas
|
|
715
|
+
{{regras}}
|
|
716
|
+
|
|
717
|
+
## Evidencias exigidas
|
|
718
|
+
{{evidencias}}
|
|
719
|
+
|
|
720
|
+
## Escopo desta rodada (governanca de custo)
|
|
721
|
+
{{escopo}}
|
|
722
|
+
{{linha_graphify}}
|
|
723
|
+
{{linha_janela}}
|
|
724
|
+
- esforco desta rodada: {{effort}}
|
|
725
|
+
|
|
726
|
+
## Checklists normativas citaveis por item
|
|
727
|
+
{{referencias}}
|
|
728
|
+
|
|
729
|
+
## Bloco OBRIGATORIO de propostas
|
|
730
|
+
A rodada so termina quando cada achado virar uma proposta enderecada ao roadmap de "{{produto}}",
|
|
731
|
+
com os cinco campos: evidencia arquivo:linha, impacto, fix sugerido, passo irreversivel e
|
|
732
|
+
estimativa. Achado sem proposta completa e recusado pelo \`ork\`, nao por opiniao.
|
|
733
|
+
|
|
734
|
+
## Como registrar (o \`ork\` e o unico escritor)
|
|
735
|
+
Escreva os achados em {{dir_da_rodada}}/achados.json e registre com:
|
|
736
|
+
|
|
737
|
+
{{comando_de_registro}}
|
|
738
|
+
|
|
739
|
+
## Regras de evidencia
|
|
740
|
+
{{regras_de_evidencia}}`;
|
|
741
|
+
/** Os templates de auditoria que vem dentro do `ork`, por id. */
|
|
742
|
+
exports.TEMPLATES_DE_AUDITORIA_EMBUTIDOS = {
|
|
743
|
+
'auditoria-padrao': exports.TEMPLATE_AUDITORIA_PADRAO,
|
|
744
|
+
};
|
|
745
|
+
/** As regras de evidencia que valem para todo auditor, em todo pack. */
|
|
746
|
+
exports.REGRAS_DE_EVIDENCIA_DO_AUDITOR = [
|
|
747
|
+
'O auditor NAO tem direito a self-report: todo achado carrega o comando que o reexecuta no HEAD real.',
|
|
748
|
+
'Evidencia e arquivo:linha, nunca "varios lugares" nem "o codigo em geral".',
|
|
749
|
+
'Alegacao negativa ou absoluta ("nenhum", "sempre", "zero") SEM comando e reprovada por `ork audit verify`.',
|
|
750
|
+
'Nunca imprima o segredo nem o dado pessoal encontrado: cite o padrao e a posicao.',
|
|
751
|
+
'Nenhum passo irreversivel: a rodada e somente leitura, e a correcao e proposta ao roadmap.',
|
|
752
|
+
'NUNCA altere o estado do git: nada de reset, checkout, restore, stash, add, commit ou branch.',
|
|
753
|
+
];
|
|
754
|
+
/**
|
|
755
|
+
* Os templates de auditoria que valem para este projeto: o embutido, sobrescrito por
|
|
756
|
+
* `auditors/auditoria-<pack>.md` ou `auditors/auditoria-padrao.md` versionado no projeto.
|
|
757
|
+
*/
|
|
758
|
+
function carregarTemplatesDeAuditoria(raiz) {
|
|
759
|
+
return (0, prompts_1.carregarTemplatesDe)(exports.TEMPLATES_DE_AUDITORIA_EMBUTIDOS, raiz ? dirDeAuditores(raiz) : undefined);
|
|
760
|
+
}
|
|
761
|
+
/** O template que conduz o pack: o especifico do pack, senao o padrao. */
|
|
762
|
+
function templateDoPack(pack, raiz) {
|
|
763
|
+
const templates = carregarTemplatesDeAuditoria(raiz);
|
|
764
|
+
const especifico = templates.find((t) => t.id === `auditoria-${pack}`);
|
|
765
|
+
if (especifico)
|
|
766
|
+
return especifico;
|
|
767
|
+
const padrao = templates.find((t) => t.id === 'auditoria-padrao');
|
|
768
|
+
if (!padrao)
|
|
769
|
+
throw new Error('template `auditoria-padrao` ausente: o `ork` nao tem prompt de auditoria');
|
|
770
|
+
return padrao;
|
|
771
|
+
}
|
|
772
|
+
/** Secoes que todo template de auditoria precisa carregar para continuar sendo uma auditoria. */
|
|
773
|
+
exports.SECOES_OBRIGATORIAS_DE_AUDITORIA = [
|
|
774
|
+
'## Regras auditadas',
|
|
775
|
+
'## Evidencias exigidas',
|
|
776
|
+
'## Escopo desta rodada',
|
|
777
|
+
'## Bloco OBRIGATORIO de propostas',
|
|
778
|
+
'## Regras de evidencia',
|
|
779
|
+
];
|
|
780
|
+
/** A frase que nenhum template de auditoria pode perder. */
|
|
781
|
+
exports.REGRA_CENTRAL_DA_AUDITORIA = 'REGRA CENTRAL DA AUDITORIA: a saida e sempre PROPOSTA DE AJUSTE para o roadmap do produto.';
|
|
782
|
+
/**
|
|
783
|
+
* O contrato do prompt de auditoria, no mesmo formato do contrato do prompt de fase.
|
|
784
|
+
*
|
|
785
|
+
* Um template de auditoria nao tem fase nem pedido do builder (a demanda dele vem do pack),
|
|
786
|
+
* mas tem o bloco obrigatorio de propostas: sem ele a rodada deixaria de ser auditoria e
|
|
787
|
+
* viraria relatorio.
|
|
788
|
+
*/
|
|
789
|
+
exports.CONTRATO_DE_AUDITORIA = {
|
|
790
|
+
nome: 'auditoria',
|
|
791
|
+
secoes: exports.SECOES_OBRIGATORIAS_DE_AUDITORIA,
|
|
792
|
+
regraCentral: exports.REGRA_CENTRAL_DA_AUDITORIA,
|
|
793
|
+
variavelObrigatoria: null,
|
|
794
|
+
validaFases: false,
|
|
795
|
+
};
|
|
796
|
+
/**
|
|
797
|
+
* Lint do template de auditoria.
|
|
798
|
+
*
|
|
799
|
+
* Reusa o `lintTemplate` do B4 trocando SO o contrato: id, versao, descricao, variaveis
|
|
800
|
+
* declaradas versus usadas, segredo no corpo, limite de bytes e idioma continuam valendo,
|
|
801
|
+
* pelas mesmas regras e com o mesmo codigo. Uma copia deste lint ja tinha nascido mais
|
|
802
|
+
* frouxa que a original (sem o limite de bytes e sem o aviso de idioma), e foi o proprio
|
|
803
|
+
* pack `reuse` que apontou isso na rodada ork-reuse-2026-09-03-1.
|
|
804
|
+
*/
|
|
805
|
+
function lintTemplateDeAuditoria(t) {
|
|
806
|
+
return (0, prompts_1.lintTemplate)(t, exports.CONTRATO_DE_AUDITORIA);
|
|
807
|
+
}
|
|
808
|
+
/** Os valores que o template de auditoria recebe. Nada e calculado dentro do template. */
|
|
809
|
+
function valoresDoPromptDeAuditoria(entrada) {
|
|
810
|
+
const p = exports.PACKS[entrada.pack];
|
|
811
|
+
const listaDeArquivos = entrada.escopo.arquivos.length === 0
|
|
812
|
+
? ''
|
|
813
|
+
: '\n' +
|
|
814
|
+
entrada.escopo.arquivos.slice(0, 200).map((a) => ` - ${a}`).join('\n') +
|
|
815
|
+
(entrada.escopo.arquivos.length > 200
|
|
816
|
+
? `\n - (mais ${entrada.escopo.arquivos.length - 200} arquivo(s) no run.json da rodada)`
|
|
817
|
+
: '');
|
|
818
|
+
return {
|
|
819
|
+
pack: p.id,
|
|
820
|
+
titulo: p.titulo,
|
|
821
|
+
objetivo: p.objetivo,
|
|
822
|
+
produto: entrada.produto,
|
|
823
|
+
perfil: entrada.perfil,
|
|
824
|
+
estagio: entrada.estagio,
|
|
825
|
+
postura: entrada.postura,
|
|
826
|
+
descricao_da_postura: exports.DESCRICAO_DA_POSTURA[entrada.postura],
|
|
827
|
+
fonte: p.fonte === 'ledger' ? 'ledger, POSTMORTEMs e MASTER logs das threads' : 'arvore de codigo do produto',
|
|
828
|
+
rodada: entrada.rodada,
|
|
829
|
+
dir_da_rodada: entrada.dirDaRodada,
|
|
830
|
+
regras: p.regras.map((r) => `- ${r.id}: ${r.regra}\n evidencia exigida: ${r.evidencia}`).join('\n'),
|
|
831
|
+
evidencias: p.evidencias.map((e) => `- ${e}`).join('\n'),
|
|
832
|
+
referencias: p.referencias.map((r) => `- ${r}`).join('\n'),
|
|
833
|
+
escopo: `- ${entrada.escopo.detalhe}${listaDeArquivos}`,
|
|
834
|
+
linha_graphify: entrada.escopo.graphify === 'disponivel'
|
|
835
|
+
? '- Graphify disponivel nesta maquina: use o mapa do Graphify no lugar da leitura bruta do repositorio.'
|
|
836
|
+
: entrada.escopo.graphify === 'desligado'
|
|
837
|
+
? '- Graphify desligado no manifesto (audit.graphify: off): leitura dirigida por grep, sem varredura bruta.'
|
|
838
|
+
: '- Graphify ausente nesta maquina: leitura dirigida por grep no escopo acima, nunca varredura bruta do repositorio.',
|
|
839
|
+
linha_janela: `- janela de custo: ${entrada.janela.detalhe}`,
|
|
840
|
+
effort: entrada.effort,
|
|
841
|
+
comando_de_registro: ` ork audit ingest ${entrada.rodada} --arquivo ${entrada.dirDaRodada}/achados.json\n\nO formato de cada achado esta em ${entrada.dirDaRodada}/FORMATO.md.`,
|
|
842
|
+
regras_de_evidencia: exports.REGRAS_DE_EVIDENCIA_DO_AUDITOR.map((r) => `- ${r}`).join('\n'),
|
|
843
|
+
};
|
|
844
|
+
}
|
|
845
|
+
/** Monta o prompt exato da rodada, renderizando o template versionado do pack. */
|
|
846
|
+
function montarPromptDeAuditoria(entrada, raiz) {
|
|
847
|
+
return (0, prompts_1.renderizar)(templateDoPack(entrada.pack, raiz), valoresDoPromptDeAuditoria(entrada));
|
|
848
|
+
}
|