@semacode/cli 2.3.1 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (250) hide show
  1. package/README.md +265 -217
  2. package/dist/agentContextPack.js +14 -10
  3. package/dist/agentEntryPoints.d.ts +5 -0
  4. package/dist/agentEntryPoints.js +567 -557
  5. package/dist/angular-consumer-standalone.js +1 -1
  6. package/dist/bin.d.ts +6 -0
  7. package/dist/bin.js +130 -0
  8. package/dist/cliArgs.js +4 -4
  9. package/dist/cliControlError.d.ts +12 -0
  10. package/dist/cliControlError.js +47 -0
  11. package/dist/cliGrammar.d.ts +11 -0
  12. package/dist/cliGrammar.js +551 -0
  13. package/dist/cliHelp.d.ts +13 -0
  14. package/dist/cliHelp.js +19 -0
  15. package/dist/cliHelpTexto.d.ts +3 -0
  16. package/dist/cliHelpTexto.js +168 -0
  17. package/dist/cliRuntime.d.ts +2 -0
  18. package/dist/cliRuntime.js +31 -0
  19. package/dist/comandos.js +9 -22
  20. package/dist/contexto.js +5 -5
  21. package/dist/dev/index.d.ts +1 -0
  22. package/dist/dev/index.js +51 -9
  23. package/dist/discovery/catalog.js +3 -3
  24. package/dist/distribuicao/filesystemGlobal.d.ts +63 -0
  25. package/dist/distribuicao/filesystemGlobal.js +701 -0
  26. package/dist/distribuicao/index.d.ts +7 -0
  27. package/dist/distribuicao/index.js +227 -0
  28. package/dist/distribuicao/launcherGlobal.d.ts +53 -0
  29. package/dist/distribuicao/launcherGlobal.js +643 -0
  30. package/dist/distribuicao/launcherWindows.d.ts +28 -0
  31. package/dist/distribuicao/launcherWindows.js +326 -0
  32. package/dist/distribuicao/lockContextGlobal.d.ts +10 -0
  33. package/dist/distribuicao/lockContextGlobal.js +17 -0
  34. package/dist/distribuicao/lockGlobal.d.ts +6 -0
  35. package/dist/distribuicao/lockGlobal.js +520 -0
  36. package/dist/distribuicao/skillGlobal.d.ts +48 -0
  37. package/dist/distribuicao/skillGlobal.js +652 -0
  38. package/dist/distribuicao/skillIntentPolicy.d.ts +21 -0
  39. package/dist/distribuicao/skillIntentPolicy.js +115 -0
  40. package/dist/distribuicao/tipos.d.ts +50 -0
  41. package/dist/distribuicao/tipos.js +10 -0
  42. package/dist/distribuicao/versaoSemantica.d.ts +3 -0
  43. package/dist/distribuicao/versaoSemantica.js +62 -0
  44. package/dist/drift.part01.d.ts +26 -24
  45. package/dist/drift.part01.js +2 -1
  46. package/dist/drift.part04.d.ts +12 -3
  47. package/dist/drift.part04.js +88 -17
  48. package/dist/drift.part05.d.ts +2 -2
  49. package/dist/drift.part05.js +8 -6
  50. package/dist/drift.part06.d.ts +2 -2
  51. package/dist/drift.part06.js +113 -26
  52. package/dist/drift.part07.d.ts +11 -11
  53. package/dist/drift.part07.js +261 -265
  54. package/dist/drift.part08.d.ts +2 -2
  55. package/dist/drift.part08.js +35 -26
  56. package/dist/drift.part11.js +238 -56
  57. package/dist/drift.part12.d.ts +1 -1
  58. package/dist/drift.part12.js +193 -21
  59. package/dist/drift.part13.d.ts +20 -39
  60. package/dist/drift.part13.js +601 -647
  61. package/dist/drift.part14.js +21 -7
  62. package/dist/driftCacheCas.d.ts +43 -0
  63. package/dist/driftCacheCas.js +351 -0
  64. package/dist/driftCacheFilesystem.d.ts +64 -0
  65. package/dist/driftCacheFilesystem.js +313 -0
  66. package/dist/driftCacheModes.d.ts +38 -0
  67. package/dist/driftCacheModes.js +147 -0
  68. package/dist/driftCacheStore.d.ts +80 -0
  69. package/dist/driftCacheStore.js +603 -0
  70. package/dist/driftCatalogo.d.ts +2 -28
  71. package/dist/driftCatalogo.js +143 -284
  72. package/dist/driftEscopo.d.ts +1 -3
  73. package/dist/driftEscopo.js +235 -151
  74. package/dist/driftEscopoReferencias.d.ts +5 -1
  75. package/dist/driftEscopoReferencias.js +375 -28
  76. package/dist/driftOrcamento.d.ts +0 -6
  77. package/dist/driftOrcamento.js +2 -1
  78. package/dist/execucoesExternas.js +19 -5
  79. package/dist/geracaoCore.js +4 -6
  80. package/dist/iaPrompts.d.ts +3 -3
  81. package/dist/iaPrompts.js +312 -313
  82. package/dist/index.d.ts +4 -1
  83. package/dist/index.js +6 -25
  84. package/dist/index.part01.d.ts +20 -28
  85. package/dist/index.part01.js +16 -237
  86. package/dist/index.part02.js +36 -22
  87. package/dist/index.part03.d.ts +24 -2
  88. package/dist/index.part03.js +83 -19
  89. package/dist/index.part04.d.ts +10 -2
  90. package/dist/index.part04.js +142 -120
  91. package/dist/index.part05.js +80 -78
  92. package/dist/index.part06.js +34 -17
  93. package/dist/index.part07.js +7 -3
  94. package/dist/index.part08.d.ts +1 -1
  95. package/dist/index.part08.js +22 -27
  96. package/dist/initCommand.js +5 -1
  97. package/dist/initTemplatesBase.js +81 -79
  98. package/dist/pipelineConteudo/command.d.ts +1 -0
  99. package/dist/pipelineConteudo/command.js +9 -2
  100. package/dist/pipelineConteudo/help.d.ts +2 -0
  101. package/dist/pipelineConteudo/help.js +33 -0
  102. package/dist/profileAuthorCommand.js +3 -7
  103. package/dist/profileCommand.js +3 -7
  104. package/dist/projetoCarregar.js +35 -17
  105. package/dist/projetoCatalogo.d.ts +1 -0
  106. package/dist/projetoCatalogo.js +64 -25
  107. package/dist/projetoOrigens.d.ts +2 -0
  108. package/dist/projetoOrigens.js +65 -9
  109. package/dist/projetoTipos.d.ts +1 -0
  110. package/dist/resultadoCli.d.ts +20 -0
  111. package/dist/resultadoCli.js +57 -0
  112. package/dist/saidaCli.d.ts +35 -0
  113. package/dist/saidaCli.js +118 -0
  114. package/dist/sistemasInterativos/acceptanceEvidence.d.ts +22 -0
  115. package/dist/sistemasInterativos/acceptanceEvidence.js +345 -0
  116. package/dist/sistemasInterativos/engineObservation.d.ts +12 -0
  117. package/dist/sistemasInterativos/engineObservation.js +438 -0
  118. package/dist/sistemasInterativos/jobOrchestration.d.ts +2 -0
  119. package/dist/sistemasInterativos/jobOrchestration.js +204 -0
  120. package/dist/sistemasInterativos/operationPrimitives.d.ts +21 -0
  121. package/dist/sistemasInterativos/operationPrimitives.js +194 -0
  122. package/dist/sistemasInterativos/operations.d.ts +4 -39
  123. package/dist/sistemasInterativos/operations.js +5 -1164
  124. package/dist/skillCommand.d.ts +5 -0
  125. package/dist/skillCommand.js +88 -0
  126. package/docs/README.md +34 -30
  127. package/docs/ai-integration.md +25 -12
  128. package/docs/ai-onboarding.md +37 -18
  129. package/docs/ai-workflow.md +9 -7
  130. package/docs/cli.md +125 -7
  131. package/docs/commands.md +41 -20
  132. package/docs/deploy.md +21 -8
  133. package/docs/descoberta-capacidades.md +106 -106
  134. package/docs/documentation.md +49 -39
  135. package/docs/drift-cache.md +108 -0
  136. package/docs/getting-started.md +43 -18
  137. package/docs/pipeline-conteudo.md +246 -246
  138. package/docs/profiles.md +54 -54
  139. package/docs/repositories.md +19 -2
  140. package/docs/rollback.md +15 -8
  141. package/docs/security.md +25 -3
  142. package/docs/sistemas-interativos.md +379 -374
  143. package/docs/testing.md +139 -40
  144. package/exemplos/pipeline-conteudo/README.md +44 -44
  145. package/exemplos/pipeline-conteudo/alvos.json +23 -23
  146. package/exemplos/pipeline-conteudo/definicao.json +136 -136
  147. package/exemplos/profile_simulation.sema +211 -211
  148. package/exemplos/sistemas-interativos/README.md +100 -100
  149. package/exemplos/sistemas-interativos/advanced/acceptance-context-evaluate-valid.json +5 -5
  150. package/exemplos/sistemas-interativos/advanced/acceptance-lock-valid.json +16 -16
  151. package/exemplos/sistemas-interativos/advanced/asset-provenance-valid.json +32 -32
  152. package/exemplos/sistemas-interativos/advanced/autonomy-repair-valid.json +93 -93
  153. package/exemplos/sistemas-interativos/advanced/control-run-definition-valid.json +78 -78
  154. package/exemplos/sistemas-interativos/advanced/control-run-valid.json +27 -27
  155. package/exemplos/sistemas-interativos/advanced/distributed-workers-valid.json +79 -79
  156. package/exemplos/sistemas-interativos/advanced/editor-state-valid.json +42 -42
  157. package/exemplos/sistemas-interativos/advanced/engine-snapshot-after-valid.json +32 -32
  158. package/exemplos/sistemas-interativos/advanced/engine-snapshot-before-valid.json +23 -23
  159. package/exemplos/sistemas-interativos/advanced/job-orchestration-valid.json +39 -39
  160. package/exemplos/sistemas-interativos/advanced/multimodal-evidence-valid.json +46 -46
  161. package/exemplos/sistemas-interativos/advanced/multiplayer-authority-valid.json +39 -39
  162. package/exemplos/sistemas-interativos/advanced/playtest-fuzz-valid.json +37 -37
  163. package/exemplos/sistemas-interativos/advanced/portability-valid.json +104 -104
  164. package/exemplos/sistemas-interativos/advanced/temporal-evidence-valid.json +27 -27
  165. package/exemplos/sistemas-interativos/advanced/temporal-valid.json +118 -118
  166. package/exemplos/sistemas-interativos/experience-ir-valid.json +459 -459
  167. package/exemplos/sistemas-interativos/game-2d.json +83 -83
  168. package/exemplos/sistemas-interativos/game-3d-human.json +81 -81
  169. package/exemplos/sistemas-interativos/game-pixel-16-bit.json +97 -97
  170. package/exemplos/sistemas-interativos/game-pixel-8-bit.json +94 -94
  171. package/exemplos/sistemas-interativos/game-xr-human.json +80 -80
  172. package/exemplos/sistemas-interativos/hybrid-2-5d.json +108 -108
  173. package/exemplos/sistemas-interativos/protocol-mutating-rollback-valid.json +75 -75
  174. package/exemplos/sistemas-interativos/protocol-read-only-valid.json +58 -58
  175. package/exemplos/sistemas-interativos/simulation-2d-controlled.json +97 -97
  176. package/exemplos/sistemas-interativos/simulation-3d-calibrated-autonomous.json +141 -141
  177. package/exemplos/sistemas-interativos/simulation-headless-autonomous-batch.json +112 -112
  178. package/exemplos/sistemas-interativos/simulation-pixel-16-bit.json +103 -103
  179. package/exemplos/sistemas-interativos/simulation-text-controlled.json +95 -95
  180. package/node_modules/@sema/gerador-cpp/package.json +1 -1
  181. package/node_modules/@sema/gerador-dotnet/package.json +1 -1
  182. package/node_modules/@sema/gerador-lua/dist/index.js +51 -51
  183. package/node_modules/@sema/gerador-php/dist/index.js +113 -113
  184. package/node_modules/@sema/nucleo/dist/semantico/analisador.d.ts +1 -0
  185. package/node_modules/@sema/nucleo/dist/semantico/analisador.js +1 -0
  186. package/package.json +9 -4
  187. package/scripts/postinstall.mjs +148 -0
  188. package/skills/sema/SKILL.md +199 -0
  189. package/skills/sema/agents/openai.yaml +4 -0
  190. package/dist/driftCache.d.ts +0 -49
  191. package/dist/driftCache.js +0 -311
  192. package/dist/driftCacheIncremental.d.ts +0 -98
  193. package/dist/driftCacheIncremental.js +0 -596
  194. package/dist/driftCatalogoPersistente.d.ts +0 -8
  195. package/dist/driftCatalogoPersistente.js +0 -77
  196. package/node_modules/@sema/gerador-cpp/dist/index.js.map +0 -1
  197. package/node_modules/@sema/gerador-css/dist/index.js.map +0 -1
  198. package/node_modules/@sema/gerador-css/dist/index.part01.js.map +0 -1
  199. package/node_modules/@sema/gerador-css/dist/index.part02.js.map +0 -1
  200. package/node_modules/@sema/gerador-dart/dist/index.js.map +0 -1
  201. package/node_modules/@sema/gerador-dotnet/dist/index.js.map +0 -1
  202. package/node_modules/@sema/gerador-html/dist/index.js.map +0 -1
  203. package/node_modules/@sema/gerador-javascript/dist/index.js.map +0 -1
  204. package/node_modules/@sema/gerador-lua/dist/index.js.map +0 -1
  205. package/node_modules/@sema/gerador-php/dist/index.js.map +0 -1
  206. package/node_modules/@sema/gerador-python/dist/index.js.map +0 -1
  207. package/node_modules/@sema/gerador-python/dist/index.part01.js.map +0 -1
  208. package/node_modules/@sema/gerador-python/dist/index.part02.js.map +0 -1
  209. package/node_modules/@sema/gerador-typescript/dist/index.js.map +0 -1
  210. package/node_modules/@sema/gerador-typescript/dist/index.part01.js.map +0 -1
  211. package/node_modules/@sema/gerador-typescript/dist/index.part02.js.map +0 -1
  212. package/node_modules/@sema/gerador-typescript/dist/index.part03.js.map +0 -1
  213. package/node_modules/@sema/nucleo/dist/ast/tipos.js.map +0 -1
  214. package/node_modules/@sema/nucleo/dist/diagnosticos/index.js.map +0 -1
  215. package/node_modules/@sema/nucleo/dist/diagnosticos/melhorador.js.map +0 -1
  216. package/node_modules/@sema/nucleo/dist/diagnosticos/snippets.js.map +0 -1
  217. package/node_modules/@sema/nucleo/dist/formatador/index.js.map +0 -1
  218. package/node_modules/@sema/nucleo/dist/formatador/index.part01.js.map +0 -1
  219. package/node_modules/@sema/nucleo/dist/formatador/index.part02.js.map +0 -1
  220. package/node_modules/@sema/nucleo/dist/index.js.map +0 -1
  221. package/node_modules/@sema/nucleo/dist/ir/conversor.js.map +0 -1
  222. package/node_modules/@sema/nucleo/dist/ir/conversor.part01.js.map +0 -1
  223. package/node_modules/@sema/nucleo/dist/ir/conversor.part02.js.map +0 -1
  224. package/node_modules/@sema/nucleo/dist/ir/conversor.part03.js.map +0 -1
  225. package/node_modules/@sema/nucleo/dist/ir/modelos.js.map +0 -1
  226. package/node_modules/@sema/nucleo/dist/lexer/lexer.js.map +0 -1
  227. package/node_modules/@sema/nucleo/dist/lexer/tokens.js.map +0 -1
  228. package/node_modules/@sema/nucleo/dist/parser/parser.declaracoes.js.map +0 -1
  229. package/node_modules/@sema/nucleo/dist/parser/parser.js.map +0 -1
  230. package/node_modules/@sema/nucleo/dist/parser/parser.modulo.js.map +0 -1
  231. package/node_modules/@sema/nucleo/dist/parser/parser.part01.js.map +0 -1
  232. package/node_modules/@sema/nucleo/dist/parser/parser.part02.js.map +0 -1
  233. package/node_modules/@sema/nucleo/dist/parser/parser.part03.js.map +0 -1
  234. package/node_modules/@sema/nucleo/dist/persistencia/contratos.js.map +0 -1
  235. package/node_modules/@sema/nucleo/dist/semantico/analisador.js.map +0 -1
  236. package/node_modules/@sema/nucleo/dist/semantico/analisador.part01.js.map +0 -1
  237. package/node_modules/@sema/nucleo/dist/semantico/analisador.part02.js.map +0 -1
  238. package/node_modules/@sema/nucleo/dist/semantico/analisador.part03.js.map +0 -1
  239. package/node_modules/@sema/nucleo/dist/semantico/analisador.part04.js.map +0 -1
  240. package/node_modules/@sema/nucleo/dist/semantico/analisador.part05.js.map +0 -1
  241. package/node_modules/@sema/nucleo/dist/semantico/analisador.part06.js.map +0 -1
  242. package/node_modules/@sema/nucleo/dist/semantico/analisador.part07.js.map +0 -1
  243. package/node_modules/@sema/nucleo/dist/semantico/analisador.part08.js.map +0 -1
  244. package/node_modules/@sema/nucleo/dist/semantico/estruturas.js.map +0 -1
  245. package/node_modules/@sema/nucleo/dist/semantico/estruturas.part01.js.map +0 -1
  246. package/node_modules/@sema/nucleo/dist/semantico/estruturas.part02.js.map +0 -1
  247. package/node_modules/@sema/nucleo/dist/semantico/orcamentoSemantico.js.map +0 -1
  248. package/node_modules/@sema/nucleo/dist/semantico/seguranca.js.map +0 -1
  249. package/node_modules/@sema/nucleo/dist/util/arquivos.js.map +0 -1
  250. package/node_modules/@sema/padroes/dist/index.js.map +0 -1
@@ -1,1167 +1,8 @@
1
1
  // SEMA-GOVERNED: sema.produto.sistemas_interativos.operacao
2
- // Descricao: validadores e planejadores operacionais puros; runners externos continuam donos de toda execucao.
3
- import { createHash } from "node:crypto";
4
- import { ACCEPTANCE_LOCK_SCHEMA_V1, ASSET_PROVENANCE_SCHEMA_V1, EDITOR_STATE_SCHEMA_V1, ENGINE_DIFF_SCHEMA_V1, ENGINE_SNAPSHOT_SCHEMA_V1, JOB_ORCHESTRATION_SCHEMA_V1, MULTIMODAL_EVIDENCE_SCHEMA_V1, OPERATION_RESULT_SCHEMA_V1, } from "./operationsTypes.js";
2
+ // Descricao: fachada publica estavel para validadores e planejadores operacionais puros.
3
+ export { criarReferenciaFonteOpaca, digestJsonOperacional, } from "./operationPrimitives.js";
4
+ export { derivarDiffSnapshotsEngine, validarEstadoEditor, validarProvenienciaAsset, validarSnapshotEngine, } from "./engineObservation.js";
5
+ export { planejarOrquestracaoJobs } from "./jobOrchestration.js";
6
+ export { digestVinculoClaimMultimodal, operarAcceptanceLock, validarAcceptanceLock, validarEvidenciaMultimodal, } from "./acceptanceEvidence.js";
5
7
  export * from "./operationsTypes.js";
6
- const BASE_FLAGS = {
7
- executed: false,
8
- workspaceMutated: false,
9
- engineProbed: false,
10
- editorInspected: false,
11
- processesInspected: false,
12
- resourcesReserved: false,
13
- authoritative: false,
14
- };
15
- const SHA256_PATTERN = /^sha256:[a-f0-9]{64}$/;
16
- const OPAQUE_SHA256_PATTERN = /^opaque:sha256:[a-f0-9]{64}$/;
17
- const SEMANTIC_ID_PATTERN = /^[a-z][a-z0-9_-]{0,31}(?:[.:/][a-z0-9][a-z0-9_-]{0,63})+$/;
18
- const SAFE_NAME_PATTERN = /^[A-Za-z][A-Za-z0-9._+-]{0,127}$/;
19
- const VERSION_PATTERN = /^[0-9]+\.[0-9]+\.[0-9]+(?:-[A-Za-z0-9.-]+)?$/;
20
- const MEDIA_TYPE_PATTERN = /^[a-z0-9][a-z0-9.+-]{0,63}\/[a-z0-9][a-z0-9.+-]{0,63}$/;
21
- const DANGEROUS_KEYS = new Set(["__proto__", "prototype", "constructor"]);
22
- const OPAQUE_SENSITIVE_KEYS = new Set(["recoverytoken", "sourceuriref"]);
23
- const SENSITIVE_KEY_PARTS = [
24
- "password", "passwd", "secret", "token", "apikey", "privatekey",
25
- "clientsecret", "accesstoken", "refreshtoken", "credential",
26
- "authorization", "cookie", "connectionstring",
27
- ];
28
- const SENSITIVE_VALUE_PATTERNS = [
29
- /\bbearer\s+[a-z0-9._~+\/-]{8,}/i,
30
- /^(?:sk[-_][a-z0-9_-]{8,}|ghp_[a-z0-9]{20,}|github_pat_[a-z0-9_]{20,})$/i,
31
- /^eyJ[a-z0-9_-]{8,}\.eyJ[a-z0-9_-]{8,}\.[a-z0-9_-]{8,}$/i,
32
- /\b(?:AKIA|ASIA)[A-Z0-9]{16}\b/,
33
- /-----BEGIN [A-Z0-9 ]*(?:PRIVATE KEY|CERTIFICATE)-----/,
34
- /(?:^|[?&])(?:access_?token|api_?key|aws_?secret_?access_?key|secret|password|passwd|signature|sig|token|credential|authorization)=[^&#\s]+/i,
35
- /:\/\/[^/\s:@]+:[^/\s@]+@/,
36
- ];
37
- function issue(code, field) {
38
- return { code, field };
39
- }
40
- function normalizedIssues(issues) {
41
- const unique = new Map();
42
- for (const item of issues)
43
- unique.set(item.code + "\u0000" + item.field, item);
44
- return [...unique.values()].sort((a, b) => (a.code.localeCompare(b.code) || a.field.localeCompare(b.field)));
45
- }
46
- function failure(issues) {
47
- return {
48
- schemaVersion: OPERATION_RESULT_SCHEMA_V1,
49
- valid: false,
50
- issues: normalizedIssues(issues),
51
- ...BASE_FLAGS,
52
- };
53
- }
54
- function success(value, digest) {
55
- return {
56
- schemaVersion: OPERATION_RESULT_SCHEMA_V1,
57
- valid: true,
58
- issues: [],
59
- value,
60
- ...(digest === undefined ? {} : { digest }),
61
- ...BASE_FLAGS,
62
- };
63
- }
64
- function isRecord(value) {
65
- if (value === null || typeof value !== "object" || Array.isArray(value))
66
- return false;
67
- const prototype = Object.getPrototypeOf(value);
68
- return prototype === Object.prototype || prototype === null;
69
- }
70
- function normalizedKey(key) {
71
- return key.toLowerCase().replace(/[^a-z0-9]/g, "");
72
- }
73
- function isSha256(value) {
74
- return typeof value === "string" && SHA256_PATTERN.test(value);
75
- }
76
- function isOpaqueSha256(value) {
77
- return typeof value === "string" && OPAQUE_SHA256_PATTERN.test(value);
78
- }
79
- function isSemanticId(value) {
80
- return typeof value === "string" && value.length <= 192 && SEMANTIC_ID_PATTERN.test(value);
81
- }
82
- function isSafeName(value) {
83
- return typeof value === "string" && SAFE_NAME_PATTERN.test(value);
84
- }
85
- function isVersion(value) {
86
- return typeof value === "string" && VERSION_PATTERN.test(value);
87
- }
88
- function isIsoTimestamp(value) {
89
- if (typeof value !== "string" || value.length > 40)
90
- return false;
91
- const parsed = Date.parse(value);
92
- return Number.isFinite(parsed) && new Date(parsed).toISOString() === value;
93
- }
94
- function isIntegerIn(value, minimum, maximum) {
95
- return typeof value === "number"
96
- && Number.isSafeInteger(value)
97
- && value >= minimum
98
- && value <= maximum;
99
- }
100
- function hasOnlyKeys(value, allowed) {
101
- const allowlist = new Set(allowed);
102
- return Object.keys(value).every((key) => allowlist.has(key));
103
- }
104
- function isSensitiveValue(value) {
105
- if (isSha256(value) || isOpaqueSha256(value))
106
- return false;
107
- return SENSITIVE_VALUE_PATTERNS.some((pattern) => pattern.test(value));
108
- }
109
- function inspectPlainJson(input, rootField) {
110
- const issues = [];
111
- const active = new Set();
112
- let nodes = 0;
113
- const visit = (value, field, depth) => {
114
- nodes += 1;
115
- if (nodes > 20_000) {
116
- issues.push(issue("json_node_limit_exceeded", rootField));
117
- return;
118
- }
119
- if (depth > 48) {
120
- issues.push(issue("json_depth_limit_exceeded", rootField));
121
- return;
122
- }
123
- if (typeof value === "string") {
124
- if (isSensitiveValue(value))
125
- issues.push(issue("sensitive_material_forbidden", field));
126
- return;
127
- }
128
- if (value === null || typeof value === "boolean")
129
- return;
130
- if (typeof value === "number") {
131
- if (!Number.isFinite(value))
132
- issues.push(issue("json_number_invalid", field));
133
- return;
134
- }
135
- if (typeof value !== "object") {
136
- issues.push(issue("json_type_unsupported", field));
137
- return;
138
- }
139
- if (active.has(value)) {
140
- issues.push(issue("json_cycle_detected", rootField));
141
- return;
142
- }
143
- active.add(value);
144
- if (Array.isArray(value)) {
145
- if (value.length > 10_000)
146
- issues.push(issue("json_array_limit_exceeded", field));
147
- for (const item of value)
148
- visit(item, field, depth + 1);
149
- active.delete(value);
150
- return;
151
- }
152
- if (!isRecord(value)) {
153
- issues.push(issue("json_object_not_plain", field));
154
- active.delete(value);
155
- return;
156
- }
157
- for (const [key, descriptor] of Object.entries(Object.getOwnPropertyDescriptors(value))) {
158
- if (DANGEROUS_KEYS.has(key))
159
- issues.push(issue("json_dangerous_key", field));
160
- if (descriptor.get !== undefined || descriptor.set !== undefined) {
161
- issues.push(issue("json_accessor_forbidden", field));
162
- continue;
163
- }
164
- const keyNormalized = normalizedKey(key);
165
- const child = descriptor.value;
166
- const sensitive = SENSITIVE_KEY_PARTS.some((part) => keyNormalized.includes(part));
167
- const opaqueException = OPAQUE_SENSITIVE_KEYS.has(keyNormalized) && isOpaqueSha256(child);
168
- if (sensitive && !opaqueException)
169
- issues.push(issue("sensitive_material_forbidden", field));
170
- visit(child, field, depth + 1);
171
- }
172
- active.delete(value);
173
- };
174
- visit(input, rootField, 0);
175
- return normalizedIssues(issues);
176
- }
177
- function canonicalJson(value) {
178
- if (Array.isArray(value))
179
- return "[" + value.map(canonicalJson).join(",") + "]";
180
- if (isRecord(value)) {
181
- return "{" + Object.keys(value).sort().map((key) => (JSON.stringify(key) + ":" + canonicalJson(value[key]))).join(",") + "}";
182
- }
183
- return JSON.stringify(value);
184
- }
185
- export function digestJsonOperacional(value) {
186
- return ("sha256:" + createHash("sha256").update(canonicalJson(value)).digest("hex"));
187
- }
188
- export function criarReferenciaFonteOpaca(sourceUri) {
189
- if (typeof sourceUri !== "string" || sourceUri.length === 0 || sourceUri.length > 4096 || sourceUri.includes("\u0000")) {
190
- return failure([issue("source_uri_invalid", "sourceUri")]);
191
- }
192
- const sourceUriRef = ("opaque:sha256:" + createHash("sha256").update(sourceUri).digest("hex"));
193
- return success({ sourceUriRef, sourceUriRedacted: true }, digestJsonOperacional(sourceUriRef));
194
- }
195
- export function validarSnapshotEngine(input) {
196
- const issues = inspectPlainJson(input, "snapshot");
197
- if (!isRecord(input))
198
- return failure([...issues, issue("snapshot_object_required", "snapshot")]);
199
- if (!hasOnlyKeys(input, [
200
- "schemaVersion", "snapshotId", "projectId", "sceneId", "adapter",
201
- "semanticObjects", "artifactDigest", "readOnly", "authoritative",
202
- ]))
203
- issues.push(issue("snapshot_unknown_field", "snapshot"));
204
- if (input.schemaVersion !== ENGINE_SNAPSHOT_SCHEMA_V1)
205
- issues.push(issue("snapshot_schema_invalid", "schemaVersion"));
206
- if (!isSemanticId(input.snapshotId))
207
- issues.push(issue("snapshot_id_invalid", "snapshotId"));
208
- if (!isSemanticId(input.projectId))
209
- issues.push(issue("project_id_invalid", "projectId"));
210
- if (!isSemanticId(input.sceneId))
211
- issues.push(issue("scene_id_invalid", "sceneId"));
212
- if (!isSha256(input.artifactDigest))
213
- issues.push(issue("artifact_digest_invalid", "artifactDigest"));
214
- if (input.readOnly !== true)
215
- issues.push(issue("snapshot_must_be_read_only", "readOnly"));
216
- if (input.authoritative !== false)
217
- issues.push(issue("snapshot_must_be_non_authoritative", "authoritative"));
218
- const adapter = input.adapter;
219
- if (!isRecord(adapter)
220
- || !hasOnlyKeys(adapter, ["adapterId", "adapterVersion"])
221
- || !isSafeName(adapter.adapterId)
222
- || !isVersion(adapter.adapterVersion))
223
- issues.push(issue("snapshot_adapter_invalid", "adapter"));
224
- const objects = input.semanticObjects;
225
- const ids = new Set();
226
- if (!Array.isArray(objects) || objects.length === 0) {
227
- issues.push(issue("snapshot_objects_required", "semanticObjects"));
228
- }
229
- else {
230
- for (const object of objects) {
231
- if (!isRecord(object) || !hasOnlyKeys(object, [
232
- "semanticId", "kind", "parentSemanticId", "stateDigest", "componentDigests",
233
- ])) {
234
- issues.push(issue("snapshot_object_invalid", "semanticObjects"));
235
- continue;
236
- }
237
- if (!isSemanticId(object.semanticId))
238
- issues.push(issue("semantic_object_id_invalid", "semanticObjects"));
239
- else if (ids.has(object.semanticId))
240
- issues.push(issue("semantic_object_id_duplicate", "semanticObjects"));
241
- else
242
- ids.add(object.semanticId);
243
- if (!isSafeName(object.kind))
244
- issues.push(issue("semantic_object_kind_invalid", "semanticObjects"));
245
- if (object.parentSemanticId !== undefined && !isSemanticId(object.parentSemanticId)) {
246
- issues.push(issue("semantic_parent_id_invalid", "semanticObjects"));
247
- }
248
- if (!isSha256(object.stateDigest))
249
- issues.push(issue("semantic_state_digest_invalid", "semanticObjects"));
250
- if (!isRecord(object.componentDigests)) {
251
- issues.push(issue("component_digests_invalid", "semanticObjects"));
252
- }
253
- else
254
- for (const [name, digest] of Object.entries(object.componentDigests)) {
255
- if (!isSafeName(name) || !isSha256(digest))
256
- issues.push(issue("component_digest_invalid", "semanticObjects"));
257
- }
258
- }
259
- for (const object of objects) {
260
- if (isRecord(object) && typeof object.parentSemanticId === "string" && !ids.has(object.parentSemanticId)) {
261
- issues.push(issue("semantic_parent_missing", "semanticObjects"));
262
- }
263
- }
264
- const parentById = new Map();
265
- for (const object of objects) {
266
- if (!isRecord(object) || !isSemanticId(object.semanticId) || !isSemanticId(object.parentSemanticId))
267
- continue;
268
- if (object.parentSemanticId === object.semanticId) {
269
- issues.push(issue("semantic_parent_self_reference", "semanticObjects"));
270
- }
271
- else if (ids.has(object.parentSemanticId))
272
- parentById.set(object.semanticId, object.parentSemanticId);
273
- }
274
- for (const start of parentById.keys()) {
275
- const path = new Set();
276
- let cursor = start;
277
- while (cursor !== undefined && parentById.has(cursor)) {
278
- if (path.has(cursor)) {
279
- issues.push(issue("semantic_parent_cycle", "semanticObjects"));
280
- break;
281
- }
282
- path.add(cursor);
283
- cursor = parentById.get(cursor);
284
- }
285
- if (issues.some((item) => item.code === "semantic_parent_cycle"))
286
- break;
287
- }
288
- }
289
- if (issues.length > 0)
290
- return failure(issues);
291
- const snapshot = input;
292
- const normalized = {
293
- ...snapshot,
294
- adapter: { ...snapshot.adapter },
295
- semanticObjects: snapshot.semanticObjects.map((object) => ({
296
- ...object,
297
- componentDigests: Object.fromEntries(Object.entries(object.componentDigests).sort(([left], [right]) => left.localeCompare(right))),
298
- })).sort((left, right) => left.semanticId.localeCompare(right.semanticId)),
299
- };
300
- const snapshotDigest = digestJsonOperacional(normalized);
301
- return success({ snapshot: normalized, snapshotDigest, localValidationOnly: true }, snapshotDigest);
302
- }
303
- export function derivarDiffSnapshotsEngine(beforeInput, afterInput) {
304
- const beforeResult = validarSnapshotEngine(beforeInput);
305
- const afterResult = validarSnapshotEngine(afterInput);
306
- const issues = [];
307
- if (!beforeResult.valid)
308
- issues.push(issue("before_snapshot_invalid", "snapshotBefore"), ...beforeResult.issues);
309
- if (!afterResult.valid)
310
- issues.push(issue("after_snapshot_invalid", "snapshotAfter"), ...afterResult.issues);
311
- if (!beforeResult.value || !afterResult.value)
312
- return failure(issues);
313
- const before = beforeResult.value.snapshot;
314
- const after = afterResult.value.snapshot;
315
- if (before.projectId !== after.projectId)
316
- issues.push(issue("snapshot_project_binding_mismatch", "projectId"));
317
- if (before.sceneId !== after.sceneId)
318
- issues.push(issue("snapshot_scene_binding_mismatch", "sceneId"));
319
- if (before.adapter.adapterId !== after.adapter.adapterId
320
- || before.adapter.adapterVersion !== after.adapter.adapterVersion) {
321
- issues.push(issue("snapshot_adapter_binding_mismatch", "adapter"));
322
- }
323
- if (issues.length > 0)
324
- return failure(issues);
325
- const beforeById = new Map(before.semanticObjects.map((item) => [item.semanticId, item]));
326
- const afterById = new Map(after.semanticObjects.map((item) => [item.semanticId, item]));
327
- const allIds = [...new Set([...beforeById.keys(), ...afterById.keys()])].sort();
328
- const changes = [];
329
- for (const semanticId of allIds) {
330
- const previous = beforeById.get(semanticId);
331
- const current = afterById.get(semanticId);
332
- if (!previous && current) {
333
- changes.push({ semanticId, change: "ADDED", afterDigest: digestJsonOperacional(current) });
334
- }
335
- else if (previous && !current) {
336
- changes.push({ semanticId, change: "REMOVED", beforeDigest: digestJsonOperacional(previous) });
337
- }
338
- else if (previous && current) {
339
- const beforeDigest = digestJsonOperacional(previous);
340
- const afterDigest = digestJsonOperacional(current);
341
- if (beforeDigest !== afterDigest)
342
- changes.push({ semanticId, change: "MODIFIED", beforeDigest, afterDigest });
343
- }
344
- }
345
- const withoutDigest = {
346
- schemaVersion: ENGINE_DIFF_SCHEMA_V1,
347
- beforeSnapshotDigest: beforeResult.value.snapshotDigest,
348
- afterSnapshotDigest: afterResult.value.snapshotDigest,
349
- bindingDigest: digestJsonOperacional({ projectId: before.projectId, sceneId: before.sceneId, adapter: before.adapter }),
350
- artifactDigestChanged: before.artifactDigest !== after.artifactDigest,
351
- changes,
352
- readOnly: true,
353
- authoritative: false,
354
- };
355
- const diff = { ...withoutDigest, diffDigest: digestJsonOperacional(withoutDigest) };
356
- return success(diff, diff.diffDigest);
357
- }
358
- export function validarProvenienciaAsset(input) {
359
- const issues = inspectPlainJson(input, "provenance");
360
- if (!isRecord(input))
361
- return failure([...issues, issue("provenance_object_required", "provenance")]);
362
- if (!hasOnlyKeys(input, [
363
- "schemaVersion", "assetId", "sourceUriRef", "sourceUriRedacted", "license",
364
- "sourceHash", "contentHash", "transforms", "derivatives", "authoritative",
365
- ]))
366
- issues.push(issue("provenance_unknown_field", "provenance"));
367
- if (input.schemaVersion !== ASSET_PROVENANCE_SCHEMA_V1)
368
- issues.push(issue("provenance_schema_invalid", "schemaVersion"));
369
- if (!isSemanticId(input.assetId))
370
- issues.push(issue("asset_id_invalid", "assetId"));
371
- if (!isOpaqueSha256(input.sourceUriRef))
372
- issues.push(issue("source_uri_ref_must_be_opaque", "sourceUriRef"));
373
- if (input.sourceUriRedacted !== true)
374
- issues.push(issue("source_uri_must_be_redacted", "sourceUriRedacted"));
375
- if (!isSha256(input.sourceHash))
376
- issues.push(issue("source_hash_invalid", "sourceHash"));
377
- if (!isSha256(input.contentHash))
378
- issues.push(issue("content_hash_invalid", "contentHash"));
379
- if (input.authoritative !== false)
380
- issues.push(issue("provenance_must_be_non_authoritative", "authoritative"));
381
- const license = input.license;
382
- if (!isRecord(license)
383
- || !hasOnlyKeys(license, ["licenseId", "evidenceDigest", "redistributable"])
384
- || !isSafeName(license.licenseId)
385
- || !isSha256(license.evidenceDigest)
386
- || typeof license.redistributable !== "boolean")
387
- issues.push(issue("asset_license_invalid", "license"));
388
- const transforms = input.transforms;
389
- const transformIds = new Set();
390
- let previousDigest = input.sourceHash;
391
- if (!Array.isArray(transforms)) {
392
- issues.push(issue("asset_transforms_invalid", "transforms"));
393
- }
394
- else {
395
- for (const transform of transforms) {
396
- if (!isRecord(transform) || !hasOnlyKeys(transform, [
397
- "transformId", "toolRef", "toolVersion", "inputDigest", "outputDigest", "parametersDigest",
398
- ])) {
399
- issues.push(issue("asset_transform_invalid", "transforms"));
400
- continue;
401
- }
402
- if (!isSemanticId(transform.transformId))
403
- issues.push(issue("transform_id_invalid", "transforms"));
404
- else if (transformIds.has(transform.transformId))
405
- issues.push(issue("transform_id_duplicate", "transforms"));
406
- else
407
- transformIds.add(transform.transformId);
408
- if (!isSafeName(transform.toolRef) || !isVersion(transform.toolVersion))
409
- issues.push(issue("transform_tool_invalid", "transforms"));
410
- if (!isSha256(transform.inputDigest) || !isSha256(transform.outputDigest) || !isSha256(transform.parametersDigest)) {
411
- issues.push(issue("transform_digest_invalid", "transforms"));
412
- }
413
- if (transform.inputDigest !== previousDigest)
414
- issues.push(issue("transform_chain_broken", "transforms"));
415
- previousDigest = transform.outputDigest;
416
- }
417
- if (previousDigest !== input.contentHash)
418
- issues.push(issue("transform_final_hash_mismatch", "contentHash"));
419
- }
420
- const derivatives = input.derivatives;
421
- const derivativeIds = new Set();
422
- const derivativeHashes = new Set();
423
- const parentByHash = new Map();
424
- if (!Array.isArray(derivatives)) {
425
- issues.push(issue("asset_derivatives_invalid", "derivatives"));
426
- }
427
- else {
428
- for (const derivative of derivatives) {
429
- if (!isRecord(derivative) || !hasOnlyKeys(derivative, [
430
- "assetId", "parentContentHash", "contentHash", "transformDigest",
431
- ])) {
432
- issues.push(issue("asset_derivative_invalid", "derivatives"));
433
- continue;
434
- }
435
- if (!isSemanticId(derivative.assetId))
436
- issues.push(issue("derivative_asset_id_invalid", "derivatives"));
437
- else if (derivativeIds.has(derivative.assetId))
438
- issues.push(issue("derivative_asset_id_duplicate", "derivatives"));
439
- else
440
- derivativeIds.add(derivative.assetId);
441
- if (!isSha256(derivative.parentContentHash)
442
- || !isSha256(derivative.contentHash)
443
- || !isSha256(derivative.transformDigest)) {
444
- issues.push(issue("derivative_digest_invalid", "derivatives"));
445
- continue;
446
- }
447
- if (derivativeHashes.has(derivative.contentHash) || derivative.contentHash === input.contentHash) {
448
- issues.push(issue("derivative_content_hash_duplicate", "derivatives"));
449
- }
450
- derivativeHashes.add(derivative.contentHash);
451
- parentByHash.set(derivative.contentHash, derivative.parentContentHash);
452
- }
453
- const knownHashes = new Set([input.contentHash, ...derivativeHashes]);
454
- for (const [contentHash, parentHash] of parentByHash) {
455
- if (!knownHashes.has(parentHash))
456
- issues.push(issue("derivative_parent_missing", "derivatives"));
457
- const visited = new Set();
458
- let cursor = contentHash;
459
- while (cursor !== undefined && cursor !== input.contentHash) {
460
- if (visited.has(cursor)) {
461
- issues.push(issue("derivative_cycle_detected", "derivatives"));
462
- break;
463
- }
464
- visited.add(cursor);
465
- cursor = parentByHash.get(cursor);
466
- if (cursor === undefined)
467
- issues.push(issue("derivative_lineage_incomplete", "derivatives"));
468
- }
469
- }
470
- }
471
- if (issues.length > 0)
472
- return failure(issues);
473
- const provenance = input;
474
- const normalized = {
475
- ...provenance,
476
- license: { ...provenance.license },
477
- transforms: provenance.transforms.map((item) => ({ ...item })),
478
- derivatives: provenance.derivatives.map((item) => ({ ...item }))
479
- .sort((left, right) => left.assetId.localeCompare(right.assetId)),
480
- };
481
- const provenanceDigest = digestJsonOperacional(normalized);
482
- return success({ provenance: normalized, provenanceDigest }, provenanceDigest);
483
- }
484
- const BACKGROUND_JOB_STATES = new Set(["QUEUED", "RUNNING", "SUCCEEDED", "FAILED", "CANCELLED"]);
485
- const EDITOR_MODES = new Set(["EDIT", "PLAY", "PAUSED"]);
486
- const PROCESS_ROLES = new Set(["ENGINE", "EDITOR", "SHADER_COMPILER", "IMPORT_WORKER", "BUILD_WORKER"]);
487
- const PROCESS_STATES = new Set(["IDLE", "RUNNING", "BLOCKED", "FAILED", "EXITED"]);
488
- function validateBackgroundJobs(value, field, issues) {
489
- const ids = new Set();
490
- if (!Array.isArray(value)) {
491
- issues.push(issue("editor_jobs_invalid", field));
492
- return;
493
- }
494
- for (const job of value) {
495
- if (!isRecord(job)
496
- || !hasOnlyKeys(job, ["jobId", "status", "progressBasisPoints"])
497
- || !isSemanticId(job.jobId)
498
- || typeof job.status !== "string"
499
- || !BACKGROUND_JOB_STATES.has(job.status)
500
- || !isIntegerIn(job.progressBasisPoints, 0, 10_000)) {
501
- issues.push(issue("editor_job_invalid", field));
502
- continue;
503
- }
504
- if (ids.has(job.jobId))
505
- issues.push(issue("editor_job_id_duplicate", field));
506
- ids.add(job.jobId);
507
- }
508
- }
509
- export function validarEstadoEditor(input) {
510
- const issues = inspectPlainJson(input, "editorState");
511
- if (!isRecord(input))
512
- return failure([...issues, issue("editor_state_object_required", "editorState")]);
513
- if (!hasOnlyKeys(input, [
514
- "schemaVersion", "editorSessionId", "adapter", "scene", "selection", "mode",
515
- "unsavedChanges", "shaderJobs", "importJobs", "plugins", "modals", "processes",
516
- "observedAt", "readOnly", "authoritative",
517
- ]))
518
- issues.push(issue("editor_state_unknown_field", "editorState"));
519
- if (input.schemaVersion !== EDITOR_STATE_SCHEMA_V1)
520
- issues.push(issue("editor_state_schema_invalid", "schemaVersion"));
521
- if (!isSemanticId(input.editorSessionId))
522
- issues.push(issue("editor_session_id_invalid", "editorSessionId"));
523
- if (typeof input.mode !== "string" || !EDITOR_MODES.has(input.mode))
524
- issues.push(issue("editor_mode_invalid", "mode"));
525
- if (typeof input.unsavedChanges !== "boolean")
526
- issues.push(issue("unsaved_changes_invalid", "unsavedChanges"));
527
- if (!isIsoTimestamp(input.observedAt))
528
- issues.push(issue("editor_observed_at_invalid", "observedAt"));
529
- if (input.readOnly !== true)
530
- issues.push(issue("editor_state_must_be_read_only", "readOnly"));
531
- if (input.authoritative !== false)
532
- issues.push(issue("editor_state_must_be_non_authoritative", "authoritative"));
533
- if (!isRecord(input.adapter)
534
- || !hasOnlyKeys(input.adapter, ["adapterId", "adapterVersion"])
535
- || !isSafeName(input.adapter.adapterId)
536
- || !isVersion(input.adapter.adapterVersion))
537
- issues.push(issue("editor_adapter_invalid", "adapter"));
538
- if (!isRecord(input.scene)
539
- || !hasOnlyKeys(input.scene, ["semanticId", "artifactDigest"])
540
- || !isSemanticId(input.scene.semanticId)
541
- || !isSha256(input.scene.artifactDigest))
542
- issues.push(issue("editor_scene_invalid", "scene"));
543
- const selectionIds = new Set();
544
- if (!Array.isArray(input.selection))
545
- issues.push(issue("editor_selection_invalid", "selection"));
546
- else
547
- for (const selected of input.selection) {
548
- if (!isSemanticId(selected))
549
- issues.push(issue("editor_selection_id_invalid", "selection"));
550
- else if (selectionIds.has(selected))
551
- issues.push(issue("editor_selection_duplicate", "selection"));
552
- else
553
- selectionIds.add(selected);
554
- }
555
- validateBackgroundJobs(input.shaderJobs, "shaderJobs", issues);
556
- validateBackgroundJobs(input.importJobs, "importJobs", issues);
557
- const pluginIds = new Set();
558
- if (!Array.isArray(input.plugins))
559
- issues.push(issue("editor_plugins_invalid", "plugins"));
560
- else
561
- for (const plugin of input.plugins) {
562
- if (!isRecord(plugin)
563
- || !hasOnlyKeys(plugin, ["pluginId", "version", "enabled", "provenanceDigest"])
564
- || !isSafeName(plugin.pluginId)
565
- || !isVersion(plugin.version)
566
- || typeof plugin.enabled !== "boolean"
567
- || !isSha256(plugin.provenanceDigest)) {
568
- issues.push(issue("editor_plugin_invalid", "plugins"));
569
- continue;
570
- }
571
- if (pluginIds.has(plugin.pluginId))
572
- issues.push(issue("editor_plugin_id_duplicate", "plugins"));
573
- pluginIds.add(plugin.pluginId);
574
- }
575
- const modalIds = new Set();
576
- if (!Array.isArray(input.modals))
577
- issues.push(issue("editor_modals_invalid", "modals"));
578
- else
579
- for (const modal of input.modals) {
580
- if (!isRecord(modal)
581
- || !hasOnlyKeys(modal, ["modalId", "kind", "blocking"])
582
- || !isSemanticId(modal.modalId)
583
- || !isSafeName(modal.kind)
584
- || typeof modal.blocking !== "boolean") {
585
- issues.push(issue("editor_modal_invalid", "modals"));
586
- continue;
587
- }
588
- if (modalIds.has(modal.modalId))
589
- issues.push(issue("editor_modal_id_duplicate", "modals"));
590
- modalIds.add(modal.modalId);
591
- }
592
- const processRefs = new Set();
593
- if (!Array.isArray(input.processes))
594
- issues.push(issue("editor_processes_invalid", "processes"));
595
- else
596
- for (const process of input.processes) {
597
- if (!isRecord(process)
598
- || !hasOnlyKeys(process, ["processRef", "role", "state"])
599
- || !isOpaqueSha256(process.processRef)
600
- || typeof process.role !== "string"
601
- || !PROCESS_ROLES.has(process.role)
602
- || typeof process.state !== "string"
603
- || !PROCESS_STATES.has(process.state)) {
604
- issues.push(issue("editor_process_invalid", "processes"));
605
- continue;
606
- }
607
- if (processRefs.has(process.processRef))
608
- issues.push(issue("editor_process_ref_duplicate", "processes"));
609
- processRefs.add(process.processRef);
610
- }
611
- if (issues.length > 0)
612
- return failure(issues);
613
- const state = input;
614
- const normalized = {
615
- ...state,
616
- adapter: { ...state.adapter },
617
- scene: { ...state.scene },
618
- selection: [...state.selection].sort(),
619
- shaderJobs: state.shaderJobs.map((item) => ({ ...item })).sort((a, b) => a.jobId.localeCompare(b.jobId)),
620
- importJobs: state.importJobs.map((item) => ({ ...item })).sort((a, b) => a.jobId.localeCompare(b.jobId)),
621
- plugins: state.plugins.map((item) => ({ ...item })).sort((a, b) => a.pluginId.localeCompare(b.pluginId)),
622
- modals: state.modals.map((item) => ({ ...item })).sort((a, b) => a.modalId.localeCompare(b.modalId)),
623
- processes: state.processes.map((item) => ({ ...item })).sort((a, b) => a.processRef.localeCompare(b.processRef)),
624
- };
625
- const editorStateDigest = digestJsonOperacional(normalized);
626
- return success({ state: normalized, editorStateDigest, externallyObserved: false }, editorStateDigest);
627
- }
628
- const RESOURCE_LOCKS = ["GPU", "EDITOR", "CACHE"];
629
- function validateBudget(value, field, issues) {
630
- if (!isRecord(value)
631
- || !hasOnlyKeys(value, ["ramMb", "vramMb", "diskMb"])
632
- || !isIntegerIn(value.ramMb, 1, 16_777_216)
633
- || !isIntegerIn(value.vramMb, 0, 16_777_216)
634
- || !isIntegerIn(value.diskMb, 1, 1_073_741_824)) {
635
- issues.push(issue("resource_budget_invalid", field));
636
- return false;
637
- }
638
- return true;
639
- }
640
- export function planejarOrquestracaoJobs(input) {
641
- const issues = inspectPlainJson(input, "jobRequest");
642
- if (!isRecord(input))
643
- return failure([...issues, issue("job_request_object_required", "jobRequest")]);
644
- if (!hasOnlyKeys(input, ["schemaVersion", "queueId", "capacity", "lockCapacity", "jobs"])) {
645
- issues.push(issue("job_request_unknown_field", "jobRequest"));
646
- }
647
- if (input.schemaVersion !== JOB_ORCHESTRATION_SCHEMA_V1)
648
- issues.push(issue("job_schema_invalid", "schemaVersion"));
649
- if (!isSemanticId(input.queueId))
650
- issues.push(issue("queue_id_invalid", "queueId"));
651
- const capacity = input.capacity;
652
- const capacityValid = validateBudget(capacity, "capacity", issues);
653
- const lockCapacity = input.lockCapacity;
654
- if (!isRecord(lockCapacity)
655
- || !hasOnlyKeys(lockCapacity, RESOURCE_LOCKS)
656
- || !RESOURCE_LOCKS.every((lock) => isIntegerIn(lockCapacity[lock], 0, 1))) {
657
- issues.push(issue("lock_capacity_invalid", "lockCapacity"));
658
- }
659
- const jobs = input.jobs;
660
- const ids = new Set();
661
- if (!Array.isArray(jobs) || jobs.length === 0) {
662
- issues.push(issue("jobs_required", "jobs"));
663
- }
664
- else {
665
- for (const job of jobs) {
666
- if (!isRecord(job) || !hasOnlyKeys(job, [
667
- "jobId", "kind", "priority", "dependencies", "locks", "budget",
668
- "heartbeat", "checkpoint", "adapter",
669
- ])) {
670
- issues.push(issue("job_invalid", "jobs"));
671
- continue;
672
- }
673
- if (!isSemanticId(job.jobId))
674
- issues.push(issue("job_id_invalid", "jobs"));
675
- else if (ids.has(job.jobId))
676
- issues.push(issue("job_id_duplicate", "jobs"));
677
- else
678
- ids.add(job.jobId);
679
- if (!isSafeName(job.kind))
680
- issues.push(issue("job_kind_invalid", "jobs"));
681
- if (!isIntegerIn(job.priority, 0, 100))
682
- issues.push(issue("job_priority_invalid", "jobs"));
683
- if (!Array.isArray(job.dependencies)
684
- || job.dependencies.some((dependency) => !isSemanticId(dependency))
685
- || new Set(job.dependencies).size !== job.dependencies.length
686
- || job.dependencies.includes(job.jobId))
687
- issues.push(issue("job_dependencies_invalid", "jobs"));
688
- if (!Array.isArray(job.locks)
689
- || job.locks.some((lock) => typeof lock !== "string" || !RESOURCE_LOCKS.includes(lock))
690
- || new Set(job.locks).size !== job.locks.length)
691
- issues.push(issue("job_locks_invalid", "jobs"));
692
- const budget = job.budget;
693
- const budgetValid = validateBudget(budget, "jobs", issues);
694
- if (budgetValid && capacityValid
695
- && (budget.ramMb > capacity.ramMb
696
- || budget.vramMb > capacity.vramMb
697
- || budget.diskMb > capacity.diskMb))
698
- issues.push(issue("job_budget_exceeds_capacity", "jobs"));
699
- if (Array.isArray(job.locks) && isRecord(lockCapacity)) {
700
- for (const lock of job.locks) {
701
- if (typeof lock === "string"
702
- && RESOURCE_LOCKS.includes(lock)
703
- && lockCapacity[lock] !== 1)
704
- issues.push(issue("job_lock_unavailable", "jobs"));
705
- }
706
- if (job.locks.includes("GPU") && isRecord(job.budget) && job.budget.vramMb === 0) {
707
- issues.push(issue("gpu_job_requires_vram", "jobs"));
708
- }
709
- }
710
- if (!isRecord(job.heartbeat)
711
- || !hasOnlyKeys(job.heartbeat, ["intervalMs", "timeoutMs"])
712
- || !isIntegerIn(job.heartbeat.intervalMs, 100, 86_400_000)
713
- || !isIntegerIn(job.heartbeat.timeoutMs, 100, 86_400_000)
714
- || (typeof job.heartbeat.intervalMs === "number"
715
- && typeof job.heartbeat.timeoutMs === "number"
716
- && job.heartbeat.timeoutMs < job.heartbeat.intervalMs * 2))
717
- issues.push(issue("job_heartbeat_invalid", "jobs"));
718
- if (!isRecord(job.checkpoint)
719
- || !hasOnlyKeys(job.checkpoint, ["intervalMs", "resume", "checkpointDigest", "recoveryToken"])
720
- || !isIntegerIn(job.checkpoint.intervalMs, 100, 86_400_000)
721
- || typeof job.checkpoint.resume !== "boolean"
722
- || !isOpaqueSha256(job.checkpoint.recoveryToken)
723
- || (job.checkpoint.checkpointDigest !== undefined && !isSha256(job.checkpoint.checkpointDigest))
724
- || (job.checkpoint.resume === true && !isSha256(job.checkpoint.checkpointDigest))) {
725
- issues.push(issue("job_checkpoint_invalid", "jobs"));
726
- }
727
- if (!isRecord(job.adapter)
728
- || !hasOnlyKeys(job.adapter, ["adapterId", "adapterVersion"])
729
- || !isSafeName(job.adapter.adapterId)
730
- || !isVersion(job.adapter.adapterVersion))
731
- issues.push(issue("job_adapter_invalid", "jobs"));
732
- }
733
- for (const job of jobs) {
734
- if (!isRecord(job) || !Array.isArray(job.dependencies))
735
- continue;
736
- for (const dependency of job.dependencies) {
737
- if (typeof dependency === "string" && !ids.has(dependency))
738
- issues.push(issue("job_dependency_missing", "jobs"));
739
- }
740
- }
741
- }
742
- if (issues.length > 0)
743
- return failure(issues);
744
- const request = input;
745
- const byId = new Map(request.jobs.map((job) => [job.jobId, job]));
746
- const indegree = new Map(request.jobs.map((job) => [job.jobId, job.dependencies.length]));
747
- const dependents = new Map();
748
- for (const job of request.jobs)
749
- for (const dependency of job.dependencies) {
750
- const list = dependents.get(dependency) ?? [];
751
- list.push(job.jobId);
752
- dependents.set(dependency, list);
753
- }
754
- const compareJobs = (leftId, rightId) => {
755
- const left = byId.get(leftId);
756
- const right = byId.get(rightId);
757
- return right.priority - left.priority || left.jobId.localeCompare(right.jobId);
758
- };
759
- const ready = request.jobs.filter((job) => job.dependencies.length === 0)
760
- .map((job) => job.jobId).sort(compareJobs);
761
- const ordered = [];
762
- while (ready.length > 0) {
763
- const id = ready.shift();
764
- ordered.push(byId.get(id));
765
- for (const dependent of (dependents.get(id) ?? []).sort()) {
766
- const next = (indegree.get(dependent) ?? 0) - 1;
767
- indegree.set(dependent, next);
768
- if (next === 0) {
769
- ready.push(dependent);
770
- ready.sort(compareJobs);
771
- }
772
- }
773
- }
774
- if (ordered.length !== request.jobs.length)
775
- return failure([issue("job_dependency_cycle", "jobs")]);
776
- const normalizedRequest = {
777
- schemaVersion: request.schemaVersion,
778
- queueId: request.queueId,
779
- capacity: { ...request.capacity },
780
- lockCapacity: Object.fromEntries(RESOURCE_LOCKS.map((lock) => [lock, request.lockCapacity[lock]])),
781
- jobs: request.jobs.map((job) => ({
782
- jobId: job.jobId,
783
- kind: job.kind,
784
- priority: job.priority,
785
- dependencies: [...job.dependencies].sort(),
786
- locks: [...job.locks].sort((a, b) => RESOURCE_LOCKS.indexOf(a) - RESOURCE_LOCKS.indexOf(b)),
787
- budget: { ...job.budget },
788
- heartbeat: { ...job.heartbeat },
789
- checkpoint: {
790
- intervalMs: job.checkpoint.intervalMs,
791
- resume: job.checkpoint.resume,
792
- ...(job.checkpoint.checkpointDigest === undefined ? {} : { checkpointDigest: job.checkpoint.checkpointDigest }),
793
- recoveryToken: job.checkpoint.recoveryToken,
794
- },
795
- adapter: { ...job.adapter },
796
- })).sort((left, right) => left.jobId.localeCompare(right.jobId)),
797
- };
798
- const requestDigest = digestJsonOperacional(normalizedRequest);
799
- const queue = ordered.map((job, index) => ({
800
- position: index + 1,
801
- jobId: job.jobId,
802
- kind: job.kind,
803
- priority: job.priority,
804
- adapter: { ...job.adapter },
805
- dependencies: [...job.dependencies].sort(),
806
- locks: [...job.locks].sort((a, b) => RESOURCE_LOCKS.indexOf(a) - RESOURCE_LOCKS.indexOf(b)),
807
- budget: { ...job.budget },
808
- heartbeatIntervalMs: job.heartbeat.intervalMs,
809
- heartbeatTimeoutMs: job.heartbeat.timeoutMs,
810
- checkpointIntervalMs: job.checkpoint.intervalMs,
811
- resume: job.checkpoint.resume,
812
- ...(job.checkpoint.checkpointDigest === undefined ? {} : { checkpointDigest: job.checkpoint.checkpointDigest }),
813
- recoveryToken: job.checkpoint.recoveryToken,
814
- }));
815
- const withoutDigest = {
816
- schemaVersion: JOB_ORCHESTRATION_SCHEMA_V1,
817
- queueId: request.queueId,
818
- queue,
819
- requestDigest,
820
- externalRunnerRequired: true,
821
- resourcesReserved: false,
822
- authoritative: false,
823
- };
824
- const plan = { ...withoutDigest, planDigest: digestJsonOperacional(withoutDigest) };
825
- return success(plan, plan.planDigest);
826
- }
827
- const ACCEPTANCE_REASONS = new Set([
828
- "ARTIFACT_CHANGED", "SCENE_CHANGED", "TIME_RANGE_CHANGED", "APPROVER_REVOKED", "MANUAL_WITHDRAWAL",
829
- ]);
830
- function validateTimeRange(input, field, issues) {
831
- if (!isRecord(input)
832
- || !hasOnlyKeys(input, ["start", "end", "unit"])
833
- || typeof input.start !== "number"
834
- || !Number.isFinite(input.start)
835
- || input.start < 0
836
- || typeof input.end !== "number"
837
- || !Number.isFinite(input.end)
838
- || input.end <= input.start
839
- || (input.unit !== "FRAME" && input.unit !== "TICK" && input.unit !== "SECOND")) {
840
- issues.push(issue("time_range_invalid", field));
841
- return false;
842
- }
843
- return true;
844
- }
845
- export function validarAcceptanceLock(input) {
846
- const issues = inspectPlainJson(input, "acceptanceLock");
847
- if (!isRecord(input))
848
- return failure([...issues, issue("acceptance_lock_object_required", "acceptanceLock")]);
849
- if (!hasOnlyKeys(input, [
850
- "schemaVersion", "lockId", "artifactDigest", "sceneId", "timeRange", "approver",
851
- "decision", "status", "createdAt", "invalidation", "authoritative",
852
- ]))
853
- issues.push(issue("acceptance_lock_unknown_field", "acceptanceLock"));
854
- if (input.schemaVersion !== ACCEPTANCE_LOCK_SCHEMA_V1)
855
- issues.push(issue("acceptance_lock_schema_invalid", "schemaVersion"));
856
- if (!isSemanticId(input.lockId))
857
- issues.push(issue("acceptance_lock_id_invalid", "lockId"));
858
- if (!isSha256(input.artifactDigest))
859
- issues.push(issue("acceptance_artifact_digest_invalid", "artifactDigest"));
860
- if (!isSemanticId(input.sceneId))
861
- issues.push(issue("acceptance_scene_id_invalid", "sceneId"));
862
- validateTimeRange(input.timeRange, "timeRange", issues);
863
- if (!isRecord(input.approver)
864
- || !hasOnlyKeys(input.approver, ["approverIdDigest", "role", "method"])
865
- || !isSha256(input.approver.approverIdDigest)
866
- || !isSafeName(input.approver.role)
867
- || (input.approver.method !== "HUMAN" && input.approver.method !== "POLICY")) {
868
- issues.push(issue("acceptance_approver_invalid", "approver"));
869
- }
870
- if (input.decision !== "ACCEPTED")
871
- issues.push(issue("acceptance_decision_invalid", "decision"));
872
- if (input.status !== "ACTIVE" && input.status !== "INVALIDATED")
873
- issues.push(issue("acceptance_status_invalid", "status"));
874
- if (!isIsoTimestamp(input.createdAt))
875
- issues.push(issue("acceptance_created_at_invalid", "createdAt"));
876
- if (input.authoritative !== false)
877
- issues.push(issue("acceptance_lock_must_be_non_authoritative", "authoritative"));
878
- if (input.status === "ACTIVE" && input.invalidation !== undefined) {
879
- issues.push(issue("active_lock_cannot_have_invalidation", "invalidation"));
880
- }
881
- if (input.status === "INVALIDATED") {
882
- const invalidation = input.invalidation;
883
- if (!isRecord(invalidation)
884
- || !hasOnlyKeys(invalidation, ["previousLockDigest", "invalidatedByDigest", "reasonCode", "invalidatedAt"])
885
- || !isSha256(invalidation.previousLockDigest)
886
- || !isSha256(invalidation.invalidatedByDigest)
887
- || typeof invalidation.reasonCode !== "string"
888
- || !ACCEPTANCE_REASONS.has(invalidation.reasonCode)
889
- || !isIsoTimestamp(invalidation.invalidatedAt)) {
890
- issues.push(issue("acceptance_invalidation_invalid", "invalidation"));
891
- }
892
- }
893
- if (issues.length > 0)
894
- return failure(issues);
895
- const lock = input;
896
- const normalized = {
897
- ...lock,
898
- timeRange: { ...lock.timeRange },
899
- approver: { ...lock.approver },
900
- ...(lock.invalidation === undefined ? {} : { invalidation: { ...lock.invalidation } }),
901
- };
902
- const lockDigest = digestJsonOperacional(normalized);
903
- return success({ lock: normalized, lockDigest }, lockDigest);
904
- }
905
- export function operarAcceptanceLock(operation, lockInput, contextInput) {
906
- if (operation !== "VALIDATE" && operation !== "EVALUATE" && operation !== "INVALIDATE") {
907
- return failure([issue("acceptance_operation_invalid", "operation")]);
908
- }
909
- const lockResult = validarAcceptanceLock(lockInput);
910
- if (!lockResult.value)
911
- return failure(lockResult.issues);
912
- const contextIssues = inspectPlainJson(contextInput, "context");
913
- if (!isRecord(contextInput))
914
- return failure([...contextIssues, issue("acceptance_context_object_required", "context")]);
915
- const lock = lockResult.value.lock;
916
- const active = lock.status === "ACTIVE";
917
- if (operation === "VALIDATE") {
918
- if (!hasOnlyKeys(contextInput, []))
919
- contextIssues.push(issue("acceptance_validate_context_must_be_empty", "context"));
920
- if (contextIssues.length > 0)
921
- return failure(contextIssues);
922
- return success({
923
- operation,
924
- accepted: active,
925
- bindingMatches: active,
926
- invalidated: !active,
927
- blockers: active ? [] : ["acceptance_lock_invalidated"],
928
- lock,
929
- lockDigest: lockResult.value.lockDigest,
930
- }, lockResult.value.lockDigest);
931
- }
932
- if (operation === "EVALUATE") {
933
- if (!hasOnlyKeys(contextInput, ["artifactDigest", "sceneId", "timeRange"])) {
934
- contextIssues.push(issue("acceptance_evaluate_unknown_field", "context"));
935
- }
936
- if (!isSha256(contextInput.artifactDigest))
937
- contextIssues.push(issue("acceptance_context_artifact_invalid", "context"));
938
- if (!isSemanticId(contextInput.sceneId))
939
- contextIssues.push(issue("acceptance_context_scene_invalid", "context"));
940
- validateTimeRange(contextInput.timeRange, "context", contextIssues);
941
- if (contextIssues.length > 0)
942
- return failure(contextIssues);
943
- const bindingMatches = lock.artifactDigest === contextInput.artifactDigest
944
- && lock.sceneId === contextInput.sceneId
945
- && canonicalJson(lock.timeRange) === canonicalJson(contextInput.timeRange);
946
- const blockers = [
947
- ...(active ? [] : ["acceptance_lock_invalidated"]),
948
- ...(bindingMatches ? [] : ["acceptance_binding_mismatch"]),
949
- ];
950
- return success({
951
- operation,
952
- accepted: active && bindingMatches,
953
- bindingMatches,
954
- invalidated: !active,
955
- blockers,
956
- lock,
957
- lockDigest: lockResult.value.lockDigest,
958
- }, lockResult.value.lockDigest);
959
- }
960
- if (!hasOnlyKeys(contextInput, ["lockDigest", "invalidatedByDigest", "reasonCode", "invalidatedAt"])) {
961
- contextIssues.push(issue("acceptance_invalidate_unknown_field", "context"));
962
- }
963
- if (!isSha256(contextInput.lockDigest) || contextInput.lockDigest !== lockResult.value.lockDigest) {
964
- contextIssues.push(issue("acceptance_lock_digest_mismatch", "context"));
965
- }
966
- if (!isSha256(contextInput.invalidatedByDigest))
967
- contextIssues.push(issue("acceptance_invalidator_invalid", "context"));
968
- if (typeof contextInput.reasonCode !== "string"
969
- || !ACCEPTANCE_REASONS.has(contextInput.reasonCode)) {
970
- contextIssues.push(issue("acceptance_invalidation_reason_invalid", "context"));
971
- }
972
- if (!isIsoTimestamp(contextInput.invalidatedAt))
973
- contextIssues.push(issue("acceptance_invalidated_at_invalid", "context"));
974
- if (!active)
975
- contextIssues.push(issue("acceptance_lock_already_invalidated", "acceptanceLock"));
976
- if (contextIssues.length > 0)
977
- return failure(contextIssues);
978
- const invalidatedLock = {
979
- ...lock,
980
- status: "INVALIDATED",
981
- invalidation: {
982
- previousLockDigest: lockResult.value.lockDigest,
983
- invalidatedByDigest: contextInput.invalidatedByDigest,
984
- reasonCode: contextInput.reasonCode,
985
- invalidatedAt: contextInput.invalidatedAt,
986
- },
987
- };
988
- const lockDigest = digestJsonOperacional(invalidatedLock);
989
- return success({
990
- operation,
991
- accepted: false,
992
- bindingMatches: true,
993
- invalidated: true,
994
- blockers: ["acceptance_lock_invalidated"],
995
- lock: invalidatedLock,
996
- lockDigest,
997
- }, lockDigest);
998
- }
999
- const MULTIMODAL_CHANNEL_TYPES = new Set([
1000
- "SCREENSHOT", "VIDEO", "DEPTH", "NORMALS", "OBJECT_ID",
1001
- "MOTION", "TRANSFORMS", "EVENTS", "AUDIO", "TELEMETRY",
1002
- ]);
1003
- export function digestVinculoClaimMultimodal(input) {
1004
- return digestJsonOperacional({ ...input, requiredModalities: [...input.requiredModalities].sort() });
1005
- }
1006
- export function validarEvidenciaMultimodal(input) {
1007
- const issues = inspectPlainJson(input, "evidence");
1008
- if (!isRecord(input))
1009
- return failure([...issues, issue("evidence_object_required", "evidence")]);
1010
- if (!hasOnlyKeys(input, [
1011
- "schemaVersion", "evidenceId", "runId", "claimId", "definitionDigest", "planDigest", "contractDigest",
1012
- "claimBindingDigest", "artifactDigest", "sceneId", "timeRange", "requiredModalities", "channels",
1013
- "producer", "verifier", "decision", "observedAt", "authoritative",
1014
- ]))
1015
- issues.push(issue("evidence_unknown_field", "evidence"));
1016
- if (input.schemaVersion !== MULTIMODAL_EVIDENCE_SCHEMA_V1)
1017
- issues.push(issue("evidence_schema_invalid", "schemaVersion"));
1018
- if (!isSemanticId(input.evidenceId))
1019
- issues.push(issue("evidence_id_invalid", "evidenceId"));
1020
- if (!isSemanticId(input.runId))
1021
- issues.push(issue("evidence_run_id_invalid", "runId"));
1022
- if (!isSemanticId(input.claimId))
1023
- issues.push(issue("evidence_claim_id_invalid", "claimId"));
1024
- if (!isSha256(input.definitionDigest))
1025
- issues.push(issue("evidence_definition_digest_invalid", "definitionDigest"));
1026
- if (!isSha256(input.planDigest))
1027
- issues.push(issue("evidence_plan_digest_invalid", "planDigest"));
1028
- if (!isSha256(input.contractDigest))
1029
- issues.push(issue("evidence_contract_digest_invalid", "contractDigest"));
1030
- if (!isSha256(input.artifactDigest))
1031
- issues.push(issue("evidence_artifact_digest_invalid", "artifactDigest"));
1032
- if (!isSemanticId(input.sceneId))
1033
- issues.push(issue("evidence_scene_id_invalid", "sceneId"));
1034
- const timeRange = input.timeRange;
1035
- const timeRangeValid = validateTimeRange(timeRange, "timeRange", issues);
1036
- const requiredModalitiesInput = input.requiredModalities;
1037
- const requiredModalitiesValid = Array.isArray(requiredModalitiesInput)
1038
- && requiredModalitiesInput.length > 0
1039
- && requiredModalitiesInput.every((type) => typeof type === "string"
1040
- && MULTIMODAL_CHANNEL_TYPES.has(type))
1041
- && new Set(requiredModalitiesInput).size === requiredModalitiesInput.length;
1042
- const requiredModalities = requiredModalitiesValid
1043
- ? requiredModalitiesInput
1044
- : [];
1045
- if (!requiredModalitiesValid)
1046
- issues.push(issue("evidence_required_modalities_invalid", "requiredModalities"));
1047
- if (!isSha256(input.claimBindingDigest)
1048
- || !isSemanticId(input.claimId)
1049
- || !isSemanticId(input.runId)
1050
- || !isSha256(input.definitionDigest)
1051
- || !isSha256(input.planDigest)
1052
- || !isSha256(input.contractDigest)
1053
- || !isSha256(input.artifactDigest)
1054
- || !isSemanticId(input.sceneId)
1055
- || !timeRangeValid
1056
- || input.claimBindingDigest !== digestVinculoClaimMultimodal({
1057
- claimId: input.claimId,
1058
- runId: input.runId,
1059
- definitionDigest: input.definitionDigest,
1060
- planDigest: input.planDigest,
1061
- contractDigest: input.contractDigest,
1062
- artifactDigest: input.artifactDigest,
1063
- sceneId: input.sceneId,
1064
- timeRange,
1065
- requiredModalities,
1066
- }))
1067
- issues.push(issue("evidence_claim_binding_invalid", "claimBindingDigest"));
1068
- if (!isIsoTimestamp(input.observedAt))
1069
- issues.push(issue("evidence_observed_at_invalid", "observedAt"));
1070
- if (input.authoritative !== false)
1071
- issues.push(issue("evidence_must_be_non_authoritative", "authoritative"));
1072
- const channelIds = new Set();
1073
- const channelTypes = new Set();
1074
- if (!Array.isArray(input.channels) || input.channels.length === 0) {
1075
- issues.push(issue("evidence_channels_required", "channels"));
1076
- }
1077
- else
1078
- for (const channel of input.channels) {
1079
- if (!isRecord(channel)
1080
- || !hasOnlyKeys(channel, [
1081
- "channelId", "type", "artifactDigest", "mediaType", "metadataDigest", "sampleCount",
1082
- ])
1083
- || !isSemanticId(channel.channelId)
1084
- || typeof channel.type !== "string"
1085
- || !MULTIMODAL_CHANNEL_TYPES.has(channel.type)
1086
- || !isSha256(channel.artifactDigest)
1087
- || typeof channel.mediaType !== "string"
1088
- || !MEDIA_TYPE_PATTERN.test(channel.mediaType)
1089
- || !isSha256(channel.metadataDigest)
1090
- || !isIntegerIn(channel.sampleCount, 1, 1_000_000_000)) {
1091
- issues.push(issue("evidence_channel_invalid", "channels"));
1092
- continue;
1093
- }
1094
- if (channelIds.has(channel.channelId))
1095
- issues.push(issue("evidence_channel_id_duplicate", "channels"));
1096
- if (channelTypes.has(channel.type))
1097
- issues.push(issue("evidence_channel_type_duplicate", "channels"));
1098
- channelIds.add(channel.channelId);
1099
- channelTypes.add(channel.type);
1100
- }
1101
- const producer = input.producer;
1102
- if (!isRecord(producer)
1103
- || !hasOnlyKeys(producer, ["producerIdDigest", "producerType", "version", "configurationDigest"])
1104
- || !isSha256(producer.producerIdDigest)
1105
- || (producer.producerType !== "ENGINE"
1106
- && producer.producerType !== "EDITOR"
1107
- && producer.producerType !== "RUNNER"
1108
- && producer.producerType !== "MODEL"
1109
- && producer.producerType !== "HUMAN"
1110
- && producer.producerType !== "SENSOR")
1111
- || !isVersion(producer.version)
1112
- || !isSha256(producer.configurationDigest))
1113
- issues.push(issue("evidence_producer_invalid", "producer"));
1114
- const verifier = input.verifier;
1115
- if (!isRecord(verifier)
1116
- || !hasOnlyKeys(verifier, [
1117
- "verifierIdDigest", "verifierType", "version", "independent", "configurationDigest",
1118
- ])
1119
- || !isSha256(verifier.verifierIdDigest)
1120
- || (verifier.verifierType !== "RULE"
1121
- && verifier.verifierType !== "MODEL"
1122
- && verifier.verifierType !== "HUMAN"
1123
- && verifier.verifierType !== "SENSOR")
1124
- || !isVersion(verifier.version)
1125
- || verifier.independent !== true
1126
- || !isSha256(verifier.configurationDigest))
1127
- issues.push(issue("evidence_verifier_invalid", "verifier"));
1128
- if (isRecord(producer) && isRecord(verifier)
1129
- && isSha256(producer.producerIdDigest) && isSha256(verifier.verifierIdDigest)
1130
- && producer.producerIdDigest === verifier.verifierIdDigest) {
1131
- issues.push(issue("evidence_verifier_not_independent", "verifier"));
1132
- }
1133
- const decision = input.decision;
1134
- if (!isRecord(decision)
1135
- || !hasOnlyKeys(decision, ["verdict", "reasonCodes", "confidenceBasisPoints"])
1136
- || (decision.verdict !== "PASS" && decision.verdict !== "FAIL" && decision.verdict !== "INCONCLUSIVE")
1137
- || !Array.isArray(decision.reasonCodes)
1138
- || decision.reasonCodes.length === 0
1139
- || decision.reasonCodes.some((code) => !isSafeName(code))
1140
- || new Set(decision.reasonCodes).size !== decision.reasonCodes.length
1141
- || !isIntegerIn(decision.confidenceBasisPoints, 0, 10_000))
1142
- issues.push(issue("evidence_decision_invalid", "decision"));
1143
- if (isRecord(decision) && decision.verdict === "PASS") {
1144
- if (!requiredModalitiesValid || requiredModalities.length < 2) {
1145
- issues.push(issue("evidence_pass_requires_multiple_modalities", "requiredModalities"));
1146
- }
1147
- else if (!requiredModalities.every((type) => channelTypes.has(type))) {
1148
- issues.push(issue("evidence_pass_missing_required_modality", "channels"));
1149
- }
1150
- }
1151
- if (issues.length > 0)
1152
- return failure(issues);
1153
- const descriptor = input;
1154
- const normalized = {
1155
- ...descriptor,
1156
- timeRange: { ...descriptor.timeRange },
1157
- requiredModalities: [...descriptor.requiredModalities].sort(),
1158
- channels: descriptor.channels.map((channel) => ({ ...channel }))
1159
- .sort((left, right) => left.type.localeCompare(right.type) || left.channelId.localeCompare(right.channelId)),
1160
- producer: { ...descriptor.producer },
1161
- verifier: { ...descriptor.verifier },
1162
- decision: { ...descriptor.decision, reasonCodes: [...descriptor.decision.reasonCodes].sort() },
1163
- };
1164
- const descriptorDigest = digestJsonOperacional(normalized);
1165
- return success({ descriptor: normalized, descriptorDigest, localDescriptorOnly: true }, descriptorDigest);
1166
- }
1167
8
  //# sourceMappingURL=operations.js.map