@aifabrix/builder 2.42.1 → 2.44.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 (392) hide show
  1. package/.cursor/rules/anchor-docs.mdc +15 -0
  2. package/README.md +2 -2
  3. package/anchor-docs/README.md +10 -0
  4. package/anchor-docs/_TEMPLATE +24 -0
  5. package/bin/aifabrix.js +13 -4
  6. package/integration/hubspot-test/README.md +157 -0
  7. package/integration/{hubspot → hubspot-test}/application.json +6 -6
  8. package/integration/{hubspot → hubspot-test}/create-hubspot.js +10 -10
  9. package/integration/hubspot-test/env.template +4 -0
  10. package/integration/hubspot-test/hubspot-test-datasource-company.json +138 -0
  11. package/integration/hubspot-test/hubspot-test-datasource-contact.json +146 -0
  12. package/integration/hubspot-test/hubspot-test-datasource-deal.json +146 -0
  13. package/integration/hubspot-test/hubspot-test-datasource-users.json +76 -0
  14. package/integration/{hubspot/hubspot-deploy.json → hubspot-test/hubspot-test-deploy.json} +201 -24
  15. package/integration/{hubspot/hubspot-system.json → hubspot-test/hubspot-test-system.json} +8 -7
  16. package/integration/hubspot-test/rbac.json +166 -0
  17. package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-hubspot-credential-real.yaml +3 -3
  18. package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-hubspot-env-vars.yaml +2 -2
  19. package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-invalid-add-datasource.yaml +1 -1
  20. package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-invalid-credential-create.yaml +1 -1
  21. package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-invalid-credential-select.yaml +1 -1
  22. package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-invalid-known-platform.yaml +1 -1
  23. package/integration/hubspot-test/test-artifacts/wizard-invalid-missing-source.yaml +2 -0
  24. package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-invalid-mode.yaml +1 -1
  25. package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-invalid-openapi-file.yaml +1 -1
  26. package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-invalid-openapi-url.yaml +1 -1
  27. package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-invalid-source.yaml +1 -1
  28. package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-valid-for-dimension-array-test.yaml +1 -1
  29. package/integration/hubspot-test/test-artifacts/wizard-valid-for-dimension-key-test.yaml +5 -0
  30. package/integration/hubspot-test/test-artifacts/wizard-valid-for-dimension-path-test.yaml +5 -0
  31. package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-valid-for-dimension-test.yaml +1 -1
  32. package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-valid-for-rbac-test.yaml +1 -1
  33. package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-valid-for-rbac-yaml-test.yaml +1 -1
  34. package/integration/{hubspot → hubspot-test}/test-dataplane-down-tests.js +1 -7
  35. package/integration/{hubspot → hubspot-test}/test-dataplane-down.js +3 -3
  36. package/integration/{hubspot → hubspot-test}/test.js +137 -102
  37. package/integration/{hubspot → hubspot-test}/wizard-hubspot-e2e.yaml +2 -2
  38. package/integration/{hubspot → hubspot-test}/wizard-hubspot-platform.yaml +1 -1
  39. package/integration/hubspot-test/wizard-hubspot-test-headless.yaml +23 -0
  40. package/integration/roundtrip-test-local/README.md +144 -0
  41. package/integration/roundtrip-test-local/application.yaml +13 -0
  42. package/integration/roundtrip-test-local/env.template +15 -0
  43. package/integration/roundtrip-test-local/roundtrip-test-local-datasource-roundtrip-test-company.yaml +14 -0
  44. package/integration/roundtrip-test-local/roundtrip-test-local-deploy.json +61 -0
  45. package/integration/roundtrip-test-local/roundtrip-test-local-system.yaml +25 -0
  46. package/integration/roundtrip-test-local2/README.md +144 -0
  47. package/integration/roundtrip-test-local2/application.yaml +13 -0
  48. package/integration/roundtrip-test-local2/env.template +15 -0
  49. package/integration/roundtrip-test-local2/roundtrip-test-local2-datasource-company.yaml +31 -0
  50. package/integration/roundtrip-test-local2/roundtrip-test-local2-deploy.json +86 -0
  51. package/integration/roundtrip-test-local2/roundtrip-test-local2-system.yaml +25 -0
  52. package/integration/test/wizard.yaml +8 -0
  53. package/jest.config.default.js +10 -0
  54. package/jest.config.integration.fixtures.js +22 -0
  55. package/jest.config.integration.js +21 -18
  56. package/jest.config.isolated.js +10 -0
  57. package/jest.projects.js +288 -0
  58. package/lib/api/datasources-core.api.js +3 -3
  59. package/lib/api/dev-mtls-request.js +110 -0
  60. package/lib/api/dev-server-https.js +145 -0
  61. package/lib/api/dev.api.js +133 -144
  62. package/lib/api/index.js +0 -1
  63. package/lib/api/pipeline.api.js +67 -20
  64. package/lib/api/service-users.api.js +111 -2
  65. package/lib/api/types/dev.types.js +4 -3
  66. package/lib/api/types/pipeline.types.js +8 -5
  67. package/lib/api/types/service-users.types.js +41 -0
  68. package/lib/api/types/validation-run.types.js +56 -0
  69. package/lib/api/validation-run.api.js +99 -0
  70. package/lib/api/validation-runner.js +99 -0
  71. package/lib/app/config.js +1 -1
  72. package/lib/app/deploy-status-display.js +2 -2
  73. package/lib/app/deploy.js +7 -6
  74. package/lib/app/display.js +2 -1
  75. package/lib/app/dockerfile.js +3 -2
  76. package/lib/app/down.js +2 -1
  77. package/lib/app/helpers.js +6 -5
  78. package/lib/app/index.js +27 -8
  79. package/lib/app/list.js +7 -6
  80. package/lib/app/push.js +4 -3
  81. package/lib/app/register.js +19 -8
  82. package/lib/app/rotate-secret.js +17 -13
  83. package/lib/app/run-container-start.js +184 -0
  84. package/lib/app/run-docker-fallback.js +108 -0
  85. package/lib/app/run-env-compose.js +30 -42
  86. package/lib/app/run-helpers.js +49 -126
  87. package/lib/app/run-infra-requirements.js +30 -0
  88. package/lib/app/run-resolve-image.js +21 -0
  89. package/lib/app/run.js +74 -21
  90. package/lib/app/show-display.js +1 -1
  91. package/lib/app/show.js +1 -1
  92. package/lib/build/index.js +13 -10
  93. package/lib/cli/index.js +2 -0
  94. package/lib/cli/setup-app.help.js +67 -0
  95. package/lib/cli/setup-app.js +59 -123
  96. package/lib/cli/setup-app.test-commands.js +179 -0
  97. package/lib/cli/setup-auth.js +36 -14
  98. package/lib/cli/setup-credential-deployment.js +22 -8
  99. package/lib/cli/setup-dev-path-commands.js +124 -0
  100. package/lib/cli/setup-dev.js +190 -103
  101. package/lib/cli/setup-environment.js +11 -20
  102. package/lib/cli/setup-external-system.js +62 -22
  103. package/lib/cli/setup-infra.js +139 -47
  104. package/lib/cli/setup-parameters.js +32 -0
  105. package/lib/cli/setup-secrets.js +147 -10
  106. package/lib/cli/setup-service-user.js +146 -20
  107. package/lib/cli/setup-utility.js +47 -19
  108. package/lib/commands/app-down.js +5 -7
  109. package/lib/commands/app-install.js +14 -7
  110. package/lib/commands/app-logs.js +13 -10
  111. package/lib/commands/app-shell.js +4 -1
  112. package/lib/commands/app-test.js +25 -19
  113. package/lib/commands/app.js +22 -10
  114. package/lib/commands/auth-config.js +10 -14
  115. package/lib/commands/auth-status.js +4 -3
  116. package/lib/commands/credential-env.js +4 -3
  117. package/lib/commands/credential-list.js +5 -4
  118. package/lib/commands/credential-push.js +4 -3
  119. package/lib/commands/datasource-unified-test-cli.js +495 -0
  120. package/lib/commands/datasource-unified-test-cli.options.js +149 -0
  121. package/lib/commands/datasource-validation-cli.js +129 -0
  122. package/lib/commands/datasource.js +123 -71
  123. package/lib/commands/deployment-list.js +6 -5
  124. package/lib/commands/dev-cli-handlers.js +122 -18
  125. package/lib/commands/dev-down.js +4 -3
  126. package/lib/commands/dev-init.js +231 -116
  127. package/lib/commands/dev-show-display.js +473 -0
  128. package/lib/commands/login-credentials.js +3 -2
  129. package/lib/commands/login-device.js +4 -3
  130. package/lib/commands/login.js +5 -4
  131. package/lib/commands/logout.js +8 -7
  132. package/lib/commands/parameters-validate.js +54 -0
  133. package/lib/commands/repair-datasource.js +314 -68
  134. package/lib/commands/repair-env-template.js +16 -10
  135. package/lib/commands/repair-rbac.js +25 -19
  136. package/lib/commands/repair.js +116 -32
  137. package/lib/commands/secrets-list.js +23 -12
  138. package/lib/commands/secrets-remove-all.js +220 -0
  139. package/lib/commands/secrets-remove.js +22 -13
  140. package/lib/commands/secrets-set.js +21 -12
  141. package/lib/commands/secrets-validate.js +20 -7
  142. package/lib/commands/secure.js +10 -9
  143. package/lib/commands/service-user.js +243 -13
  144. package/lib/commands/test-e2e-external.js +27 -1
  145. package/lib/commands/up-common.js +28 -2
  146. package/lib/commands/up-dataplane.js +31 -18
  147. package/lib/commands/up-miso.js +19 -29
  148. package/lib/commands/upload.js +138 -39
  149. package/lib/commands/wizard-core-helpers.js +1 -1
  150. package/lib/commands/wizard-dataplane.js +4 -3
  151. package/lib/commands/wizard-helpers.js +3 -3
  152. package/lib/commands/wizard.js +2 -2
  153. package/lib/core/admin-secrets.js +16 -5
  154. package/lib/core/audit-logger.js +12 -4
  155. package/lib/core/config-attach-extensions.js +46 -0
  156. package/lib/core/config-runtime-paths.js +29 -0
  157. package/lib/core/config.js +59 -58
  158. package/lib/core/diff.js +3 -2
  159. package/lib/core/ensure-encryption-key.js +2 -4
  160. package/lib/core/secrets-ensure-infra.js +77 -0
  161. package/lib/core/secrets-ensure.js +120 -64
  162. package/lib/core/secrets-env-write.js +35 -7
  163. package/lib/core/secrets-infra-placeholder-sync.js +61 -0
  164. package/lib/core/secrets.js +228 -42
  165. package/lib/core/templates-env.js +4 -3
  166. package/lib/core/templates.js +1 -1
  167. package/lib/datasource/abac-validator.js +148 -0
  168. package/lib/datasource/deploy.js +75 -53
  169. package/lib/datasource/field-reference-validator.js +77 -36
  170. package/lib/datasource/integration-context.js +63 -0
  171. package/lib/datasource/list.js +8 -7
  172. package/lib/datasource/log-viewer.js +252 -0
  173. package/lib/datasource/resolve-app.js +109 -0
  174. package/lib/datasource/test-e2e.js +95 -155
  175. package/lib/datasource/test-integration.js +121 -109
  176. package/lib/datasource/unified-validation-run-body.js +65 -0
  177. package/lib/datasource/unified-validation-run-post.js +23 -0
  178. package/lib/datasource/unified-validation-run-resolve.js +43 -0
  179. package/lib/datasource/unified-validation-run.js +92 -0
  180. package/lib/datasource/validate.js +162 -15
  181. package/lib/deployment/deployer.js +4 -3
  182. package/lib/deployment/environment.js +7 -6
  183. package/lib/deployment/push.js +17 -8
  184. package/lib/external-system/delete.js +4 -3
  185. package/lib/external-system/deploy.js +131 -53
  186. package/lib/external-system/download-helpers.js +1 -1
  187. package/lib/external-system/download.js +7 -6
  188. package/lib/external-system/generator.js +104 -14
  189. package/lib/external-system/integration-test-dispatch.js +26 -0
  190. package/lib/external-system/test-execution.js +5 -1
  191. package/lib/external-system/test-helpers.js +0 -4
  192. package/lib/external-system/test-system-level-helpers.js +110 -0
  193. package/lib/external-system/test-system-level.js +83 -44
  194. package/lib/external-system/test.js +59 -8
  195. package/lib/generator/builders.js +23 -11
  196. package/lib/generator/deploy-manifest-azure-kv.js +81 -0
  197. package/lib/generator/external-controller-manifest.js +3 -3
  198. package/lib/generator/external.js +23 -11
  199. package/lib/generator/helpers.js +71 -12
  200. package/lib/generator/index.js +8 -4
  201. package/lib/generator/split-readme.js +12 -7
  202. package/lib/generator/split-variables.js +2 -1
  203. package/lib/generator/split.js +46 -11
  204. package/lib/generator/wizard-readme.js +3 -3
  205. package/lib/generator/wizard.js +16 -13
  206. package/lib/infrastructure/compose.js +60 -6
  207. package/lib/infrastructure/helpers.js +238 -51
  208. package/lib/infrastructure/index.js +64 -37
  209. package/lib/infrastructure/services.js +21 -15
  210. package/lib/internal/fs-real-sync.js +104 -0
  211. package/lib/internal/node-fs.js +98 -0
  212. package/lib/parameters/database-secret-values.js +173 -0
  213. package/lib/parameters/infra-kv-discovery.js +121 -0
  214. package/lib/parameters/infra-parameter-catalog.js +458 -0
  215. package/lib/parameters/infra-parameter-validate.js +64 -0
  216. package/lib/schema/application-schema.json +37 -17
  217. package/lib/schema/datasource-test-run.schema.json +493 -0
  218. package/lib/schema/deployment-rules.yaml +102 -63
  219. package/lib/schema/external-datasource.schema.json +1201 -433
  220. package/lib/schema/external-system.schema.json +181 -5
  221. package/lib/schema/flag-map-validation-run.json +31 -0
  222. package/lib/schema/infra-parameter.schema.json +106 -0
  223. package/lib/schema/infra.parameter.yaml +421 -0
  224. package/lib/schema/type/credential-auth-templates.json +40 -0
  225. package/lib/schema/type/document-storage.json +213 -0
  226. package/lib/schema/type/message-service.json +123 -0
  227. package/lib/schema/type/vector-store.json +88 -0
  228. package/lib/utils/aifabrix-runtime-config-dir.js +132 -0
  229. package/lib/utils/api-error-handler.js +2 -2
  230. package/lib/utils/api.js +49 -14
  231. package/lib/utils/app-config-resolver.js +23 -1
  232. package/lib/utils/app-register-api.js +3 -2
  233. package/lib/utils/app-register-auth.js +1 -1
  234. package/lib/utils/app-register-config.js +4 -4
  235. package/lib/utils/app-register-display.js +3 -2
  236. package/lib/utils/app-register-validator.js +3 -2
  237. package/lib/utils/app-run-containers.js +26 -22
  238. package/lib/utils/app-scoped-config.js +31 -0
  239. package/lib/utils/app-service-env-from-builder.js +164 -0
  240. package/lib/utils/build-copy.js +1 -1
  241. package/lib/utils/build-helpers.js +20 -20
  242. package/lib/utils/build-resolve-image.js +165 -0
  243. package/lib/utils/cli-layout-chalk.js +8 -0
  244. package/lib/utils/cli-test-layout-chalk.js +267 -0
  245. package/lib/utils/cli-utils.js +88 -11
  246. package/lib/utils/compose-db-passwords.js +138 -0
  247. package/lib/utils/compose-generate-docker-compose.js +216 -0
  248. package/lib/utils/compose-generator.js +197 -291
  249. package/lib/utils/compose-miso-env.js +18 -0
  250. package/lib/utils/compose-traefik-ingress-base.js +158 -0
  251. package/lib/utils/config-paths.js +209 -6
  252. package/lib/utils/config-scoped-resources-preference.js +41 -0
  253. package/lib/utils/controller-deployment-outcome.js +68 -0
  254. package/lib/utils/credential-display.js +2 -2
  255. package/lib/utils/credential-secrets-env.js +16 -1
  256. package/lib/utils/dataplane-pipeline-warning.js +4 -3
  257. package/lib/utils/datasource-test-run-capability-scope.js +43 -0
  258. package/lib/utils/datasource-test-run-debug-display.js +137 -0
  259. package/lib/utils/datasource-test-run-debug-slice.js +93 -0
  260. package/lib/utils/datasource-test-run-display.js +442 -0
  261. package/lib/utils/datasource-test-run-exit.js +58 -0
  262. package/lib/utils/datasource-test-run-legacy-adapter.js +93 -0
  263. package/lib/utils/datasource-test-run-report-version.js +51 -0
  264. package/lib/utils/datasource-test-run-schema-sync.js +59 -0
  265. package/lib/utils/datasource-test-run-tty-log.js +81 -0
  266. package/lib/utils/datasource-validation-watch.js +266 -0
  267. package/lib/utils/declarative-url-ports.js +47 -0
  268. package/lib/utils/derive-env-key-from-client-id.js +41 -0
  269. package/lib/utils/dev-ca-install.js +185 -23
  270. package/lib/utils/dev-cert-helper.js +266 -17
  271. package/lib/utils/dev-hosts-helper.js +307 -0
  272. package/lib/utils/dev-init-cert-hints.js +37 -0
  273. package/lib/utils/dev-init-health-messages.js +52 -0
  274. package/lib/utils/dev-init-resolve.js +86 -0
  275. package/lib/utils/dev-init-ssh-merge.js +65 -0
  276. package/lib/utils/dev-ssh-config-helper.js +196 -0
  277. package/lib/utils/dev-user-groups.js +93 -0
  278. package/lib/utils/docker-build.js +42 -17
  279. package/lib/utils/docker-exec.js +28 -0
  280. package/lib/utils/docker-manifest-public-port.js +116 -0
  281. package/lib/utils/docker-not-running-hint.js +52 -0
  282. package/lib/utils/docker.js +98 -11
  283. package/lib/utils/ensure-dev-certs-for-remote-docker.js +192 -0
  284. package/lib/utils/env-config-loader.js +10 -91
  285. package/lib/utils/env-copy.js +19 -10
  286. package/lib/utils/env-map.js +42 -11
  287. package/lib/utils/env-template.js +2 -2
  288. package/lib/utils/environment-scoped-resources.js +144 -0
  289. package/lib/utils/error-formatter.js +125 -9
  290. package/lib/utils/error-formatters/http-status-errors.js +6 -5
  291. package/lib/utils/error-formatters/network-errors.js +2 -1
  292. package/lib/utils/error-formatters/permission-errors.js +2 -1
  293. package/lib/utils/error-formatters/validation-errors.js +2 -1
  294. package/lib/utils/external-env-template.js +180 -0
  295. package/lib/utils/external-readme.js +8 -1
  296. package/lib/utils/external-system-display.js +277 -136
  297. package/lib/utils/external-system-local-test-tty.js +389 -0
  298. package/lib/utils/external-system-readiness-core.js +377 -0
  299. package/lib/utils/external-system-readiness-deploy-display.js +270 -0
  300. package/lib/utils/external-system-readiness-display-internals.js +150 -0
  301. package/lib/utils/external-system-readiness-display.js +186 -0
  302. package/lib/utils/external-system-test-helpers.js +24 -6
  303. package/lib/utils/external-system-validators.js +32 -14
  304. package/lib/utils/health-check-url.js +119 -0
  305. package/lib/utils/health-check.js +59 -25
  306. package/lib/utils/help-builder.js +14 -13
  307. package/lib/utils/image-version.js +4 -8
  308. package/lib/utils/infra-containers.js +4 -7
  309. package/lib/utils/infra-env-defaults.js +162 -0
  310. package/lib/utils/infra-status-display.js +167 -0
  311. package/lib/utils/infra-status.js +16 -8
  312. package/lib/utils/local-secrets.js +29 -7
  313. package/lib/utils/paths.js +136 -48
  314. package/lib/utils/port-resolver.js +10 -23
  315. package/lib/utils/redis-env-scope.js +62 -0
  316. package/lib/utils/register-aifabrix-shell-env.js +204 -0
  317. package/lib/utils/remote-builder-validation.js +99 -0
  318. package/lib/utils/remote-dev-auth.js +117 -21
  319. package/lib/utils/remote-docker-env.js +67 -15
  320. package/lib/utils/remote-secrets-loader.js +13 -4
  321. package/lib/utils/resolve-docker-image-ref.js +124 -0
  322. package/lib/utils/schema-loader.js +22 -9
  323. package/lib/utils/secrets-bash-kv.js +25 -0
  324. package/lib/utils/secrets-generator.js +171 -51
  325. package/lib/utils/secrets-helpers.js +70 -59
  326. package/lib/utils/secrets-kv-scope.js +60 -0
  327. package/lib/utils/secrets-utils.js +35 -37
  328. package/lib/utils/secrets-validation.js +3 -1
  329. package/lib/utils/secrets-yaml-preserve.js +109 -0
  330. package/lib/utils/secure-file-permissions.js +91 -0
  331. package/lib/utils/ssh-key-helper.js +4 -2
  332. package/lib/utils/template-helpers.js +2 -2
  333. package/lib/utils/test-log-writer.js +3 -3
  334. package/lib/utils/token-manager.js +37 -5
  335. package/lib/utils/url-declarative-public-base.js +188 -0
  336. package/lib/utils/url-declarative-resolve-build.js +493 -0
  337. package/lib/utils/url-declarative-resolve-load-doc.js +51 -0
  338. package/lib/utils/url-declarative-resolve.js +220 -0
  339. package/lib/utils/url-declarative-token-parse.js +74 -0
  340. package/lib/utils/url-declarative-url-flags.js +50 -0
  341. package/lib/utils/url-declarative-vdir-inactive-env.js +99 -0
  342. package/lib/utils/url-public-path-prefix.js +34 -0
  343. package/lib/utils/urls-local-registry.js +220 -0
  344. package/lib/utils/validation-report-tty-kit.js +77 -0
  345. package/lib/utils/validation-run-poll.js +89 -0
  346. package/lib/utils/validation-run-post-retry.js +73 -0
  347. package/lib/utils/validation-run-request.js +98 -0
  348. package/lib/utils/variable-transformer.js +21 -4
  349. package/lib/utils/yaml-preserve.js +78 -1
  350. package/lib/validation/datasource-warnings.js +56 -0
  351. package/lib/validation/env-template-auth.js +50 -2
  352. package/lib/validation/external-manifest-validator.js +35 -7
  353. package/lib/validation/validate-display.js +37 -31
  354. package/lib/validation/validate.js +9 -10
  355. package/lib/validation/validator-unresolved-placeholders.js +98 -0
  356. package/lib/validation/validator.js +32 -78
  357. package/lib/validation/wizard-config-validator.js +2 -1
  358. package/package.json +11 -3
  359. package/scripts/check-datasource-test-run-schema-sync.js +34 -0
  360. package/scripts/diagnose-cli.js +150 -0
  361. package/scripts/install-local.js +304 -55
  362. package/templates/README.md +15 -2
  363. package/templates/applications/dataplane/application.yaml +52 -2
  364. package/templates/applications/dataplane/env.template +80 -18
  365. package/templates/applications/dataplane/rbac.yaml +8 -0
  366. package/templates/applications/keycloak/application.yaml +9 -1
  367. package/templates/applications/keycloak/env.template +15 -6
  368. package/templates/applications/miso-controller/application.yaml +10 -2
  369. package/templates/applications/miso-controller/env.template +55 -14
  370. package/templates/applications/miso-controller/rbac.yaml +5 -0
  371. package/templates/external-system/README.md.hbs +20 -7
  372. package/templates/external-system/deploy.js.hbs +5 -5
  373. package/templates/external-system/env.template.hbs +22 -0
  374. package/templates/external-system/external-datasource.yaml.hbs +197 -118
  375. package/templates/infra/compose.yaml.hbs +20 -4
  376. package/templates/python/docker-compose.hbs +16 -0
  377. package/templates/typescript/docker-compose.hbs +16 -0
  378. package/integration/hubspot/README.md +0 -102
  379. package/integration/hubspot/env.template +0 -4
  380. package/integration/hubspot/hubspot-datasource-company.json +0 -541
  381. package/integration/hubspot/hubspot-datasource-contact.json +0 -639
  382. package/integration/hubspot/hubspot-datasource-deal.json +0 -588
  383. package/integration/hubspot/hubspot-datasource-users.json +0 -116
  384. package/integration/hubspot/test-artifacts/wizard-invalid-missing-source.yaml +0 -2
  385. package/integration/hubspot/test-artifacts/wizard-valid-for-dimension-key-test.yaml +0 -5
  386. package/integration/hubspot/test-artifacts/wizard-valid-for-dimension-path-test.yaml +0 -5
  387. package/lib/api/external-test.api.js +0 -111
  388. package/lib/schema/env-config.yaml +0 -43
  389. /package/integration/{hubspot → hubspot-test}/companies.json +0 -0
  390. /package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-invalid-app-name.yaml +0 -0
  391. /package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-invalid-missing-app.yaml +0 -0
  392. /package/integration/{hubspot → hubspot-test}/test-dataplane-down-helpers.js +0 -0
@@ -1,18 +1,18 @@
1
1
  {
2
2
  "$schema":"https://json-schema.org/draft/2020-12/schema",
3
- "$id":"https://raw.githubusercontent.com/esystemsdev/aifabrix-builder/refs/heads/main/lib/schema/external-datasource.schema.json",
3
+ "$id":"aifabrix://schema/external-datasource.schema.json",
4
4
  "title":"External Data Source",
5
5
  "description":"Configuration for AI Fabrix ExternalDataSource entities. Includes metadata schema, data dimensions, transformation mappings, OpenAPI/MCP exposure, execution logic, and sync behavior.",
6
6
  "metadata":{
7
7
  "key":"external-datasource-schema",
8
8
  "name":"External Data Source Configuration Schema",
9
9
  "description":"JSON schema for validating ExternalDataSource configuration files",
10
- "version":"2.3.0",
10
+ "version":"2.4.5",
11
11
  "type":"schema",
12
12
  "category":"integration",
13
13
  "author":"AI Fabrix Team",
14
14
  "createdAt":"2024-01-01T00:00:00Z",
15
- "updatedAt":"2026-01-19T00:00:00Z",
15
+ "updatedAt":"2026-04-07T00:00:00Z",
16
16
  "compatibility":{
17
17
  "minVersion":"1.0.0",
18
18
  "maxVersion":"3.0.0",
@@ -96,7 +96,7 @@
96
96
  "version":"2.2.0",
97
97
  "date":"2026-02-26T00:00:00Z",
98
98
  "changes":[
99
- "capabilities: preferred format is array [\"list\",\"get\",...]. Schema oneOf accepts both array and legacy object; runtime accepts both for backward compatibility."
99
+ "capabilities: preferred format is array [\"list\",\"get\",...]."
100
100
  ],
101
101
  "breaking":false
102
102
  },
@@ -107,6 +107,74 @@
107
107
  "BREAKING: Added required primaryKey (array of normalized attribute names). Used for get/update/delete and table indexing. Migration: add primaryKey array (e.g. [\"id\"] or [\"externalId\"]) to each datasource config."
108
108
  ],
109
109
  "breaking":true
110
+ },
111
+ {
112
+ "version":"2.4.0",
113
+ "date":"2026-03-24T00:00:00Z",
114
+ "changes":[
115
+ "BREAKING: Consolidated freeze baseline into 2.4.0 on feature branch before merge.",
116
+ "BREAKING: Removed metadataSchema.foreignKey, top-level references, and relationContract.",
117
+ "BREAKING: Removed fieldMappings.dimensions and datasource config.abac* contract surfaces.",
118
+ "BREAKING: Added root contract gate for entityType='none' (orchestration/chaining only).",
119
+ "BREAKING: Removed indexing section from datasource root; index/filter are metadataSchema-driven.",
120
+ "BREAKING: Simplified fieldMappings.attributes to expression-only normalization contract.",
121
+ "Updated expression contract to strict roots: raw.*, fk.*, dimension.* with FK traversal support.",
122
+ "Added top-level dimensions and strict foreignKeys[] contract (required name/fields/targetDatasource).",
123
+ "Simplified sync contract to mode/schedule/batchSize.",
124
+ "Hardened metadataSchema index/filter scalar-only constraints.",
125
+ "Applied naming guardrails for metadata fields (camelCase) and FK names (camelCase).",
126
+ "Added datetime representation guidance: type=string + format=date-time with UTC/native DB timestamp mapping.",
127
+ "Allowed contract/config.extensions for entityType=none orchestration datasources.",
128
+ "Added actor/operator strict defaults in dimensionBinding (eq for displayName/email/userId, in for groups/roles)."
129
+ ],
130
+ "breaking":true
131
+ },
132
+ {
133
+ "version":"2.4.1",
134
+ "date":"2026-03-29T00:00:00Z",
135
+ "changes":[
136
+ "CIP execution.cip.operations allows custom operation keys matching the same pattern as capabilities[].",
137
+ "recordStorage/documentStorage: dimensions are no longer JSON Schema-required; validator warns when missing or empty.",
138
+ "dimensionBinding type=fk: via remains required; actor is optional (warn when omitted).",
139
+ "dimensions object may be empty at schema level; recommend ≥1 binding via application validation warning.",
140
+ "testPayload: unknown top-level keys rejected by application validator (strict contract beyond JSON Schema).",
141
+ "cipStepFetch: fetch.openapiRef and fetch.operation (source=datasource) use the same naming pattern as capabilities[] and execution.cip.operations keys (^[a-z][a-zA-Z0-9]*$), not a fixed CRUD enum. Standard names list/get/create/update/delete remain valid; custom keys must match openapi.operations.<name> or the target datasource CIP operation."
142
+ ],
143
+ "breaking":false
144
+ },
145
+ {
146
+ "version":"2.4.2",
147
+ "date":"2026-03-31T00:00:00Z",
148
+ "changes":[
149
+ "recordStorage/documentStorage: metadataSchema.properties.externalId required (type=string, index=true) as global join identity (346.rules §10.1; plans SC-025/SC-029).",
150
+ "foreignKeys.targetFields: when omitted, resolution defaults to target externalId (not primaryKey); composite primaryKey must not be used as explicit cross-datasource join key (SC-026/SC-028).",
151
+ "Application validator enforces externalId field mapping and FK join semantics in lockstep with JSON Schema."
152
+ ],
153
+ "breaking":true
154
+ },
155
+ {
156
+ "version":"2.4.3",
157
+ "date":"2026-04-04T00:00:00Z",
158
+ "changes":[
159
+ "BREAKING: Removed CIP filter.enforceAbac from cipStepFilter.filter (WP-H / 346.13 matrix 18). Use filter.abac.mode (mandatory | optional | disabled) instead."
160
+ ],
161
+ "breaking":true
162
+ },
163
+ {
164
+ "version":"2.4.4",
165
+ "date":"2026-04-06T00:00:00Z",
166
+ "changes":[
167
+ "Added optional root mcpContract object for embedded MCP securityModel (tools/abac policy buckets). Required for integration manifests when CIP filter.abac uses mandatory datasource-scoped policies (static readiness vs runtime ExternalDataSource.mcpContract)."
168
+ ],
169
+ "breaking":false
170
+ },
171
+ {
172
+ "version":"2.4.5",
173
+ "date":"2026-04-07T00:00:00Z",
174
+ "changes":[
175
+ "exposed.profiles object profiles: attributes may be an object map (property names = field keys; values ignored), matching runtime exposed_profile_field_names and CIP/ExposedFieldsValidator behavior."
176
+ ],
177
+ "breaking":false
110
178
  }
111
179
  ]
112
180
  },
@@ -116,9 +184,7 @@
116
184
  "displayName",
117
185
  "systemKey",
118
186
  "entityType",
119
- "resourceType",
120
- "fieldMappings",
121
- "primaryKey"
187
+ "resourceType"
122
188
  ],
123
189
  "properties":{
124
190
  "key":{
@@ -145,8 +211,8 @@
145
211
  },
146
212
  "entityType":{
147
213
  "type":"string",
148
- "enum":["document-storage","documentStorage","vector-store","vectorStore","record-storage","recordStorage","message-service","messageService","none"],
149
- "description":"Entity type identifier. Defines storage semantics and behavior: 'document-storage' or 'documentStorage' (creates document storage service with vector-storage), 'vector-store' or 'vectorStore' (external vector storage system), 'record-storage' or 'recordStorage' (creates record-based system with metadata sync and access rights), 'message-service' or 'messageService' (message service for notifications - Slack, Teams, Email), 'none' (uses external system data directly or connects other data sources). Required field. Supports both camelCase and kebab-case formats for backward compatibility."
214
+ "enum":["documentStorage","vectorStore","recordStorage","messageService","none"],
215
+ "description":"Entity type identifier. Defines storage semantics and behavior: 'documentStorage' (creates document storage service with vector-storage), 'vectorStore' (external vector storage system), 'recordStorage' (creates record-based system with metadata sync and access rights), 'messageService' (message service for notifications - Slack, Teams, Email), 'none' (uses external system data directly or connects other data sources). Required field. Canonical values are camelCase."
150
216
  },
151
217
  "resourceType":{
152
218
  "type":"string",
@@ -160,75 +226,72 @@
160
226
  "default":"1.0.0"
161
227
  },
162
228
  "metadataSchema":{
163
- "type":"object",
164
- "description":"Subset of JSON Schema used to validate raw input metadata.",
165
- "additionalProperties":true
229
+ "$ref":"#/$defs/metadataSchemaNode"
166
230
  },
167
231
  "primaryKey":{
168
232
  "type":"array",
169
- "description":"Normalized field names that uniquely identify a record (used for get/update/delete and table indexing). Each element must exist in fieldMappings.dimensions or fieldMappings.attributes.",
233
+ "description":"Normalized field names that uniquely identify a record (used for get/update/delete and table indexing). Each element must exist in metadataSchema and be index=true.",
170
234
  "minItems":1,
171
235
  "items":{
172
236
  "type":"string",
173
- "pattern":"^[a-zA-Z0-9_]+$"
237
+ "pattern":"^[a-z][a-zA-Z0-9]*$"
238
+ },
239
+ "uniqueItems":true
240
+ },
241
+ "labelKey":{
242
+ "type":"array",
243
+ "description":"Normalized field names used for display and dimension labels. Each element must exist in metadataSchema and be scalar with index=true or filter=true.",
244
+ "minItems":1,
245
+ "items":{
246
+ "type":"string",
247
+ "pattern":"^[a-z][a-zA-Z0-9]*$"
174
248
  },
175
249
  "uniqueItems":true
176
250
  },
251
+ "foreignKeys":{
252
+ "type":"array",
253
+ "description":"Foreign key definitions referencing other datasources. Defines relational integrity and join capability.",
254
+ "items":{
255
+ "$ref":"#/$defs/foreignKeyDefinition"
256
+ },
257
+ "uniqueItems":true
258
+ },
259
+ "dimensions":{
260
+ "type":"object",
261
+ "description":"Canonical dimension bindings for this datasource. Keys must exist in Dimension Catalog when catalog validation runs. For recordStorage/documentStorage, at least one binding is recommended (application validator may warn if missing or empty).",
262
+ "propertyNames":{
263
+ "pattern":"^[a-zA-Z0-9_]+$"
264
+ },
265
+ "additionalProperties":{
266
+ "$ref":"#/$defs/dimensionBinding"
267
+ }
268
+ },
177
269
  "fieldMappings":{
178
270
  "type":"object",
179
- "description":"Transformation rules and data dimensions. Maps canonical dimensions to system attributes.",
271
+ "description":"Normalization rules only (raw/fk traversal to normalized attributes). For storage datasources, attribute keys must correspond to metadataSchema fields (builder/runtime validation).",
180
272
  "required":[
181
- "dimensions",
182
273
  "attributes"
183
274
  ],
184
275
  "properties":{
185
- "dimensions":{
186
- "type":"object",
187
- "description":"Data dimensions mapping. Key = dimension key (from Dimension Catalog), Value = attribute path (e.g., 'metadata.department').",
188
- "additionalProperties":{
189
- "type":"string",
190
- "pattern":"^[a-zA-Z0-9_.]+$"
191
- },
192
- "minProperties":0
193
- },
194
276
  "attributes":{
195
277
  "type":"object",
196
- "description":"Key = normalized attribute name. Value = transformation expression + type.",
278
+ "description":"Key = normalized attribute name. Value = transformation configuration.",
279
+ "propertyNames":{
280
+ "pattern":"^[a-z][a-zA-Z0-9]*$"
281
+ },
197
282
  "additionalProperties":{
198
283
  "type":"object",
199
- "required":[
200
- "expression",
201
- "type"
202
- ],
203
284
  "properties":{
204
285
  "expression":{
205
286
  "type":"string",
206
- "description":"Pipe-based DSL expression: '{{raw.path}} | toLower | trim' or record reference: 'record_ref:customer'.",
207
- "pattern":"^\\s*((\\{\\{[^}]+\\}\\}(\\s*\\|\\s*[a-zA-Z0-9_]+(\\([^)]*\\))?)*)|(record_ref:[a-z0-9-]+))\\s*$"
208
- },
209
- "type":{
210
- "type":"string",
211
- "enum":[
212
- "string",
213
- "number",
214
- "integer",
215
- "boolean",
216
- "array",
217
- "object"
218
- ]
219
- },
220
- "indexed":{
221
- "type":"boolean",
222
- "default":false,
223
- "description":"If true, creates database index for fast search/filtering. Dimensions are automatically indexed."
287
+ "description":"Pipe-based DSL expression. Allowed roots: raw.<path>, fk.<fk>.metadata.<field>, fk.<fk>.dimension.<dimension>[.label], dimension.<dimension>[.label]. FK traversal in DSL is one-hop only.",
288
+ "maxLength":512,
289
+ "pattern":"^\\s*\\{\\{(raw\\.[a-zA-Z0-9_.]+|fk\\.[a-z][a-zA-Z0-9]*\\.metadata\\.[a-z][a-zA-Z0-9]*|fk\\.[a-z][a-zA-Z0-9]*\\.dimension\\.[a-zA-Z0-9_]+(\\.label)?|dimension\\.[a-zA-Z0-9_]+(\\.label)?)\\}\\}(\\s*\\|\\s*[a-zA-Z0-9_]+(\\([^)]*\\))?)*\\s*$"
224
290
  },
225
291
  "description":{
226
292
  "type":"string",
227
293
  "description":"Technical description of the normalized field."
228
294
  },
229
- "required":{
230
- "type":"boolean"
231
- },
232
295
  "semantic":{
233
296
  "type":"object",
234
297
  "description":"Semantic metadata for AI agents and schema generation.",
@@ -265,53 +328,61 @@
265
328
  "lineage":{
266
329
  "$ref":"#/$defs/fieldMappingLineage"
267
330
  }
268
- }
331
+ },
332
+ "required":[
333
+ "expression"
334
+ ],
335
+ "additionalProperties":false
269
336
  }
270
337
  }
271
- }
338
+ },
339
+ "additionalProperties":false
272
340
  },
273
341
  "exposed":{
274
342
  "type":"object",
275
- "description":"Defines which normalized fields are exposed through MCP/OpenAPI. Ensures ISO27001-safe output and predictable AI model behavior.",
343
+ "description":"Defines public API exposure contract. v2.4.0 freeze requires exposed.schema as canonical response shape.",
276
344
  "properties":{
277
- "attributes":{
345
+ "schema":{
346
+ "type":"object",
347
+ "description":"Canonical public response contract. Keys define output shape; values are expressions using metadata./fk./dimension paths.",
348
+ "minProperties":1,
349
+ "additionalProperties":{
350
+ "$ref":"#/$defs/exposedSchemaNode"
351
+ }
352
+ },
353
+ "omit":{
278
354
  "type":"array",
279
- "description":"List of normalized attributes (from fieldMappings.attributes keys) that the MCP/OpenAPI layers will return.",
355
+ "description":"Fields that exist in normalized metadata but must NEVER be exposed by MCP/OpenAPI (e.g., secrets, internal IDs). Overrides 'fields'.",
280
356
  "items":{
281
357
  "type":"string",
282
- "pattern":"^[a-zA-Z0-9_]+$"
358
+ "pattern":"^[a-z][a-zA-Z0-9]*$"
283
359
  },
284
- "minItems":1,
285
360
  "uniqueItems":true
286
361
  },
287
- "omit":{
362
+ "filterable":{
288
363
  "type":"array",
289
- "description":"Fields that exist in normalized metadata but must NEVER be exposed by MCP/OpenAPI (e.g., secrets, internal IDs). Overrides 'fields'.",
364
+ "description":"Fields that may be used as deterministic filters in exposed APIs. Must reference materialized fields (`index=true` or `filter=true`).",
290
365
  "items":{
291
366
  "type":"string",
292
- "pattern":"^[a-zA-Z0-9_]+$"
367
+ "pattern":"^[a-z][a-zA-Z0-9]*$"
293
368
  },
294
369
  "uniqueItems":true
295
370
  },
296
- "groups":{
297
- "type":"object",
298
- "description":"Optional logical grouping for OpenAPI/MCP schema generation (e.g., 'default', 'analytics', 'light').",
299
- "additionalProperties":{
300
- "type":"array",
301
- "items":{
302
- "type":"string",
303
- "pattern":"^[a-zA-Z0-9_]+$"
304
- },
305
- "minItems":1,
306
- "uniqueItems":true
307
- }
371
+ "required":{
372
+ "type":"array",
373
+ "description":"Fields that profile contracts require to be present.",
374
+ "items":{
375
+ "type":"string",
376
+ "pattern":"^[a-z][a-zA-Z0-9]*$"
377
+ },
378
+ "uniqueItems":true
308
379
  },
309
380
  "readonly":{
310
381
  "type":"array",
311
382
  "description":"Fields exposed via MCP/OpenAPI but cannot be modified via write operations.",
312
383
  "items":{
313
384
  "type":"string",
314
- "pattern":"^[a-zA-Z0-9_]+$"
385
+ "pattern":"^[a-z][a-zA-Z0-9]*$"
315
386
  },
316
387
  "uniqueItems":true
317
388
  },
@@ -321,20 +392,74 @@
321
392
  },
322
393
  "profiles":{
323
394
  "type":"object",
324
- "description":"Named exposure profiles mapping profile keys to lists of normalized field names. Useful for AI-light, AI-embedding, analytics, etc.",
395
+ "description":"Named exposure profiles mapping profile keys to deterministic field contracts.",
325
396
  "additionalProperties":{
326
- "type":"array",
327
- "items":{
328
- "type":"string",
329
- "pattern":"^[a-zA-Z0-9_]+$"
330
- },
331
- "minItems":1,
332
- "uniqueItems":true
397
+ "oneOf":[
398
+ {
399
+ "type":"array",
400
+ "items":{
401
+ "type":"string",
402
+ "pattern":"^[a-z][a-zA-Z0-9]*$"
403
+ },
404
+ "minItems":1,
405
+ "uniqueItems":true
406
+ },
407
+ {
408
+ "type":"object",
409
+ "properties":{
410
+ "attributes":{
411
+ "oneOf":[
412
+ {
413
+ "type":"array",
414
+ "items":{
415
+ "type":"string",
416
+ "pattern":"^[a-z][a-zA-Z0-9]*$"
417
+ },
418
+ "minItems":1,
419
+ "uniqueItems":true
420
+ },
421
+ {
422
+ "type":"object",
423
+ "minProperties":1,
424
+ "propertyNames":{
425
+ "pattern":"^[a-z][a-zA-Z0-9]*$"
426
+ },
427
+ "additionalProperties":true
428
+ }
429
+ ]
430
+ },
431
+ "required":{
432
+ "type":"array",
433
+ "items":{
434
+ "type":"string",
435
+ "pattern":"^[a-z][a-zA-Z0-9]*$"
436
+ },
437
+ "uniqueItems":true
438
+ },
439
+ "readonly":{
440
+ "type":"array",
441
+ "items":{
442
+ "type":"string",
443
+ "pattern":"^[a-z][a-zA-Z0-9]*$"
444
+ },
445
+ "uniqueItems":true
446
+ }
447
+ },
448
+ "anyOf":[
449
+ {
450
+ "required":[
451
+ "attributes"
452
+ ]
453
+ }
454
+ ],
455
+ "additionalProperties":false
456
+ }
457
+ ]
333
458
  }
334
459
  }
335
460
  },
336
- "required":[
337
- "attributes"
461
+ "required":[
462
+ "schema"
338
463
  ],
339
464
  "additionalProperties":false
340
465
  },
@@ -352,21 +477,18 @@
352
477
  "default":"pull"
353
478
  },
354
479
  "schedule":{
355
- "type":"string"
480
+ "type":"string",
481
+ "description":"Cron schedule for sync execution. Supports 5-field cron syntax or @hourly/@daily/@weekly/@monthly.",
482
+ "pattern":"^(@hourly|@daily|@weekly|@monthly|([0-9*/,-]+\\s+){4}[0-9*/,-]+)$"
356
483
  },
357
484
  "batchSize":{
358
485
  "type":"integer",
359
486
  "minimum":1,
360
487
  "maximum":10000,
361
488
  "default":500
362
- },
363
- "maxParallelRequests":{
364
- "type":"integer",
365
- "minimum":1,
366
- "maximum":50,
367
- "default":5
368
489
  }
369
- }
490
+ },
491
+ "additionalProperties":false
370
492
  },
371
493
  "openapi":{
372
494
  "type":"object",
@@ -377,7 +499,8 @@
377
499
  "default":false
378
500
  },
379
501
  "documentKey":{
380
- "type":"string"
502
+ "type":"string",
503
+ "description":"OpenAPI document key used to resolve selected operations. Warning-only in this story when unresolved at validation time."
381
504
  },
382
505
  "baseUrl":{
383
506
  "type":"string",
@@ -391,106 +514,35 @@
391
514
  "description":"Selected operations from the OpenAPI document. Only endpoints chosen during wizard onboarding are included.",
392
515
  "properties":{
393
516
  "list":{
394
- "type":"object",
517
+ "$ref":"#/$defs/openapiOperation",
395
518
  "required":[
396
519
  "operationId"
397
- ],
398
- "properties":{
399
- "operationId":{
400
- "type":"string"
401
- },
402
- "method":{
403
- "type":"string",
404
- "enum":[
405
- "GET",
406
- "POST"
407
- ]
408
- },
409
- "path":{
410
- "type":"string"
411
- }
412
- }
520
+ ]
413
521
  },
414
522
  "get":{
415
- "type":"object",
523
+ "$ref":"#/$defs/openapiOperation",
416
524
  "required":[
417
525
  "operationId"
418
- ],
419
- "properties":{
420
- "operationId":{
421
- "type":"string"
422
- },
423
- "method":{
424
- "type":"string",
425
- "enum":[
426
- "GET"
427
- ]
428
- },
429
- "path":{
430
- "type":"string"
431
- }
432
- }
526
+ ]
433
527
  },
434
528
  "create":{
435
- "type":"object",
436
- "properties":{
437
- "operationId":{
438
- "type":"string"
439
- },
440
- "method":{
441
- "type":"string",
442
- "enum":[
443
- "POST",
444
- "PUT"
445
- ]
446
- },
447
- "path":{
448
- "type":"string"
449
- }
450
- }
529
+ "$ref":"#/$defs/openapiOperation"
451
530
  },
452
531
  "update":{
453
- "type":"object",
454
- "properties":{
455
- "operationId":{
456
- "type":"string"
457
- },
458
- "method":{
459
- "type":"string",
460
- "enum":[
461
- "PATCH",
462
- "PUT",
463
- "POST"
464
- ]
465
- },
466
- "path":{
467
- "type":"string"
468
- }
469
- }
532
+ "$ref":"#/$defs/openapiOperation"
470
533
  },
471
534
  "delete":{
472
- "type":"object",
473
- "properties":{
474
- "operationId":{
475
- "type":"string"
476
- },
477
- "method":{
478
- "type":"string",
479
- "enum":[
480
- "DELETE"
481
- ]
482
- },
483
- "path":{
484
- "type":"string"
485
- }
486
- }
535
+ "$ref":"#/$defs/openapiOperation"
487
536
  }
537
+ },
538
+ "additionalProperties":{
539
+ "$ref":"#/$defs/openapiOperation"
488
540
  }
489
541
  },
490
542
  "autoRbac":{
491
543
  "type":"boolean",
492
544
  "default":false,
493
- "description":"Generates <system>.<entity>.<action> RBAC permissions."
545
+ "description":"When true and no explicit operation security scopes are configured, the runtime resolves required RBAC permission as '<resourceType>:<operation>' for each operation (resourceType from the datasource config, default document), matching builder repair RBAC permission names. Explicit operation-level scopes (openapi.operations.*.security/permissions) take precedence and disable autoRbac for that operation."
494
546
  }
495
547
  }
496
548
  },
@@ -522,8 +574,8 @@
522
574
  "type":"string",
523
575
  "enum":[
524
576
  "reject",
525
- "latest-wins",
526
- "first-wins",
577
+ "lastWriteWins",
578
+ "firstWriteWins",
527
579
  "merge"
528
580
  ]
529
581
  },
@@ -544,7 +596,7 @@
544
596
  "properties":{
545
597
  "rejectIf":{
546
598
  "type":"array",
547
- "description":"List of conditions that cause a record to be rejected.",
599
+ "description":"List of conditions that cause a record to be rejected. For lessThan: missing field is treated as reject. For greaterThan: missing field is not rejected. See quality docs for operator semantics.",
548
600
  "items":{
549
601
  "type":"object",
550
602
  "required":[
@@ -554,7 +606,7 @@
554
606
  "properties":{
555
607
  "field":{
556
608
  "type":"string",
557
- "pattern":"^[a-zA-Z0-9_]+$",
609
+ "pattern":"^[a-z][a-zA-Z0-9]*$",
558
610
  "description":"Normalized field name to evaluate."
559
611
  },
560
612
  "operator":{
@@ -585,39 +637,6 @@
585
637
  },
586
638
  "additionalProperties":false
587
639
  },
588
- "indexing":{
589
- "type":"object",
590
- "description":"Indexing and embedding strategy for this datasource.",
591
- "properties":{
592
- "embedding":{
593
- "type":"array",
594
- "description":"List of normalized fields whose values should be concatenated and embedded for vector search.",
595
- "items":{
596
- "type":"string",
597
- "pattern":"^[a-zA-Z0-9_]+$"
598
- },
599
- "minItems":1,
600
- "uniqueItems":true
601
- },
602
- "uniqueKey":{
603
- "type":"string",
604
- "pattern":"^[a-zA-Z0-9_]+$",
605
- "description":"Normalized field used as unique identifier for deduplication and upserts."
606
- },
607
- "dedupeStrategy":{
608
- "type":"string",
609
- "enum":[
610
- "reject",
611
- "latest-wins",
612
- "first-wins",
613
- "merge"
614
- ],
615
- "default":"latest-wins",
616
- "description":"Strategy to apply when multiple records share the same uniqueKey."
617
- }
618
- },
619
- "additionalProperties":false
620
- },
621
640
  "context":{
622
641
  "type":"object",
623
642
  "description":"Natural-language and semantic hints for AI agents.",
@@ -647,248 +666,861 @@
647
666
  "additionalProperties":false
648
667
  },
649
668
  "documentStorage":{
669
+ "$ref":"aifabrix://schema/type/document-storage.json",
670
+ "description":"Document storage configuration (optional). Schema is canonical under type/document-storage.json."
671
+ },
672
+ "messageService":{
673
+ "$ref":"aifabrix://schema/type/message-service.json",
674
+ "description":"Message service configuration (optional). Schema is canonical under type/message-service.json."
675
+ },
676
+ "testPayload":{
650
677
  "type":"object",
651
- "description":"Document storage configuration (optional, enables vector storage). Validated against type/document-storage.json schema.",
678
+ "description":"Execution-aware test payload configuration for unit and integration testing. Only the listed properties are allowed at this level; nested shapes for payloadTemplate/expectedResult/fk fixtures are validated strictly by the application validator where required.",
652
679
  "properties":{
653
- "enabled":{
654
- "type":"boolean",
655
- "default":true
656
- },
657
- "twoPhaseSync":{
658
- "type":"boolean",
659
- "default":true,
660
- "description":"Enable two-phase sync pattern. When true: validates metadata first (quality rules, comparison with DocumentRecords), then fetches binaries via CIP for changed/new documents. When false: fetches binaries directly without metadata validation phase (single-phase sync). Note: Files are never synced back to external systems (one-way sync only: external → dataplane)."
661
- },
662
- "binaryOperationRef":{
663
- "type":"string",
664
- "default":"get",
665
- "description":"CIP operation name for binary document retrieval. Must exist in execution.cip.operations. Defaults to 'get' operation."
666
- },
667
- "responseType":{
680
+ "mode":{
668
681
  "type":"string",
669
682
  "enum":[
670
- "binary",
671
- "base64",
672
- "json"
673
- ],
674
- "default":"binary",
675
- "description":"Expected response type from CIP operation. 'binary' for raw binary data, 'base64' for base64-encoded data, 'json' for JSON response with binary field."
676
- },
677
- "binaryField":{
678
- "type":"string",
679
- "description":"Field name containing binary data if responseType is 'json' or 'base64'. Required when responseType is not 'binary'."
683
+ "mock",
684
+ "live"
685
+ ]
680
686
  },
681
- "parameterMapping":{
687
+ "primaryKey":{
682
688
  "type":"object",
683
- "additionalProperties":{
684
- "type":"string"
685
- },
686
- "description":"Map metadata record fields to CIP operation parameters. Example: {\"fileId\": \"{{key}}\", \"downloadUrl\": \"{{metadata.downloadUrl}}\"}"
689
+ "description":"Optional key/value payload for primary-key focused operation tests.",
690
+ "additionalProperties":true
687
691
  },
688
- "processing":{
689
- "type":"object",
690
- "properties":{
691
- "fileStoragePath":{
692
- "type":"string",
693
- "default":"/data/documents"
694
- },
695
- "aiValidation":{
696
- "type":"object"
697
- },
698
- "spacyEnrichment":{
699
- "type":"object"
692
+ "scenarios":{
693
+ "type":"array",
694
+ "description":"Optional operation-specific test scenarios.",
695
+ "items":{
696
+ "type":"object",
697
+ "required":[
698
+ "operation"
699
+ ],
700
+ "properties":{
701
+ "operation":{
702
+ "type":"string",
703
+ "pattern":"^[a-z][a-zA-Z0-9]*$"
704
+ },
705
+ "input":{
706
+ "type":"object",
707
+ "additionalProperties":true
708
+ }
700
709
  },
701
- "notifications":{
702
- "type":"object"
710
+ "additionalProperties":false
711
+ }
712
+ },
713
+ "fk":{
714
+ "type":"object",
715
+ "description":"Optional FK fixture payload used by expression and join tests.",
716
+ "additionalProperties":true
717
+ },
718
+ "actors":{
719
+ "type":"array",
720
+ "description":"Optional actor fixture list for ABAC/runtime tests.",
721
+ "items":{
722
+ "type":"object",
723
+ "properties":{
724
+ "email":{
725
+ "type":"string"
726
+ },
727
+ "userId":{
728
+ "type":"string"
729
+ }
730
+ },
731
+ "additionalProperties":true
732
+ }
733
+ },
734
+ "payloadTemplate":{
735
+ "type":"object",
736
+ "description":"Sample payload matching the expected API response structure. Used for testing field mappings and metadata schema validation.",
737
+ "additionalProperties":true
738
+ },
739
+ "expectedResult":{
740
+ "type":"object",
741
+ "description":"Expected normalized result after field mapping transformations (optional, for validation)",
742
+ "additionalProperties":true
743
+ }
744
+ },
745
+ "additionalProperties":false
746
+ },
747
+ "capabilities":{
748
+ "type":"array",
749
+ "description":"Supported operations list.",
750
+ "items":{
751
+ "type":"string",
752
+ "pattern":"^[a-z][a-zA-Z0-9]*$"
753
+ },
754
+ "uniqueItems":true
755
+ },
756
+ "execution":{
757
+ "type":"object",
758
+ "description":"Execution engine configuration for this datasource (CIP, Python, or datasource-chaining). CIP is the native declarative mode.",
759
+ "required":[
760
+ "engine"
761
+ ],
762
+ "properties":{
763
+ "engine":{
764
+ "type":"string",
765
+ "enum":[
766
+ "cip",
767
+ "python",
768
+ "datasource"
769
+ ],
770
+ "description":"Execution engine. 'cip' for declarative pipelines, 'python' for custom handlers, 'datasource' for datasource-chained CIP execution."
771
+ },
772
+ "cip":{
773
+ "$ref":"#/$defs/cipDefinition"
774
+ },
775
+ "python":{
776
+ "$ref":"#/$defs/pythonExecution"
777
+ }
778
+ },
779
+ "additionalProperties":false
780
+ },
781
+ "config":{
782
+ "type":"object",
783
+ "description":"Additional configuration for this datasource.",
784
+ "properties":{
785
+ "extensions":{
786
+ "type":"object",
787
+ "description":"Vendor extensions namespace for controlled schema evolution.",
788
+ "propertyNames":{
789
+ "pattern":"^x[A-Z][a-zA-Z0-9]*$"
790
+ },
791
+ "additionalProperties":true
792
+ }
793
+ },
794
+ "additionalProperties":false
795
+ },
796
+ "contract":{
797
+ "$ref":"#/$defs/contractConfig"
798
+ },
799
+ "mcpContract":{
800
+ "type":"object",
801
+ "description":"Optional embedded MCP contract material (e.g. securityModel.tools and securityModel.abac) for manifest validation and CIP filter.abac policy-scope readiness. Persisted on ExternalDataSource.mcpContract when published.",
802
+ "additionalProperties":true
803
+ }
804
+ },
805
+ "allOf":[
806
+ {
807
+ "if":{
808
+ "properties":{
809
+ "entityType":{
810
+ "const":"none"
811
+ }
812
+ },
813
+ "required":[
814
+ "entityType"
815
+ ]
816
+ },
817
+ "then":{
818
+ "not":{
819
+ "anyOf":[
820
+ {
821
+ "required":[
822
+ "metadataSchema"
823
+ ]
824
+ },
825
+ {
826
+ "required":[
827
+ "primaryKey"
828
+ ]
829
+ },
830
+ {
831
+ "required":[
832
+ "labelKey"
833
+ ]
834
+ },
835
+ {
836
+ "required":[
837
+ "foreignKeys"
838
+ ]
839
+ },
840
+ {
841
+ "required":[
842
+ "dimensions"
843
+ ]
844
+ },
845
+ {
846
+ "required":[
847
+ "fieldMappings"
848
+ ]
849
+ },
850
+ {
851
+ "required":[
852
+ "sync"
853
+ ]
854
+ },
855
+ {
856
+ "required":[
857
+ "quality"
858
+ ]
859
+ },
860
+ {
861
+ "required":[
862
+ "context"
863
+ ]
864
+ },
865
+ {
866
+ "required":[
867
+ "validation"
868
+ ]
869
+ },
870
+ {
871
+ "required":[
872
+ "documentStorage"
873
+ ]
874
+ }
875
+ ]
876
+ }
877
+ },
878
+ "else":{
879
+ "required":[
880
+ "metadataSchema",
881
+ "primaryKey",
882
+ "labelKey",
883
+ "fieldMappings"
884
+ ]
885
+ }
886
+ },
887
+ {
888
+ "if":{
889
+ "properties":{
890
+ "entityType":{
891
+ "enum":[
892
+ "recordStorage",
893
+ "documentStorage"
894
+ ]
895
+ }
896
+ },
897
+ "required":[
898
+ "entityType"
899
+ ]
900
+ },
901
+ "then":{
902
+ "properties":{
903
+ "metadataSchema":{
904
+ "allOf":[
905
+ {
906
+ "$ref":"#/$defs/metadataSchemaNode"
907
+ },
908
+ {
909
+ "type":"object",
910
+ "required":[
911
+ "properties"
912
+ ],
913
+ "properties":{
914
+ "properties":{
915
+ "type":"object",
916
+ "required":[
917
+ "externalId"
918
+ ],
919
+ "properties":{
920
+ "externalId":{
921
+ "allOf":[
922
+ {
923
+ "$ref":"#/$defs/metadataSchemaNode"
924
+ },
925
+ {
926
+ "type":"object",
927
+ "properties":{
928
+ "type":{
929
+ "const":"string"
930
+ },
931
+ "index":{
932
+ "const":true
933
+ }
934
+ },
935
+ "required":[
936
+ "type",
937
+ "index"
938
+ ]
939
+ }
940
+ ]
941
+ }
942
+ }
943
+ }
944
+ }
945
+ }
946
+ ]
947
+ }
948
+ }
949
+ }
950
+ }
951
+ ],
952
+ "$defs":{
953
+ "metadataSchemaNode":{
954
+ "type":"object",
955
+ "description":"Strict supported subset of JSON Schema for metadataSchema.",
956
+ "properties":{
957
+ "description":{
958
+ "type":"string"
959
+ },
960
+ "type":{
961
+ "type":"string",
962
+ "enum":[
963
+ "object",
964
+ "array",
965
+ "string",
966
+ "number",
967
+ "integer",
968
+ "boolean",
969
+ "null"
970
+ ]
971
+ },
972
+ "properties":{
973
+ "type":"object",
974
+ "propertyNames":{
975
+ "pattern":"^[a-z][a-zA-Z0-9]*$"
976
+ },
977
+ "additionalProperties":{
978
+ "$ref":"#/$defs/metadataSchemaNode"
979
+ }
980
+ },
981
+ "required":{
982
+ "type":"array",
983
+ "items":{
984
+ "type":"string"
985
+ },
986
+ "uniqueItems":true
987
+ },
988
+ "items":{
989
+ "$ref":"#/$defs/metadataSchemaNode"
990
+ },
991
+ "additionalProperties":{
992
+ "oneOf":[
993
+ {
994
+ "type":"boolean"
995
+ },
996
+ {
997
+ "$ref":"#/$defs/metadataSchemaNode"
998
+ }
999
+ ]
1000
+ },
1001
+ "index":{
1002
+ "type":"boolean",
1003
+ "description":"Storage/index hint for metadata persistence. True marks this field as index-eligible."
1004
+ },
1005
+ "filter":{
1006
+ "type":"boolean",
1007
+ "description":"Filterability hint for metadata-driven query planning."
1008
+ },
1009
+ "nullable":{
1010
+ "type":"boolean"
1011
+ },
1012
+ "format":{
1013
+ "type":"string",
1014
+ "description":"For datetime semantics use type='string' with format='date-time' (UTC at runtime)."
1015
+ },
1016
+ "pattern":{
1017
+ "type":"string"
1018
+ },
1019
+ "minimum":{
1020
+ "type":"number"
1021
+ },
1022
+ "maximum":{
1023
+ "type":"number"
1024
+ },
1025
+ "exclusiveMinimum":{
1026
+ "type":"number"
1027
+ },
1028
+ "exclusiveMaximum":{
1029
+ "type":"number"
1030
+ },
1031
+ "multipleOf":{
1032
+ "type":"number",
1033
+ "exclusiveMinimum":0
1034
+ },
1035
+ "minLength":{
1036
+ "type":"integer",
1037
+ "minimum":0
1038
+ },
1039
+ "maxLength":{
1040
+ "type":"integer",
1041
+ "minimum":0
1042
+ },
1043
+ "minItems":{
1044
+ "type":"integer",
1045
+ "minimum":0
1046
+ },
1047
+ "maxItems":{
1048
+ "type":"integer",
1049
+ "minimum":0
1050
+ },
1051
+ "uniqueItems":{
1052
+ "type":"boolean"
1053
+ },
1054
+ "minProperties":{
1055
+ "type":"integer",
1056
+ "minimum":0
1057
+ },
1058
+ "maxProperties":{
1059
+ "type":"integer",
1060
+ "minimum":0
1061
+ }
1062
+ },
1063
+ "allOf":[
1064
+ {
1065
+ "if":{
1066
+ "properties":{
1067
+ "format":{
1068
+ "const":"date-time"
1069
+ }
1070
+ },
1071
+ "required":[
1072
+ "format"
1073
+ ]
1074
+ },
1075
+ "then":{
1076
+ "properties":{
1077
+ "type":{
1078
+ "const":"string"
1079
+ }
1080
+ },
1081
+ "required":[
1082
+ "type"
1083
+ ]
1084
+ }
1085
+ },
1086
+ {
1087
+ "if":{
1088
+ "properties":{
1089
+ "index":{
1090
+ "const":true
1091
+ }
1092
+ },
1093
+ "required":[
1094
+ "index"
1095
+ ]
1096
+ },
1097
+ "then":{
1098
+ "properties":{
1099
+ "type":{
1100
+ "type":"string",
1101
+ "enum":[
1102
+ "string",
1103
+ "number",
1104
+ "integer",
1105
+ "boolean"
1106
+ ]
1107
+ }
1108
+ },
1109
+ "not":{
1110
+ "anyOf":[
1111
+ {
1112
+ "required":[
1113
+ "properties"
1114
+ ]
1115
+ },
1116
+ {
1117
+ "required":[
1118
+ "items"
1119
+ ]
1120
+ }
1121
+ ]
1122
+ }
1123
+ }
1124
+ },
1125
+ {
1126
+ "if":{
1127
+ "properties":{
1128
+ "filter":{
1129
+ "const":true
1130
+ }
1131
+ },
1132
+ "required":[
1133
+ "filter"
1134
+ ]
1135
+ },
1136
+ "then":{
1137
+ "properties":{
1138
+ "type":{
1139
+ "type":"string",
1140
+ "enum":[
1141
+ "string",
1142
+ "number",
1143
+ "integer",
1144
+ "boolean"
1145
+ ]
1146
+ }
1147
+ },
1148
+ "not":{
1149
+ "anyOf":[
1150
+ {
1151
+ "required":[
1152
+ "properties"
1153
+ ]
1154
+ },
1155
+ {
1156
+ "required":[
1157
+ "items"
1158
+ ]
1159
+ }
1160
+ ]
1161
+ }
1162
+ }
1163
+ }
1164
+ ],
1165
+ "additionalProperties":false
1166
+ },
1167
+ "foreignKeyDefinition":{
1168
+ "type":"object",
1169
+ "required":[
1170
+ "name",
1171
+ "fields",
1172
+ "targetDatasource"
1173
+ ],
1174
+ "properties":{
1175
+ "name":{
1176
+ "type":"string",
1177
+ "pattern":"^[a-z][a-zA-Z0-9]*$",
1178
+ "description":"Mandatory foreign key name (camelCase) for debugging, UI, and generated contracts (must be unique per datasource)."
1179
+ },
1180
+ "fields":{
1181
+ "type":"array",
1182
+ "description":"Local normalized fields forming the foreign key. Each field must exist in metadataSchema and have index=true (builder/runtime enforced).",
1183
+ "minItems":1,
1184
+ "items":{
1185
+ "type":"string",
1186
+ "pattern":"^[a-z][a-zA-Z0-9]*$"
1187
+ },
1188
+ "uniqueItems":true
1189
+ },
1190
+ "targetDatasource":{
1191
+ "type":"string",
1192
+ "pattern":"^[a-z0-9-]+$",
1193
+ "description":"Target datasource key"
1194
+ },
1195
+ "targetFields":{
1196
+ "type":"array",
1197
+ "description":"Target fields joined by this FK. If omitted, defaults to target metadataSchema externalId ([\"externalId\"]) for cross-datasource identity (not target primaryKey). Explicit multi-field lists must not mirror the target composite primaryKey as the join contract.",
1198
+ "items":{
1199
+ "type":"string",
1200
+ "pattern":"^[a-z][a-zA-Z0-9]*$"
1201
+ },
1202
+ "minItems":1
1203
+ },
1204
+ "required":{
1205
+ "type":"boolean",
1206
+ "default":false,
1207
+ "description":"If true, missing or invalid reference causes validation failure"
1208
+ },
1209
+ "description":{
1210
+ "type":"string"
1211
+ }
1212
+ },
1213
+ "additionalProperties":false
1214
+ },
1215
+ "dimensionBinding":{
1216
+ "type":"object",
1217
+ "required":[
1218
+ "type"
1219
+ ],
1220
+ "properties":{
1221
+ "type":{
1222
+ "type":"string",
1223
+ "enum":[
1224
+ "local",
1225
+ "fk"
1226
+ ]
1227
+ },
1228
+ "field":{
1229
+ "type":"string",
1230
+ "pattern":"^[a-z][a-zA-Z0-9]*$"
1231
+ },
1232
+ "actor":{
1233
+ "type":"string",
1234
+ "enum":[
1235
+ "displayName",
1236
+ "email",
1237
+ "userId",
1238
+ "groups",
1239
+ "roles"
1240
+ ]
1241
+ },
1242
+ "operator":{
1243
+ "type":"string",
1244
+ "enum":[
1245
+ "eq",
1246
+ "in"
1247
+ ]
1248
+ },
1249
+ "via":{
1250
+ "type":"array",
1251
+ "minItems":1,
1252
+ "items":{
1253
+ "$ref":"#/$defs/dimensionVia"
1254
+ }
1255
+ },
1256
+ "required":{
1257
+ "type":"boolean",
1258
+ "default":true
1259
+ }
1260
+ },
1261
+ "oneOf":[
1262
+ {
1263
+ "required":[
1264
+ "field"
1265
+ ]
1266
+ },
1267
+ {
1268
+ "required":[
1269
+ "via"
1270
+ ]
1271
+ }
1272
+ ],
1273
+ "allOf":[
1274
+ {
1275
+ "if":{
1276
+ "properties":{
1277
+ "type":{
1278
+ "const":"local"
1279
+ }
1280
+ },
1281
+ "required":[
1282
+ "type"
1283
+ ]
1284
+ },
1285
+ "then":{
1286
+ "required":[
1287
+ "field"
1288
+ ],
1289
+ "not":{
1290
+ "required":[
1291
+ "via"
1292
+ ]
703
1293
  }
704
- },
705
- "additionalProperties":false
1294
+ }
706
1295
  },
707
- "credentialId":{
708
- "type":"string"
709
- }
710
- },
711
- "required":[
712
- "enabled"
713
- ],
714
- "additionalProperties":false
715
- },
716
- "portalInput":{
717
- "type":"array",
718
- "description":"Optional UI metadata definition for the AI Fabrix portal.",
719
- "items":{
720
- "type":"object",
721
- "required":[
722
- "name",
723
- "field",
724
- "label"
725
- ],
726
- "properties":{
727
- "name":{
728
- "type":"string"
729
- },
730
- "field":{
731
- "type":"string",
732
- "enum":[
733
- "text",
734
- "textarea",
735
- "select",
736
- "json",
737
- "boolean",
738
- "number"
1296
+ {
1297
+ "if":{
1298
+ "properties":{
1299
+ "type":{
1300
+ "const":"fk"
1301
+ }
1302
+ },
1303
+ "required":[
1304
+ "type"
739
1305
  ]
740
1306
  },
741
- "label":{
742
- "type":"string"
743
- },
744
- "placeholder":{
745
- "type":"string"
746
- },
747
- "options":{
748
- "type":"array",
749
- "items":{
750
- "type":"string"
1307
+ "then":{
1308
+ "required":[
1309
+ "via"
1310
+ ],
1311
+ "not":{
1312
+ "required":[
1313
+ "field"
1314
+ ]
751
1315
  }
1316
+ }
1317
+ },
1318
+ {
1319
+ "if":{
1320
+ "properties":{
1321
+ "actor":{
1322
+ "enum":[
1323
+ "displayName",
1324
+ "email",
1325
+ "userId"
1326
+ ]
1327
+ }
1328
+ },
1329
+ "required":[
1330
+ "actor"
1331
+ ]
752
1332
  },
753
- "masked":{
754
- "type":"boolean"
1333
+ "then":{
1334
+ "properties":{
1335
+ "operator":{
1336
+ "const":"eq",
1337
+ "default":"eq"
1338
+ }
1339
+ }
1340
+ }
1341
+ },
1342
+ {
1343
+ "if":{
1344
+ "properties":{
1345
+ "actor":{
1346
+ "enum":[
1347
+ "groups",
1348
+ "roles"
1349
+ ]
1350
+ }
1351
+ },
1352
+ "required":[
1353
+ "actor"
1354
+ ]
755
1355
  },
756
- "validation":{
757
- "type":"object",
1356
+ "then":{
758
1357
  "properties":{
759
- "minLength":{
760
- "type":"integer"
761
- },
762
- "maxLength":{
763
- "type":"integer"
764
- },
765
- "pattern":{
766
- "type":"string"
767
- },
768
- "required":{
769
- "type":"boolean"
1358
+ "operator":{
1359
+ "const":"in",
1360
+ "default":"in"
770
1361
  }
771
1362
  }
772
1363
  }
773
1364
  }
774
- }
1365
+ ],
1366
+ "additionalProperties":false
775
1367
  },
776
- "testPayload":{
1368
+ "dimensionVia":{
777
1369
  "type":"object",
778
- "description":"Test payload configuration for unit and integration testing",
1370
+ "required":[
1371
+ "fk",
1372
+ "dimension"
1373
+ ],
779
1374
  "properties":{
780
- "payloadTemplate":{
781
- "type":"object",
782
- "description":"Sample payload matching the expected API response structure. Used for testing field mappings and metadata schema validation.",
783
- "additionalProperties":true
1375
+ "fk":{
1376
+ "type":"string",
1377
+ "pattern":"^[a-z][a-zA-Z0-9]*$"
784
1378
  },
785
- "expectedResult":{
786
- "type":"object",
787
- "description":"Expected normalized result after field mapping transformations (optional, for validation)",
788
- "additionalProperties":true
1379
+ "dimension":{
1380
+ "type":"string",
1381
+ "pattern":"^[a-zA-Z0-9_]+$"
789
1382
  }
790
1383
  },
791
1384
  "additionalProperties":false
792
1385
  },
793
- "capabilities":{
1386
+ "exposedSchemaNode":{
1387
+ "description":"Recursive exposed.schema node. Object values create nested API objects; string values are expression leaves.",
794
1388
  "oneOf":[
795
1389
  {
796
- "type":"array",
797
- "description":"Preferred: list of supported operation names. Values: list, get, create, update, delete.",
798
- "items":{"type":"string","enum":["list","get","create","update","delete"]},
799
- "uniqueItems":true
1390
+ "type":"string",
1391
+ "maxLength":512,
1392
+ "pattern":"^(metadata\\.[a-z][a-zA-Z0-9]*(\\.[a-zA-Z0-9_]+)*|fk\\.[a-z][a-zA-Z0-9]*\\.metadata\\.[a-z][a-zA-Z0-9]*|fk\\.[a-z][a-zA-Z0-9]*\\.dimension\\.[a-zA-Z0-9_]+(\\.label)?|dimension\\.[a-zA-Z0-9_]+(\\.label)?)$"
800
1393
  },
801
1394
  {
802
1395
  "type":"object",
803
- "description":"Legacy: object with boolean flags per operation. Accepted for backward compatibility.",
804
- "properties":{
805
- "list":{"type":"boolean"},
806
- "get":{"type":"boolean"},
807
- "create":{"type":"boolean"},
808
- "update":{"type":"boolean"},
809
- "delete":{"type":"boolean"}
810
- },
811
- "additionalProperties":false
1396
+ "minProperties":1,
1397
+ "additionalProperties":{
1398
+ "$ref":"#/$defs/exposedSchemaNode"
1399
+ }
812
1400
  }
813
- ],
814
- "description":"Supported operations. When omitted, derived from execution.engine (CIP operations or list-only for Python)."
1401
+ ]
815
1402
  },
816
- "execution":{
1403
+ "openapiOperation":{
817
1404
  "type":"object",
818
- "description":"Execution engine configuration for this datasource (CIP or Python). CIP is the native declarative mode.",
819
- "required":[
820
- "engine"
821
- ],
1405
+ "description":"Selected OpenAPI operation contract with explicit security metadata.",
822
1406
  "properties":{
823
- "engine":{
1407
+ "operationId":{
1408
+ "type":"string"
1409
+ },
1410
+ "method":{
824
1411
  "type":"string",
825
1412
  "enum":[
826
- "cip",
827
- "python"
828
- ],
829
- "description":"Execution engine. 'cip' for declarative pipelines, 'python' for custom handlers."
1413
+ "GET",
1414
+ "POST",
1415
+ "PUT",
1416
+ "PATCH",
1417
+ "DELETE"
1418
+ ]
830
1419
  },
831
- "cip":{
832
- "$ref":"#/$defs/cipDefinition"
1420
+ "path":{
1421
+ "type":"string"
833
1422
  },
834
- "python":{
835
- "$ref":"#/$defs/pythonExecution"
836
- }
837
- },
838
- "additionalProperties":false
839
- },
840
- "config":{
841
- "type":"object",
842
- "description":"Additional configuration for this datasource, including ABAC settings, MCP contracts, and other metadata.",
843
- "properties":{
844
- "abac":{
845
- "type":"object",
846
- "description":"Attribute-Based Access Control (ABAC) configuration for this datasource.",
847
- "properties":{
848
- "dimensions":{
849
- "type":"object",
850
- "description":"Data dimensions mapping. Key = dimension key (from Dimension Catalog), Value = attribute path. Overrides fieldMappings.dimensions if specified.",
851
- "additionalProperties":{
852
- "type":"string",
853
- "pattern":"^[a-zA-Z0-9_.]+$"
854
- }
1423
+ "permissions":{
1424
+ "oneOf":[
1425
+ {
1426
+ "type":"string"
855
1427
  },
856
- "crossSystemSql":{
857
- "type":"string",
858
- "description":"Cross-system ABAC filter expression in SQL format (advanced, for developers). Example: 'hubspot-companies.country = user.country AND hubspot-companies.revenue >= 1000000'"
1428
+ {
1429
+ "type":"array",
1430
+ "items":{
1431
+ "type":"string"
1432
+ },
1433
+ "minItems":1,
1434
+ "uniqueItems":true
1435
+ }
1436
+ ]
1437
+ },
1438
+ "security":{
1439
+ "description":"OpenAPI security requirements. Supports object/list/string forms consumed by RBAC coverage validation.",
1440
+ "oneOf":[
1441
+ {
1442
+ "type":"string"
859
1443
  },
860
- "crossSystemJson":{
1444
+ {
861
1445
  "type":"object",
862
- "description":"Cross-system ABAC filter expression in JSON format (simple, for UI). Example: {'hubspot-companies.country': {'eq': 'user.country'}, 'hubspot-companies.revenue': {'gte': 1000000}}",
863
1446
  "additionalProperties":{
864
- "type":"object",
865
- "properties":{
866
- "eq":{"type":["string","number","boolean"]},
867
- "ne":{"type":["string","number","boolean"]},
868
- "gt":{"type":["string","number"]},
869
- "lt":{"type":["string","number"]},
870
- "gte":{"type":["string","number"]},
871
- "lte":{"type":["string","number"]},
872
- "in":{"type":"array"},
873
- "nin":{"type":"array"},
874
- "contains":{"type":"string"},
875
- "like":{"type":"string"},
876
- "isNull":{"type":"null"},
877
- "isNotNull":{"type":"null"}
878
- }
1447
+ "oneOf":[
1448
+ {
1449
+ "type":"string"
1450
+ },
1451
+ {
1452
+ "type":"array",
1453
+ "items":{
1454
+ "type":"string"
1455
+ }
1456
+ }
1457
+ ]
1458
+ }
1459
+ },
1460
+ {
1461
+ "type":"array",
1462
+ "items":{
1463
+ "oneOf":[
1464
+ {
1465
+ "type":"string"
1466
+ },
1467
+ {
1468
+ "type":"object",
1469
+ "additionalProperties":{
1470
+ "oneOf":[
1471
+ {
1472
+ "type":"string"
1473
+ },
1474
+ {
1475
+ "type":"array",
1476
+ "items":{
1477
+ "type":"string"
1478
+ }
1479
+ }
1480
+ ]
1481
+ }
1482
+ }
1483
+ ]
879
1484
  }
880
1485
  }
1486
+ ]
1487
+ }
1488
+ },
1489
+ "additionalProperties":false
1490
+ },
1491
+ "cipRuntimeContext":{
1492
+ "type":"object",
1493
+ "description":"Runtime context requirements for CIP execution.",
1494
+ "properties":{
1495
+ "requires":{
1496
+ "type":"array",
1497
+ "items":{
1498
+ "type":"string",
1499
+ "enum":[
1500
+ "user",
1501
+ "groups",
1502
+ "environment",
1503
+ "request"
1504
+ ]
881
1505
  },
882
- "additionalProperties":false
1506
+ "uniqueItems":true
1507
+ },
1508
+ "optional":{
1509
+ "type":"array",
1510
+ "items":{
1511
+ "type":"string",
1512
+ "enum":[
1513
+ "user",
1514
+ "groups",
1515
+ "environment",
1516
+ "request"
1517
+ ]
1518
+ },
1519
+ "uniqueItems":true
883
1520
  }
884
1521
  },
885
- "additionalProperties":true
1522
+ "additionalProperties":false
886
1523
  },
887
- "contract":{
888
- "$ref":"#/$defs/contractConfig"
889
- }
890
- },
891
- "$defs":{
892
1524
  "pythonExecution":{
893
1525
  "type":"object",
894
1526
  "description":"Python-based execution config for advanced/custom use cases.",
@@ -952,7 +1584,10 @@
952
1584
  },
953
1585
  "operations":{
954
1586
  "type":"object",
955
- "description":"Logical operations (list/get/create/update/delete) implemented for this datasource.",
1587
+ "description":"Logical operations implemented for this datasource. Standard names: list, get, create, update, delete. Additional keys are allowed when they match the capability naming pattern (same as capabilities[] items).",
1588
+ "propertyNames":{
1589
+ "pattern":"^[a-z][a-zA-Z0-9]*$"
1590
+ },
956
1591
  "properties":{
957
1592
  "list":{
958
1593
  "$ref":"#/$defs/cipOperation"
@@ -970,10 +1605,15 @@
970
1605
  "$ref":"#/$defs/cipOperation"
971
1606
  }
972
1607
  },
973
- "additionalProperties":false
1608
+ "additionalProperties":{
1609
+ "$ref":"#/$defs/cipOperation"
1610
+ }
974
1611
  },
975
1612
  "idempotency":{
976
1613
  "$ref":"#/$defs/idempotencyConfig"
1614
+ },
1615
+ "runtimeContext":{
1616
+ "$ref":"#/$defs/cipRuntimeContext"
977
1617
  }
978
1618
  },
979
1619
  "additionalProperties":false
@@ -991,9 +1631,41 @@
991
1631
  "type":"boolean",
992
1632
  "default":true
993
1633
  },
1634
+ "method":{
1635
+ "type":"string",
1636
+ "enum":[
1637
+ "GET",
1638
+ "POST",
1639
+ "PUT",
1640
+ "PATCH",
1641
+ "DELETE"
1642
+ ],
1643
+ "description":"Optional canonical HTTP method for this operation contract."
1644
+ },
1645
+ "path":{
1646
+ "type":"string",
1647
+ "description":"Optional canonical route/path for this operation contract."
1648
+ },
1649
+ "input":{
1650
+ "type":"object",
1651
+ "description":"Optional operation input contract schema.",
1652
+ "additionalProperties":true
1653
+ },
1654
+ "output":{
1655
+ "type":"object",
1656
+ "description":"Optional operation output contract schema.",
1657
+ "additionalProperties":true
1658
+ },
1659
+ "safe":{
1660
+ "type":"boolean",
1661
+ "description":"Optional safety hint for operation execution."
1662
+ },
994
1663
  "lineage":{
995
1664
  "$ref":"#/$defs/cipLineage"
996
1665
  },
1666
+ "identity":{
1667
+ "$ref":"#/$defs/identitySpec"
1668
+ },
997
1669
  "steps":{
998
1670
  "type":"array",
999
1671
  "minItems":1,
@@ -1027,6 +1699,48 @@
1027
1699
  }
1028
1700
  ]
1029
1701
  },
1702
+ "identityMode":{
1703
+ "type":"string",
1704
+ "enum":[
1705
+ "impersonation",
1706
+ "attribution",
1707
+ "system"
1708
+ ],
1709
+ "description":"Identity execution mode for operation-level override."
1710
+ },
1711
+ "identitySpec":{
1712
+ "type":"object",
1713
+ "description":"Operation-level identity override. When omitted, external-system default applies.",
1714
+ "required":[
1715
+ "mode"
1716
+ ],
1717
+ "properties":{
1718
+ "mode":{
1719
+ "$ref":"#/$defs/identityMode"
1720
+ },
1721
+ "required":{
1722
+ "type":"boolean",
1723
+ "default":false,
1724
+ "description":"When true, fail operation if requested mode cannot be applied."
1725
+ },
1726
+ "fallback":{
1727
+ "type":"array",
1728
+ "description":"Fallback mode chain evaluated when primary mode fails.",
1729
+ "items":{
1730
+ "$ref":"#/$defs/identityMode"
1731
+ },
1732
+ "uniqueItems":true
1733
+ },
1734
+ "scopes":{
1735
+ "type":"array",
1736
+ "description":"Optional scopes requested for impersonation minting.",
1737
+ "items":{
1738
+ "type":"string"
1739
+ }
1740
+ }
1741
+ },
1742
+ "additionalProperties":false
1743
+ },
1030
1744
  "cipStepFetch":{
1031
1745
  "type":"object",
1032
1746
  "required":[
@@ -1044,20 +1758,15 @@
1044
1758
  "type":"string",
1045
1759
  "enum":[
1046
1760
  "openapi",
1047
- "http"
1761
+ "http",
1762
+ "datasource"
1048
1763
  ],
1049
- "description":"If 'openapi', refer to openapi.operations.*. If 'http', use explicit method/path."
1764
+ "description":"If 'openapi', refer to openapi.operations.*. If 'http', use explicit method/path. If 'datasource', execute another datasource operation."
1050
1765
  },
1051
1766
  "openapiRef":{
1052
1767
  "type":"string",
1053
- "enum":[
1054
- "list",
1055
- "get",
1056
- "create",
1057
- "update",
1058
- "delete"
1059
- ],
1060
- "description":"Reference to openapi.operations.<openapiRef> entry."
1768
+ "pattern":"^[a-z][a-zA-Z0-9]*$",
1769
+ "description":"Key under openapi.operations (standard CRUD: list, get, create, update, delete, or any custom name matching capabilities[] / execution.cip.operations naming)."
1061
1770
  },
1062
1771
  "operationId":{
1063
1772
  "type":"string",
@@ -1078,6 +1787,22 @@
1078
1787
  "type":"string",
1079
1788
  "description":"Explicit HTTP path when source='http'."
1080
1789
  },
1790
+ "datasource":{
1791
+ "type":"string",
1792
+ "pattern":"^[a-z0-9-]+$",
1793
+ "description":"Target datasource key when source='datasource'."
1794
+ },
1795
+ "operation":{
1796
+ "type":"string",
1797
+ "pattern":"^[a-z][a-zA-Z0-9]*$",
1798
+ "default":"list",
1799
+ "description":"Target datasource operation when source='datasource' (standard CRUD or custom CIP operation key on the target). Defaults to list."
1800
+ },
1801
+ "parameters":{
1802
+ "type":"object",
1803
+ "description":"Optional operation parameters forwarded to datasource execution when source='datasource'.",
1804
+ "additionalProperties":true
1805
+ },
1081
1806
  "query":{
1082
1807
  "type":"object",
1083
1808
  "description":"Static query parameters. ABAC/runtime can still override or append at runtime.",
@@ -1094,9 +1819,13 @@
1094
1819
  "description":"Optional static request body or template for POST/PUT/PATCH fetches.",
1095
1820
  "type":["object","string","null"]
1096
1821
  },
1822
+ "expectedItemsPath":{
1823
+ "type":"string",
1824
+ "description":"Optional response shape guard. When set, runtime validates this path exists and is non-null in fetch response."
1825
+ },
1097
1826
  "headers":{
1098
1827
  "type":"object",
1099
- "description":"Optional HTTP headers for the request.",
1828
+ "description":"Optional HTTP headers for the request (compatibility contract; runtime support may depend on executor path).",
1100
1829
  "additionalProperties":{
1101
1830
  "type":"string"
1102
1831
  }
@@ -1140,6 +1869,20 @@
1140
1869
  "path"
1141
1870
  ]
1142
1871
  }
1872
+ },
1873
+ {
1874
+ "if":{
1875
+ "properties":{
1876
+ "source":{
1877
+ "const":"datasource"
1878
+ }
1879
+ }
1880
+ },
1881
+ "then":{
1882
+ "required":[
1883
+ "datasource"
1884
+ ]
1885
+ }
1143
1886
  }
1144
1887
  ],
1145
1888
  "additionalProperties":false
@@ -1276,27 +2019,52 @@
1276
2019
  "properties":{
1277
2020
  "filter":{
1278
2021
  "type":"object",
1279
- "description":"Filter mapped records before output. Dimension enforcement is applied automatically based on fieldMappings.dimensions.",
2022
+ "description":"Filter mapped records before output.",
1280
2023
  "properties":{
1281
- "enforceAbac":{
1282
- "type":"boolean",
1283
- "default":true
1284
- },
1285
- "expression":{
1286
- "oneOf":[
1287
- {
2024
+ "abac":{
2025
+ "type":"object",
2026
+ "description":"ABAC filtering behavior for this step.",
2027
+ "properties":{
2028
+ "mode":{
1288
2029
  "type":"string",
1289
- "description":"SQL filter expression (e.g., 'status = \"active\" AND revenue >= 1000000')"
2030
+ "enum":[
2031
+ "mandatory",
2032
+ "optional",
2033
+ "disabled"
2034
+ ],
2035
+ "default":"mandatory"
1290
2036
  },
1291
- {
1292
- "type":"object",
1293
- "description":"JSON filter expression (e.g., {'status': {'eq': 'active'}, 'revenue': {'gte': 1000000}})",
1294
- "additionalProperties":{
1295
- "type":"object"
1296
- }
2037
+ "policyScope":{
2038
+ "type":"string",
2039
+ "enum":[
2040
+ "datasource",
2041
+ "system",
2042
+ "cross-system"
2043
+ ],
2044
+ "default":"datasource"
2045
+ },
2046
+ "explain":{
2047
+ "type":"boolean",
2048
+ "default":false
1297
2049
  }
2050
+ },
2051
+ "additionalProperties":false
2052
+ },
2053
+ "expression":{
2054
+ "type":"string",
2055
+ "description":"JMESPath expression evaluated after ABAC filtering."
2056
+ },
2057
+ "expressionLanguage":{
2058
+ "type":"string",
2059
+ "enum":[
2060
+ "jmespath"
1298
2061
  ],
1299
- "description":"Optional additional filter expression. Supports both SQL and JSON formats."
2062
+ "default":"jmespath"
2063
+ },
2064
+ "maxComplexity":{
2065
+ "type":"integer",
2066
+ "minimum":1,
2067
+ "default":50
1300
2068
  }
1301
2069
  },
1302
2070
  "additionalProperties":false
@@ -1422,7 +2190,7 @@
1422
2190
  },
1423
2191
  "cipCompensationConfig":{
1424
2192
  "type":"object",
1425
- "description":"Compensation (rollback) configuration for error handling.",
2193
+ "description":"Compensation (rollback) configuration for error handling. Current runtime compensation execution is focused on fetch/map step flows.",
1426
2194
  "properties":{
1427
2195
  "enabled":{
1428
2196
  "type":"boolean",