@semacode/cli 2.2.0 → 2.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/README.md +91 -4
- package/dist/agentContext.d.ts +1 -1
- package/dist/agentContextPack.js +6 -1
- package/dist/agentContextTipos.d.ts +4 -2
- package/dist/agentContextTipos.js +7 -0
- package/dist/agentEntryPoints.js +70 -19
- package/dist/comandos.js +4 -0
- package/dist/discovery/catalog.d.ts +11 -0
- package/dist/discovery/catalog.js +521 -0
- package/dist/discovery/command.d.ts +11 -0
- package/dist/discovery/command.js +226 -0
- package/dist/discovery/index.d.ts +5 -0
- package/dist/discovery/index.js +8 -0
- package/dist/discovery/ranker.d.ts +3 -0
- package/dist/discovery/ranker.js +310 -0
- package/dist/discovery/redaction.d.ts +2 -0
- package/dist/discovery/redaction.js +21 -0
- package/dist/discovery/render.d.ts +2 -0
- package/dist/discovery/render.js +100 -0
- package/dist/discovery/types.d.ts +119 -0
- package/dist/discovery/types.js +13 -0
- package/dist/exemplosOficiais.js +29 -8
- package/dist/iaPrompts.d.ts +1 -1
- package/dist/iaPrompts.js +3 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +23 -5
- package/dist/index.part01.d.ts +1 -1
- package/dist/index.part01.js +39 -4
- package/dist/index.part06.js +3 -0
- package/dist/initTemplatesBase.js +3 -2
- package/dist/profileArtefatoValidadores.d.ts +3 -2
- package/dist/profileArtefatoValidadores.js +81 -0
- package/dist/profileAuthorTipos.d.ts +4 -3
- package/dist/profileCatalogo.d.ts +5 -5
- package/dist/profileCatalogo.js +30 -0
- package/dist/profileCommand.d.ts +8 -2
- package/dist/profileCommand.js +15 -5
- package/dist/profileRegras.d.ts +5 -5
- package/dist/profileRegras.js +13 -1
- package/dist/profileRulePacks.js +68 -0
- package/dist/sistemasInterativos/adapterProtocol.d.ts +3 -0
- package/dist/sistemasInterativos/adapterProtocol.js +240 -0
- package/dist/sistemasInterativos/advancedCatalog.d.ts +5 -0
- package/dist/sistemasInterativos/advancedCatalog.js +442 -0
- package/dist/sistemasInterativos/autonomy.d.ts +230 -0
- package/dist/sistemasInterativos/autonomy.js +753 -0
- package/dist/sistemasInterativos/canonical.d.ts +3 -0
- package/dist/sistemasInterativos/canonical.js +43 -0
- package/dist/sistemasInterativos/catalog.d.ts +116 -0
- package/dist/sistemasInterativos/catalog.js +543 -0
- package/dist/sistemasInterativos/command.d.ts +7 -0
- package/dist/sistemasInterativos/command.js +311 -0
- package/dist/sistemasInterativos/controlRun.d.ts +56 -0
- package/dist/sistemasInterativos/controlRun.js +391 -0
- package/dist/sistemasInterativos/evidence.d.ts +5 -0
- package/dist/sistemasInterativos/evidence.js +306 -0
- package/dist/sistemasInterativos/experienceIr.d.ts +12 -0
- package/dist/sistemasInterativos/experienceIr.js +895 -0
- package/dist/sistemasInterativos/experienceIrSemantics.d.ts +30 -0
- package/dist/sistemasInterativos/experienceIrSemantics.js +368 -0
- package/dist/sistemasInterativos/experienceIrTypes.d.ts +370 -0
- package/dist/sistemasInterativos/experienceIrTypes.js +5 -0
- package/dist/sistemasInterativos/extensionCommand.d.ts +391 -0
- package/dist/sistemasInterativos/extensionCommand.js +383 -0
- package/dist/sistemasInterativos/index.d.ts +19 -0
- package/dist/sistemasInterativos/index.js +22 -0
- package/dist/sistemasInterativos/operations.d.ts +40 -0
- package/dist/sistemasInterativos/operations.js +1167 -0
- package/dist/sistemasInterativos/operationsTypes.d.ts +297 -0
- package/dist/sistemasInterativos/operationsTypes.js +11 -0
- package/dist/sistemasInterativos/planner.d.ts +2 -0
- package/dist/sistemasInterativos/planner.js +159 -0
- package/dist/sistemasInterativos/portability.d.ts +164 -0
- package/dist/sistemasInterativos/portability.js +539 -0
- package/dist/sistemasInterativos/render.d.ts +3 -0
- package/dist/sistemasInterativos/render.js +179 -0
- package/dist/sistemasInterativos/temporal.d.ts +183 -0
- package/dist/sistemasInterativos/temporal.js +543 -0
- package/dist/sistemasInterativos/types.d.ts +215 -0
- package/dist/sistemasInterativos/types.js +4 -0
- package/dist/sistemasInterativos/validator.d.ts +2 -0
- package/dist/sistemasInterativos/validator.js +305 -0
- package/docs/README.md +6 -0
- package/docs/ai-integration.md +7 -1
- package/docs/ai-workflow.md +5 -4
- package/docs/commands.md +43 -1
- package/docs/descoberta-capacidades.md +106 -0
- package/docs/documentation.md +11 -2
- package/docs/profiles.md +11 -2
- package/docs/sistemas-interativos.md +381 -0
- package/docs/testing.md +11 -2
- package/exemplos/profile_simulation.sema +211 -0
- package/exemplos/sistemas-interativos/README.md +100 -0
- package/exemplos/sistemas-interativos/advanced/acceptance-context-evaluate-valid.json +5 -0
- package/exemplos/sistemas-interativos/advanced/acceptance-lock-valid.json +16 -0
- package/exemplos/sistemas-interativos/advanced/asset-provenance-valid.json +32 -0
- package/exemplos/sistemas-interativos/advanced/autonomy-repair-valid.json +93 -0
- package/exemplos/sistemas-interativos/advanced/control-run-definition-valid.json +78 -0
- package/exemplos/sistemas-interativos/advanced/control-run-valid.json +27 -0
- package/exemplos/sistemas-interativos/advanced/distributed-workers-valid.json +79 -0
- package/exemplos/sistemas-interativos/advanced/editor-state-valid.json +42 -0
- package/exemplos/sistemas-interativos/advanced/engine-snapshot-after-valid.json +32 -0
- package/exemplos/sistemas-interativos/advanced/engine-snapshot-before-valid.json +23 -0
- package/exemplos/sistemas-interativos/advanced/job-orchestration-valid.json +39 -0
- package/exemplos/sistemas-interativos/advanced/multimodal-evidence-valid.json +46 -0
- package/exemplos/sistemas-interativos/advanced/multiplayer-authority-valid.json +39 -0
- package/exemplos/sistemas-interativos/advanced/playtest-fuzz-valid.json +37 -0
- package/exemplos/sistemas-interativos/advanced/portability-valid.json +104 -0
- package/exemplos/sistemas-interativos/advanced/temporal-evidence-valid.json +27 -0
- package/exemplos/sistemas-interativos/advanced/temporal-valid.json +118 -0
- package/exemplos/sistemas-interativos/experience-ir-valid.json +459 -0
- package/exemplos/sistemas-interativos/game-2d.json +83 -0
- package/exemplos/sistemas-interativos/game-3d-human.json +81 -0
- package/exemplos/sistemas-interativos/game-pixel-16-bit.json +97 -0
- package/exemplos/sistemas-interativos/game-pixel-8-bit.json +94 -0
- package/exemplos/sistemas-interativos/game-xr-human.json +80 -0
- package/exemplos/sistemas-interativos/hybrid-2-5d.json +108 -0
- package/exemplos/sistemas-interativos/protocol-mutating-rollback-valid.json +75 -0
- package/exemplos/sistemas-interativos/protocol-read-only-valid.json +58 -0
- package/exemplos/sistemas-interativos/simulation-2d-controlled.json +97 -0
- package/exemplos/sistemas-interativos/simulation-3d-calibrated-autonomous.json +141 -0
- package/exemplos/sistemas-interativos/simulation-headless-autonomous-batch.json +112 -0
- package/exemplos/sistemas-interativos/simulation-pixel-16-bit.json +103 -0
- package/exemplos/sistemas-interativos/simulation-text-controlled.json +95 -0
- package/node_modules/@sema/gerador-lua/dist/index.js +31 -2
- package/node_modules/@sema/gerador-lua/dist/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,539 @@
|
|
|
1
|
+
// SEMA-GOVERNED: sema.produto.sistemas_interativos.portabilidade
|
|
2
|
+
// Descricao: analise local de portabilidade com perdas declaradas e planejamento de workers distribuidos sem execucao.
|
|
3
|
+
import { digestJsonSistemaInterativo, digestSha256Valido } from "./canonical.js";
|
|
4
|
+
export const SCHEMA_PORTABILIDADE = "sema.interactive.portability/v1";
|
|
5
|
+
export const SCHEMA_WORKERS_DISTRIBUIDOS = "sema.interactive.distributed-jobs/v1";
|
|
6
|
+
const ID = /^[a-z0-9][a-z0-9._:/-]{0,127}$/;
|
|
7
|
+
const VERSAO = /^[0-9]+(?:\.[0-9]+){1,3}(?:[-+][a-z0-9.-]+)?$/i;
|
|
8
|
+
const CHAVE_SENSIVEL = /(?:password|passwd|senha|secret|token|api.?key|private.?key|credential|authorization|cookie)/i;
|
|
9
|
+
const VALORES_SENSIVEIS = [
|
|
10
|
+
/\bbearer\s+[a-z0-9._~+\/-]{8,}/i,
|
|
11
|
+
/^(?:sk[-_][a-z0-9_-]{8,}|ghp_[a-z0-9]{20,}|github_pat_[a-z0-9_]{20,})$/i,
|
|
12
|
+
/^eyJ[a-z0-9_-]{8,}\.eyJ[a-z0-9_-]{8,}\.[a-z0-9_-]{8,}$/i,
|
|
13
|
+
/\b(?:AKIA|ASIA)[A-Z0-9]{16}\b/,
|
|
14
|
+
/-----BEGIN [A-Z0-9 ]*(?:PRIVATE KEY|CERTIFICATE)-----/,
|
|
15
|
+
/(?:^|[?&])(?:access_?token|api_?key|aws_?secret_?access_?key|secret|password|passwd|signature|sig|token|credential|authorization)=[^&#\s]+/i,
|
|
16
|
+
/:\/\/[^/\s:@]+:[^/\s@]+@/,
|
|
17
|
+
];
|
|
18
|
+
const STATUS = new Set(["EXACT", "APPROXIMATE", "UNSUPPORTED"]);
|
|
19
|
+
const EVIDENCIAS_PORTABILIDADE = [
|
|
20
|
+
"import.scene", "import.assets", "import.materials", "import.animation", "import.physics",
|
|
21
|
+
"import.audio", "import.timeline", "package.build", "runtime.smoke",
|
|
22
|
+
];
|
|
23
|
+
const EVIDENCIAS_JOB = ["output.digest", "job.log", "job.checkpoint", "resources.metrics"];
|
|
24
|
+
function objeto(valor) {
|
|
25
|
+
return typeof valor === "object" && valor !== null && !Array.isArray(valor);
|
|
26
|
+
}
|
|
27
|
+
function texto(valor) {
|
|
28
|
+
return typeof valor === "string" && valor.trim().length > 0;
|
|
29
|
+
}
|
|
30
|
+
function id(valor) {
|
|
31
|
+
return typeof valor === "string" && ID.test(valor);
|
|
32
|
+
}
|
|
33
|
+
function positivo(valor) {
|
|
34
|
+
return typeof valor === "number" && Number.isFinite(valor) && valor > 0;
|
|
35
|
+
}
|
|
36
|
+
function inteiroNaoNegativo(valor) {
|
|
37
|
+
return typeof valor === "number" && Number.isInteger(valor) && valor >= 0;
|
|
38
|
+
}
|
|
39
|
+
function listaUnica(valor, validar, permitirVazia = false) {
|
|
40
|
+
return Array.isArray(valor)
|
|
41
|
+
&& (permitirVazia || valor.length > 0)
|
|
42
|
+
&& valor.every(validar)
|
|
43
|
+
&& new Set(valor).size === valor.length;
|
|
44
|
+
}
|
|
45
|
+
function idsUnicos(valores) {
|
|
46
|
+
return valores.every(id) && new Set(valores).size === valores.length;
|
|
47
|
+
}
|
|
48
|
+
function somenteChaves(valor, permitidas) {
|
|
49
|
+
const allowlist = new Set(permitidas);
|
|
50
|
+
return Object.keys(valor).every((chave) => allowlist.has(chave));
|
|
51
|
+
}
|
|
52
|
+
function valorSensivel(valor) {
|
|
53
|
+
if (digestSha256Valido(valor) || /^opaque:sha256:[a-f0-9]{64}$/.test(valor))
|
|
54
|
+
return false;
|
|
55
|
+
return VALORES_SENSIVEIS.some((padrao) => padrao.test(valor));
|
|
56
|
+
}
|
|
57
|
+
function contemSensivel(valor, visitados = new Set()) {
|
|
58
|
+
if (typeof valor === "string")
|
|
59
|
+
return valorSensivel(valor);
|
|
60
|
+
if (!objeto(valor) && !Array.isArray(valor))
|
|
61
|
+
return false;
|
|
62
|
+
if (visitados.has(valor))
|
|
63
|
+
return true;
|
|
64
|
+
visitados.add(valor);
|
|
65
|
+
try {
|
|
66
|
+
if (Array.isArray(valor))
|
|
67
|
+
return valor.some((item) => contemSensivel(item, visitados));
|
|
68
|
+
return Object.entries(valor).some(([chave, item]) => CHAVE_SENSIVEL.test(chave) || contemSensivel(item, visitados));
|
|
69
|
+
}
|
|
70
|
+
finally {
|
|
71
|
+
visitados.delete(valor);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
function exigir(bloqueios, condicao, codigo) {
|
|
75
|
+
if (!condicao)
|
|
76
|
+
bloqueios.push(codigo);
|
|
77
|
+
}
|
|
78
|
+
function digestSeguro(valor, bloqueios, codigo) {
|
|
79
|
+
try {
|
|
80
|
+
return digestJsonSistemaInterativo(valor);
|
|
81
|
+
}
|
|
82
|
+
catch {
|
|
83
|
+
bloqueios.push(codigo);
|
|
84
|
+
return "sha256:invalid";
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
function versao(valor) {
|
|
88
|
+
return typeof valor === "string" && VERSAO.test(valor);
|
|
89
|
+
}
|
|
90
|
+
export function digestManifestoFontePortabilidade(manifesto) {
|
|
91
|
+
return digestJsonSistemaInterativo({
|
|
92
|
+
experienceIrDigest: manifesto.experienceIrDigest,
|
|
93
|
+
snapshotDigest: manifesto.snapshotDigest,
|
|
94
|
+
entries: [...manifesto.entries]
|
|
95
|
+
.map((entry) => ({
|
|
96
|
+
semanticId: entry.semanticId,
|
|
97
|
+
sourceKind: entry.sourceKind,
|
|
98
|
+
contentDigest: entry.contentDigest,
|
|
99
|
+
required: entry.required,
|
|
100
|
+
}))
|
|
101
|
+
.sort((a, b) => a.semanticId.localeCompare(b.semanticId)),
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
export function analisarPlanoPortabilidadeInterativa(entrada) {
|
|
105
|
+
const bloqueios = [];
|
|
106
|
+
const reports = [];
|
|
107
|
+
const perdas = [];
|
|
108
|
+
const gaps = [];
|
|
109
|
+
if (!objeto(entrada)) {
|
|
110
|
+
return {
|
|
111
|
+
valido: false, planDigest: "sha256:invalid", targetReports: [], declaredLosses: [], migrationGaps: [],
|
|
112
|
+
nextActions: ["corrigir_plano_portabilidade"], converted: false, authoritative: false, executed: false, bloqueios: ["plano_invalido"],
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
const entradaSensivel = contemSensivel(entrada);
|
|
116
|
+
if (entradaSensivel)
|
|
117
|
+
bloqueios.push("plano_contem_dado_sensivel");
|
|
118
|
+
exigir(bloqueios, somenteChaves(entrada, [
|
|
119
|
+
"schemaVersion", "planId", "systemId", "experienceIrDigest", "source", "sourceManifest", "targets", "migrations", "acceptance",
|
|
120
|
+
]), "campos_top_level_desconhecidos");
|
|
121
|
+
exigir(bloqueios, entrada.schemaVersion === SCHEMA_PORTABILIDADE, "schema_version_nao_suportada");
|
|
122
|
+
exigir(bloqueios, id(entrada.planId), "plan_id_invalido");
|
|
123
|
+
exigir(bloqueios, id(entrada.systemId), "system_id_invalido");
|
|
124
|
+
exigir(bloqueios, digestSha256Valido(entrada.experienceIrDigest), "experience_ir_digest_invalido");
|
|
125
|
+
const source = entrada.source;
|
|
126
|
+
const sourceValida = objeto(source)
|
|
127
|
+
&& texto(source.engine)
|
|
128
|
+
&& versao(source.version)
|
|
129
|
+
&& digestSha256Valido(source.snapshotDigest)
|
|
130
|
+
&& texto(source.coordinateSystem);
|
|
131
|
+
exigir(bloqueios, sourceValida, "source_invalida");
|
|
132
|
+
const sourceManifest = entrada.sourceManifest;
|
|
133
|
+
const manifestEntries = objeto(sourceManifest) && Array.isArray(sourceManifest.entries) ? sourceManifest.entries : [];
|
|
134
|
+
const manifestEntryIdsValidos = idsUnicos(manifestEntries.map((item) => objeto(item) ? item.semanticId : undefined));
|
|
135
|
+
const manifestEntriesPorId = new Map();
|
|
136
|
+
let manifestEntriesValidas = manifestEntries.length > 0 && manifestEntryIdsValidos;
|
|
137
|
+
for (const entry of manifestEntries) {
|
|
138
|
+
const valida = objeto(entry)
|
|
139
|
+
&& id(entry.semanticId)
|
|
140
|
+
&& texto(entry.sourceKind)
|
|
141
|
+
&& digestSha256Valido(entry.contentDigest)
|
|
142
|
+
&& typeof entry.required === "boolean";
|
|
143
|
+
if (!valida)
|
|
144
|
+
manifestEntriesValidas = false;
|
|
145
|
+
else {
|
|
146
|
+
const tipada = entry;
|
|
147
|
+
manifestEntriesPorId.set(tipada.semanticId, tipada);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
const manifestShapeValido = objeto(sourceManifest)
|
|
151
|
+
&& digestSha256Valido(sourceManifest.experienceIrDigest)
|
|
152
|
+
&& digestSha256Valido(sourceManifest.snapshotDigest)
|
|
153
|
+
&& digestSha256Valido(sourceManifest.manifestDigest)
|
|
154
|
+
&& manifestEntriesValidas
|
|
155
|
+
&& [...manifestEntriesPorId.values()].some((entry) => entry.required);
|
|
156
|
+
exigir(bloqueios, manifestShapeValido, "source_manifest_invalido");
|
|
157
|
+
const manifestVinculado = manifestShapeValido
|
|
158
|
+
&& sourceManifest.experienceIrDigest === entrada.experienceIrDigest
|
|
159
|
+
&& sourceValida
|
|
160
|
+
&& sourceManifest.snapshotDigest === source.snapshotDigest;
|
|
161
|
+
exigir(bloqueios, manifestVinculado, "source_manifest_desvinculado");
|
|
162
|
+
let manifestDigestValido = false;
|
|
163
|
+
if (manifestShapeValido) {
|
|
164
|
+
const manifestoTipado = sourceManifest;
|
|
165
|
+
manifestDigestValido = manifestoTipado.manifestDigest === digestManifestoFontePortabilidade({
|
|
166
|
+
experienceIrDigest: manifestoTipado.experienceIrDigest,
|
|
167
|
+
snapshotDigest: manifestoTipado.snapshotDigest,
|
|
168
|
+
entries: manifestoTipado.entries,
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
exigir(bloqueios, manifestDigestValido, "source_manifest_digest_divergente");
|
|
172
|
+
const sourceManifestValido = manifestShapeValido && manifestVinculado && manifestDigestValido;
|
|
173
|
+
const semanticIdsObrigatorios = [...manifestEntriesPorId.values()]
|
|
174
|
+
.filter((entry) => entry.required)
|
|
175
|
+
.map((entry) => entry.semanticId);
|
|
176
|
+
const acceptance = entrada.acceptance;
|
|
177
|
+
const acceptanceValida = objeto(acceptance)
|
|
178
|
+
&& inteiroNaoNegativo(acceptance.maxUnsupportedPerTarget)
|
|
179
|
+
&& typeof acceptance.allowApproximate === "boolean"
|
|
180
|
+
&& listaUnica(acceptance.requiredEvidence, texto)
|
|
181
|
+
&& EVIDENCIAS_PORTABILIDADE.every((item) => acceptance.requiredEvidence.includes(item));
|
|
182
|
+
exigir(bloqueios, acceptanceValida, "acceptance_invalida_ou_evidencias_incompletas");
|
|
183
|
+
const targets = Array.isArray(entrada.targets) ? entrada.targets : [];
|
|
184
|
+
exigir(bloqueios, targets.length > 0, "targets_ausentes");
|
|
185
|
+
const targetIdsValidos = idsUnicos(targets.map((item) => objeto(item) ? item.targetId : undefined));
|
|
186
|
+
exigir(bloqueios, targetIdsValidos, "target_ids_invalidos_ou_duplicados");
|
|
187
|
+
const targetBasicoPorId = new Map();
|
|
188
|
+
for (const target of targets) {
|
|
189
|
+
if (objeto(target) && id(target.targetId) && texto(target.engine) && versao(target.version)) {
|
|
190
|
+
targetBasicoPorId.set(target.targetId, { engine: target.engine, version: target.version });
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
const migrations = Array.isArray(entrada.migrations) ? entrada.migrations : [];
|
|
194
|
+
exigir(bloqueios, migrations.length > 0, "migrations_ausentes");
|
|
195
|
+
const migrationIdsValidos = idsUnicos(migrations.map((item) => objeto(item) ? item.migrationId : undefined));
|
|
196
|
+
exigir(bloqueios, migrationIdsValidos, "migration_ids_invalidos_ou_duplicados");
|
|
197
|
+
let migrationsValidasGlobais = migrations.length > 0 && migrationIdsValidos;
|
|
198
|
+
const targetIdsComMigration = new Set();
|
|
199
|
+
for (const migration of migrations) {
|
|
200
|
+
const baseValida = objeto(migration)
|
|
201
|
+
&& id(migration.migrationId)
|
|
202
|
+
&& id(migration.targetId)
|
|
203
|
+
&& texto(migration.engine)
|
|
204
|
+
&& versao(migration.fromVersion)
|
|
205
|
+
&& versao(migration.toVersion)
|
|
206
|
+
&& migration.fromVersion !== migration.toVersion
|
|
207
|
+
&& digestSha256Valido(migration.backupDigest)
|
|
208
|
+
&& digestSha256Valido(migration.compatibilityReportDigest)
|
|
209
|
+
&& digestSha256Valido(migration.testPlanDigest)
|
|
210
|
+
&& digestSha256Valido(migration.rollbackPlanDigest);
|
|
211
|
+
exigir(bloqueios, baseValida, "migration_invalida_sem_backup_teste_ou_rollback");
|
|
212
|
+
if (!baseValida) {
|
|
213
|
+
migrationsValidasGlobais = false;
|
|
214
|
+
continue;
|
|
215
|
+
}
|
|
216
|
+
const tipada = migration;
|
|
217
|
+
const target = targetBasicoPorId.get(tipada.targetId);
|
|
218
|
+
const ligadaNaOrigem = sourceValida && tipada.engine === source.engine && tipada.toVersion === source.version;
|
|
219
|
+
const ligadaNoTarget = Boolean(target && tipada.engine === target.engine && tipada.toVersion === target.version);
|
|
220
|
+
if (!target || (!ligadaNaOrigem && !ligadaNoTarget)) {
|
|
221
|
+
bloqueios.push("migration_desconectada_do_target_ou_source");
|
|
222
|
+
migrationsValidasGlobais = false;
|
|
223
|
+
continue;
|
|
224
|
+
}
|
|
225
|
+
targetIdsComMigration.add(tipada.targetId);
|
|
226
|
+
}
|
|
227
|
+
for (const target of targets) {
|
|
228
|
+
if (!objeto(target)
|
|
229
|
+
|| !id(target.targetId)
|
|
230
|
+
|| !texto(target.engine)
|
|
231
|
+
|| !versao(target.version)
|
|
232
|
+
|| !texto(target.outputFormat)
|
|
233
|
+
|| !Array.isArray(target.mappings)
|
|
234
|
+
|| target.mappings.length === 0) {
|
|
235
|
+
bloqueios.push("target_invalido");
|
|
236
|
+
if (objeto(target) && id(target.targetId))
|
|
237
|
+
gaps.push(target.targetId);
|
|
238
|
+
continue;
|
|
239
|
+
}
|
|
240
|
+
const targetDiferenteDaSource = !(sourceValida && source.engine === target.engine && source.version === target.version);
|
|
241
|
+
if (!targetDiferenteDaSource)
|
|
242
|
+
bloqueios.push("target_igual_a_source_sem_migracao");
|
|
243
|
+
const mappingIdsValidos = idsUnicos(target.mappings.map((item) => objeto(item) ? item.mappingId : undefined));
|
|
244
|
+
const semanticIdsValidos = idsUnicos(target.mappings.map((item) => objeto(item) ? item.semanticId : undefined));
|
|
245
|
+
exigir(bloqueios, mappingIdsValidos, "mapping_ids_invalidos_ou_duplicados");
|
|
246
|
+
exigir(bloqueios, semanticIdsValidos, "semantic_ids_invalidos_ou_duplicados");
|
|
247
|
+
let exact = 0;
|
|
248
|
+
let approximate = 0;
|
|
249
|
+
let unsupported = 0;
|
|
250
|
+
let mappingsValidos = mappingIdsValidos && semanticIdsValidos;
|
|
251
|
+
let mappingsBoundToSource = sourceManifestValido;
|
|
252
|
+
const semanticIdsMapeados = new Set();
|
|
253
|
+
for (const mapping of target.mappings) {
|
|
254
|
+
const baseValida = objeto(mapping)
|
|
255
|
+
&& id(mapping.mappingId)
|
|
256
|
+
&& id(mapping.semanticId)
|
|
257
|
+
&& texto(mapping.sourceKind)
|
|
258
|
+
&& texto(mapping.targetKind)
|
|
259
|
+
&& STATUS.has(mapping.status)
|
|
260
|
+
&& Array.isArray(mapping.losses)
|
|
261
|
+
&& mapping.losses.every(texto)
|
|
262
|
+
&& new Set(mapping.losses).size === mapping.losses.length
|
|
263
|
+
&& listaUnica(mapping.acceptanceCriteria, texto);
|
|
264
|
+
exigir(bloqueios, baseValida, "mapping_invalido");
|
|
265
|
+
if (!baseValida) {
|
|
266
|
+
mappingsValidos = false;
|
|
267
|
+
continue;
|
|
268
|
+
}
|
|
269
|
+
const tipado = mapping;
|
|
270
|
+
const manifestEntry = manifestEntriesPorId.get(tipado.semanticId);
|
|
271
|
+
if (!sourceManifestValido || !manifestEntry || manifestEntry.sourceKind !== tipado.sourceKind) {
|
|
272
|
+
bloqueios.push("mapping_desconectado_do_source_manifest");
|
|
273
|
+
mappingsBoundToSource = false;
|
|
274
|
+
continue;
|
|
275
|
+
}
|
|
276
|
+
semanticIdsMapeados.add(tipado.semanticId);
|
|
277
|
+
if (tipado.status === "EXACT") {
|
|
278
|
+
exact += 1;
|
|
279
|
+
if (tipado.losses.length > 0) {
|
|
280
|
+
bloqueios.push("mapping_exact_nao_pode_declarar_loss");
|
|
281
|
+
mappingsValidos = false;
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
else {
|
|
285
|
+
if (tipado.status === "APPROXIMATE")
|
|
286
|
+
approximate += 1;
|
|
287
|
+
if (tipado.status === "UNSUPPORTED")
|
|
288
|
+
unsupported += 1;
|
|
289
|
+
const perdaValida = tipado.losses.length > 0 && texto(tipado.fallback);
|
|
290
|
+
exigir(bloqueios, perdaValida, "mapping_nao_exato_exige_loss_e_fallback");
|
|
291
|
+
if (!perdaValida)
|
|
292
|
+
mappingsValidos = false;
|
|
293
|
+
if (perdaValida)
|
|
294
|
+
perdas.push({
|
|
295
|
+
targetId: target.targetId,
|
|
296
|
+
mappingId: tipado.mappingId,
|
|
297
|
+
status: tipado.status,
|
|
298
|
+
lossCodes: [...tipado.losses].sort(),
|
|
299
|
+
fallback: tipado.fallback,
|
|
300
|
+
});
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
const sourceCoverageComplete = sourceManifestValido
|
|
304
|
+
&& semanticIdsObrigatorios.every((semanticId) => semanticIdsMapeados.has(semanticId));
|
|
305
|
+
exigir(bloqueios, sourceCoverageComplete, "mapping_cobertura_origem_incompleta");
|
|
306
|
+
const migrationLinked = targetIdsComMigration.has(target.targetId);
|
|
307
|
+
exigir(bloqueios, migrationLinked, "target_sem_migration_ligada");
|
|
308
|
+
const limite = acceptanceValida ? acceptance.maxUnsupportedPerTarget : 0;
|
|
309
|
+
const aceitaApproximate = acceptanceValida && acceptance.allowApproximate === true;
|
|
310
|
+
const ready = acceptanceValida
|
|
311
|
+
&& targetIdsValidos
|
|
312
|
+
&& targetDiferenteDaSource
|
|
313
|
+
&& migrationsValidasGlobais
|
|
314
|
+
&& mappingsValidos
|
|
315
|
+
&& mappingsBoundToSource
|
|
316
|
+
&& sourceCoverageComplete
|
|
317
|
+
&& migrationLinked
|
|
318
|
+
&& unsupported <= limite
|
|
319
|
+
&& (approximate === 0 || aceitaApproximate);
|
|
320
|
+
if (!ready)
|
|
321
|
+
gaps.push(target.targetId);
|
|
322
|
+
reports.push({
|
|
323
|
+
targetId: target.targetId,
|
|
324
|
+
exact,
|
|
325
|
+
approximate,
|
|
326
|
+
unsupported,
|
|
327
|
+
sourceCoverageComplete,
|
|
328
|
+
mappingsBoundToSource,
|
|
329
|
+
migrationLinked,
|
|
330
|
+
readyForExternalMigration: ready,
|
|
331
|
+
requiresExternalValidation: true,
|
|
332
|
+
converted: false,
|
|
333
|
+
});
|
|
334
|
+
}
|
|
335
|
+
const planDigest = digestSeguro(entrada, bloqueios, "plano_nao_canonicalizavel");
|
|
336
|
+
const gapsUnicos = entradaSensivel ? [] : [...new Set(gaps)].sort();
|
|
337
|
+
const bloqueiosUnicos = [...new Set(bloqueios)].sort();
|
|
338
|
+
const valido = bloqueiosUnicos.length === 0 && gapsUnicos.length === 0;
|
|
339
|
+
const reportsFinais = entradaSensivel ? [] : reports.sort((a, b) => a.targetId.localeCompare(b.targetId))
|
|
340
|
+
.map((report) => valido ? report : { ...report, readyForExternalMigration: false });
|
|
341
|
+
return {
|
|
342
|
+
valido,
|
|
343
|
+
planDigest,
|
|
344
|
+
targetReports: reportsFinais,
|
|
345
|
+
declaredLosses: entradaSensivel ? [] : perdas.sort((a, b) => `${a.targetId}:${a.mappingId}`.localeCompare(`${b.targetId}:${b.mappingId}`)),
|
|
346
|
+
migrationGaps: gapsUnicos,
|
|
347
|
+
nextActions: bloqueiosUnicos.length > 0
|
|
348
|
+
? ["corrigir_plano_portabilidade"]
|
|
349
|
+
: gapsUnicos.length > 0
|
|
350
|
+
? gapsUnicos.map((targetId) => `revisar_perdas_e_acceptance:${targetId}`)
|
|
351
|
+
: reportsFinais.map((item) => `entregar_plano_ao_adapter_externo:${item.targetId}`),
|
|
352
|
+
converted: false,
|
|
353
|
+
authoritative: false,
|
|
354
|
+
executed: false,
|
|
355
|
+
bloqueios: bloqueiosUnicos,
|
|
356
|
+
};
|
|
357
|
+
}
|
|
358
|
+
function ordemTopologica(jobs) {
|
|
359
|
+
const ids = new Set(jobs.map((job) => job.jobId));
|
|
360
|
+
const referenciasInvalidas = jobs.some((job) => job.dependsOn.some((dep) => !ids.has(dep) || dep === job.jobId));
|
|
361
|
+
const graus = new Map(jobs.map((job) => [job.jobId, job.dependsOn.length]));
|
|
362
|
+
const filhos = new Map();
|
|
363
|
+
for (const job of jobs)
|
|
364
|
+
for (const dep of job.dependsOn)
|
|
365
|
+
filhos.set(dep, [...(filhos.get(dep) ?? []), job.jobId]);
|
|
366
|
+
const fila = [...graus.entries()].filter(([, grau]) => grau === 0).map(([jobId]) => jobId).sort();
|
|
367
|
+
const ordem = [];
|
|
368
|
+
while (fila.length > 0) {
|
|
369
|
+
const atual = fila.shift();
|
|
370
|
+
ordem.push(atual);
|
|
371
|
+
for (const filho of (filhos.get(atual) ?? []).sort()) {
|
|
372
|
+
const grau = (graus.get(filho) ?? 0) - 1;
|
|
373
|
+
graus.set(filho, grau);
|
|
374
|
+
if (grau === 0) {
|
|
375
|
+
fila.push(filho);
|
|
376
|
+
fila.sort();
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
return { ordem, ciclo: ordem.length !== jobs.length, referenciasInvalidas };
|
|
381
|
+
}
|
|
382
|
+
function dependeDe(jobId, ancestorId, porId, visitados = new Set()) {
|
|
383
|
+
if (visitados.has(jobId))
|
|
384
|
+
return false;
|
|
385
|
+
visitados.add(jobId);
|
|
386
|
+
const job = porId.get(jobId);
|
|
387
|
+
if (!job)
|
|
388
|
+
return false;
|
|
389
|
+
if (job.dependsOn.includes(ancestorId))
|
|
390
|
+
return true;
|
|
391
|
+
return job.dependsOn.some((dep) => dependeDe(dep, ancestorId, porId, visitados));
|
|
392
|
+
}
|
|
393
|
+
export function validarPlanoWorkersDistribuidos(entrada) {
|
|
394
|
+
const bloqueios = [];
|
|
395
|
+
const gaps = [];
|
|
396
|
+
const conflicts = [];
|
|
397
|
+
const assignments = [];
|
|
398
|
+
if (!objeto(entrada)) {
|
|
399
|
+
return {
|
|
400
|
+
valido: false, planDigest: "sha256:invalid", topologicalOrder: [], assignments: [], capabilityGaps: [], lockConflicts: [],
|
|
401
|
+
nextActions: ["corrigir_plano_workers"], completed: false, authoritative: false, executed: false, bloqueios: ["plano_invalido"],
|
|
402
|
+
};
|
|
403
|
+
}
|
|
404
|
+
const entradaSensivel = contemSensivel(entrada);
|
|
405
|
+
if (entradaSensivel)
|
|
406
|
+
bloqueios.push("plano_contem_dado_sensivel");
|
|
407
|
+
exigir(bloqueios, somenteChaves(entrada, [
|
|
408
|
+
"schemaVersion", "planId", "systemId", "inputDigest", "workers", "jobs", "leases", "evidenceRequirements",
|
|
409
|
+
]), "campos_top_level_desconhecidos");
|
|
410
|
+
exigir(bloqueios, entrada.schemaVersion === SCHEMA_WORKERS_DISTRIBUIDOS, "schema_version_nao_suportada");
|
|
411
|
+
exigir(bloqueios, id(entrada.planId), "plan_id_invalido");
|
|
412
|
+
exigir(bloqueios, id(entrada.systemId), "system_id_invalido");
|
|
413
|
+
exigir(bloqueios, digestSha256Valido(entrada.inputDigest), "input_digest_invalido");
|
|
414
|
+
const workersBrutos = Array.isArray(entrada.workers) ? entrada.workers : [];
|
|
415
|
+
exigir(bloqueios, idsUnicos(workersBrutos.map((item) => objeto(item) ? item.workerId : undefined)), "worker_ids_invalidos_ou_duplicados");
|
|
416
|
+
const workers = [];
|
|
417
|
+
for (const worker of workersBrutos) {
|
|
418
|
+
const valido = objeto(worker)
|
|
419
|
+
&& id(worker.workerId)
|
|
420
|
+
&& listaUnica(worker.capabilities, id)
|
|
421
|
+
&& positivo(worker.ramMb)
|
|
422
|
+
&& inteiroNaoNegativo(worker.vramMb)
|
|
423
|
+
&& positivo(worker.diskMb)
|
|
424
|
+
&& positivo(worker.maxConcurrency)
|
|
425
|
+
&& ["CONTAINER", "VM", "PROCESS_SANDBOX"].includes(String(worker.isolation));
|
|
426
|
+
exigir(bloqueios, valido, "worker_invalido");
|
|
427
|
+
if (valido)
|
|
428
|
+
workers.push(worker);
|
|
429
|
+
}
|
|
430
|
+
const jobsBrutos = Array.isArray(entrada.jobs) ? entrada.jobs : [];
|
|
431
|
+
exigir(bloqueios, jobsBrutos.length > 0, "jobs_ausentes");
|
|
432
|
+
exigir(bloqueios, idsUnicos(jobsBrutos.map((item) => objeto(item) ? item.jobId : undefined)), "job_ids_invalidos_ou_duplicados");
|
|
433
|
+
const jobs = [];
|
|
434
|
+
for (const job of jobsBrutos) {
|
|
435
|
+
const budgets = objeto(job) ? job.budgets : undefined;
|
|
436
|
+
const retry = objeto(job) ? job.retry : undefined;
|
|
437
|
+
const valido = objeto(job)
|
|
438
|
+
&& id(job.jobId)
|
|
439
|
+
&& ["COOK", "SHADERS", "RENDER", "TEST"].includes(String(job.type))
|
|
440
|
+
&& digestSha256Valido(job.inputDigest)
|
|
441
|
+
&& listaUnica(job.dependsOn, id, true)
|
|
442
|
+
&& listaUnica(job.requiredCapabilities, id)
|
|
443
|
+
&& objeto(budgets)
|
|
444
|
+
&& positivo(budgets.ramMb)
|
|
445
|
+
&& inteiroNaoNegativo(budgets.vramMb)
|
|
446
|
+
&& positivo(budgets.diskMb)
|
|
447
|
+
&& positivo(budgets.runtimeSeconds)
|
|
448
|
+
&& id(job.idempotencyKey)
|
|
449
|
+
&& positivo(job.checkpointIntervalSeconds)
|
|
450
|
+
&& objeto(retry)
|
|
451
|
+
&& inteiroNaoNegativo(retry.maxAttempts)
|
|
452
|
+
&& positivo(retry.backoffSeconds)
|
|
453
|
+
&& listaUnica(job.resourceLockIds, id, true)
|
|
454
|
+
&& listaUnica(job.requiredEvidence, texto)
|
|
455
|
+
&& EVIDENCIAS_JOB.every((item) => job.requiredEvidence.includes(item));
|
|
456
|
+
exigir(bloqueios, valido, "job_invalido_sem_budget_checkpoint_idempotency_ou_evidencia");
|
|
457
|
+
if (valido)
|
|
458
|
+
jobs.push(job);
|
|
459
|
+
}
|
|
460
|
+
exigir(bloqueios, new Set(jobs.map((job) => job.idempotencyKey)).size === jobs.length, "job_idempotency_key_duplicada");
|
|
461
|
+
const dag = ordemTopologica(jobs);
|
|
462
|
+
exigir(bloqueios, !dag.referenciasInvalidas, "job_dependency_invalida");
|
|
463
|
+
exigir(bloqueios, !dag.ciclo, "job_dependency_cycle");
|
|
464
|
+
const porId = new Map(jobs.map((job) => [job.jobId, job]));
|
|
465
|
+
for (const job of jobs) {
|
|
466
|
+
const candidatos = workers.filter((worker) => (job.requiredCapabilities.every((capability) => worker.capabilities.includes(capability))
|
|
467
|
+
&& worker.ramMb >= job.budgets.ramMb
|
|
468
|
+
&& worker.vramMb >= job.budgets.vramMb
|
|
469
|
+
&& worker.diskMb >= job.budgets.diskMb)).sort((a, b) => a.workerId.localeCompare(b.workerId));
|
|
470
|
+
if (candidatos.length === 0)
|
|
471
|
+
gaps.push(job.jobId);
|
|
472
|
+
else
|
|
473
|
+
assignments.push({ jobId: job.jobId, workerId: candidatos[0].workerId });
|
|
474
|
+
}
|
|
475
|
+
const leasesBrutos = Array.isArray(entrada.leases) ? entrada.leases : [];
|
|
476
|
+
exigir(bloqueios, idsUnicos(leasesBrutos.map((item) => objeto(item) ? item.lockId : undefined)), "lease_ids_invalidos_ou_duplicados");
|
|
477
|
+
const leases = [];
|
|
478
|
+
for (const lease of leasesBrutos) {
|
|
479
|
+
const valido = objeto(lease)
|
|
480
|
+
&& id(lease.lockId)
|
|
481
|
+
&& id(lease.resourceId)
|
|
482
|
+
&& ["GPU", "EDITOR", "CACHE"].includes(String(lease.resourceType))
|
|
483
|
+
&& id(lease.ownerJobId)
|
|
484
|
+
&& porId.has(lease.ownerJobId)
|
|
485
|
+
&& typeof lease.exclusive === "boolean"
|
|
486
|
+
&& positivo(lease.ttlSeconds)
|
|
487
|
+
&& positivo(lease.heartbeatSeconds)
|
|
488
|
+
&& lease.heartbeatSeconds < lease.ttlSeconds
|
|
489
|
+
&& digestSha256Valido(lease.checkpointDigest);
|
|
490
|
+
exigir(bloqueios, valido, "lease_invalido_sem_ttl_heartbeat_ou_checkpoint");
|
|
491
|
+
if (valido)
|
|
492
|
+
leases.push(lease);
|
|
493
|
+
}
|
|
494
|
+
const leasesPorId = new Map(leases.map((lease) => [lease.lockId, lease]));
|
|
495
|
+
for (const job of jobs) {
|
|
496
|
+
const leasesDoJob = job.resourceLockIds.map((lockId) => leasesPorId.get(lockId));
|
|
497
|
+
exigir(bloqueios, leasesDoJob.every((lease) => lease?.ownerJobId === job.jobId
|
|
498
|
+
&& lease.checkpointDigest === job.inputDigest), "job_lock_ausente_owner_ou_checkpoint_divergente");
|
|
499
|
+
const exigeGpu = job.type === "RENDER" || job.type === "SHADERS" || job.budgets.vramMb > 0;
|
|
500
|
+
exigir(bloqueios, !exigeGpu || leasesDoJob.some((lease) => lease?.resourceType === "GPU"), "job_gpu_lease_ausente");
|
|
501
|
+
}
|
|
502
|
+
for (let i = 0; i < leases.length; i += 1)
|
|
503
|
+
for (let j = i + 1; j < leases.length; j += 1) {
|
|
504
|
+
const a = leases[i];
|
|
505
|
+
const b = leases[j];
|
|
506
|
+
if (a.resourceId !== b.resourceId || (!a.exclusive && !b.exclusive) || a.ownerJobId === b.ownerJobId)
|
|
507
|
+
continue;
|
|
508
|
+
const ordenados = dependeDe(a.ownerJobId, b.ownerJobId, porId) || dependeDe(b.ownerJobId, a.ownerJobId, porId);
|
|
509
|
+
if (!ordenados)
|
|
510
|
+
conflicts.push(`${a.ownerJobId}|${b.ownerJobId}|${a.resourceId}`);
|
|
511
|
+
}
|
|
512
|
+
exigir(bloqueios, listaUnica(entrada.evidenceRequirements, texto)
|
|
513
|
+
&& EVIDENCIAS_JOB.every((item) => entrada.evidenceRequirements.includes(item)), "evidence_requirements_incompletos");
|
|
514
|
+
const planDigest = digestSeguro(entrada, bloqueios, "plano_nao_canonicalizavel");
|
|
515
|
+
const gapsUnicos = entradaSensivel ? [] : [...new Set(gaps)].sort();
|
|
516
|
+
const conflitosUnicos = entradaSensivel ? [] : [...new Set(conflicts)].sort();
|
|
517
|
+
const bloqueiosUnicos = [...new Set(bloqueios)].sort();
|
|
518
|
+
const valido = bloqueiosUnicos.length === 0 && gapsUnicos.length === 0 && conflitosUnicos.length === 0;
|
|
519
|
+
return {
|
|
520
|
+
valido,
|
|
521
|
+
planDigest,
|
|
522
|
+
topologicalOrder: valido ? dag.ordem : [],
|
|
523
|
+
assignments: valido ? assignments.sort((a, b) => a.jobId.localeCompare(b.jobId)) : [],
|
|
524
|
+
capabilityGaps: gapsUnicos,
|
|
525
|
+
lockConflicts: conflitosUnicos,
|
|
526
|
+
nextActions: bloqueiosUnicos.length > 0
|
|
527
|
+
? ["corrigir_plano_workers"]
|
|
528
|
+
: gapsUnicos.length > 0
|
|
529
|
+
? gapsUnicos.map((jobId) => `provisionar_worker_compativel:${jobId}`)
|
|
530
|
+
: conflitosUnicos.length > 0
|
|
531
|
+
? conflitosUnicos.map((conflictId) => `serializar_jobs_com_lock_conflitante:${conflictId}`)
|
|
532
|
+
: ["entregar_DAG_ao_orquestrador_externo"],
|
|
533
|
+
completed: false,
|
|
534
|
+
authoritative: false,
|
|
535
|
+
executed: false,
|
|
536
|
+
bloqueios: bloqueiosUnicos,
|
|
537
|
+
};
|
|
538
|
+
}
|
|
539
|
+
//# sourceMappingURL=portability.js.map
|